Compare commits

...

No commits in common. "main" and "code-example" have entirely different histories.

13 changed files with 0 additions and 1333 deletions

54
FSW.py
View File

@ -1,54 +0,0 @@
# python script created by FSW: 24:11:2020 04:53:44
import visa
def write_command(instrument, command) :
instrument.write(command)
return process_system_error(instrument)
def write_query(instrument, command) :
buffer = instrument.query(command)
bSuccess = process_system_error(instrument)
return bSuccess, buffer
def process_system_error(instrument) :
bSuccess = True
EsrErrorMask = 0x3C
if ((get_esr(instrument) & EsrErrorMask) != 0) :
print(instrument.query(":SYST:ERR?"))
instrument.write("*CLS")
bSuccess = False
return bSuccess
def get_esr(instrument) :
esr = instrument.query("*ESR?")
return int(esr)
VisaResourceManager = visa.ResourceManager()
#set center freQ
fre = '200e6'
descr = '_harm_dis_meas'
#location on FSW
tar_loc = 'd:\\murmur\\'
# connect to analyzer
Analyzer = VisaResourceManager.open_resource("TCPIP::192.168.1.43::inst0::INSTR")
print(Analyzer.query("*IDN?"))
success = write_command( Analyzer, "*CLS" )
success = write_command( Analyzer, ":SYST:DISP:UPD ON" )
success = write_command( Analyzer, ":INIT:CONT OFF" )
#success = write_command( Analyzer, ":DISP:WIND:SUBW:TRAC:Y:SCAL:RLEV 10" )
success = write_command( Analyzer, ":SENS:FREQ:CENT " + fre )
success = write_command( Analyzer, ":CALC:MARK:FUNC:HARM:STAT ON" )
success = write_command( Analyzer, ":INIT:CONT ON" )
success = write_command( Analyzer, ":FORM:DEXP:DSEP POIN" )
success = write_command( Analyzer, ":FORM:DEXP:FORM CSV" )
success = write_command( Analyzer, ":FORM:DEXP:HEAD OFF" )
success = write_command( Analyzer, ":FORM:DEXP:TRAC ALL" )
#success = write_command( Analyzer, ":MMEM:STOR1:TRAC 1,'d:\\" + fre + descr +".CSV'" )
#
success = write_command( Analyzer, ":MMEM:STOR1:TRAC 1,'" + tar_loc + fre + descr +".CSV'" )
success, data = write_query(Analyzer, f"MMEM:DATA? '{tar_loc}screenshot.png'")
with open("local_screenshot.png", "wb") as f:
f.write(data)
success = write_command( Analyzer, ":SENS:FREQ:MODE SWE" )
# back to local mode
success = write_command(Analyzer, "@LOC")
if success:
print("Done.\r\nFile's location is {}{}{}.CSV.\r\n".format(tar_loc,fre,descr))
# cleanup
Analyzer.close()
VisaResourceManager.close()

View File

@ -1,74 +0,0 @@
# 功能
采集板具备深度计、加速度计和陀螺仪,可采集相关数据并以`*.BIN`格式存储,可通过工具格式化输出为`*.CSV`支持Excel或文本编辑器查看、编辑。
# 采集状态检查
调试口有调试串口TTL/115200-8-1-N具备查看采集状态的功能。
采集状态有误时会不断重启,正常状态则会不断刷新采集的数据。
如遇采集状态有误,则需要给水密桶`断电、稍等、重新上电`尝试恢复。
# 采集数据格式
原始采集的数据文件后缀为`.BIN`,以结构体`info_t`小端序存储。
```c
// MPU传感器数据结构
typedef struct {
int16_t ax; // 加速度计 X轴
int16_t ay; // 加速度计 Y轴
int16_t az; // 加速度计 Z轴
int16_t gx; // 陀螺仪 X轴
int16_t gy; // 陀螺仪 Y轴
int16_t gz; // 陀螺仪 Z轴
} sensor_data_t;
// 完整的数据记录结构
#pragma pack(1)
typedef struct {
uint8_t y; // 年相对值需要加上2000
uint8_t month; // 月
uint8_t d; // 日
uint8_t h; // 时
uint8_t m; // 分
uint8_t s; // 秒
uint16_t ms; // 毫秒
int16_t deepth; // 深度
sensor_data_t data; // MPU传感器数据
} info_t;
```
# 导出采集数据
调试口连有一A口USB接头插入电脑后**稍作等待**,系统会多出一个盘符,双击打开可浏览采集的数据文件,其以日期为文件名,形如`20241112.BIN`。
选中采集文件后**用鼠标拖入**本地磁盘某位置即可。
# 解析采集数据
`WIN+R`输入cmd后按回车键运行命令行在命令行中输入`decode.exe`回车,会提示具体的使用方法,如:
```
用法:
decode.exe -f <文件名> [-o <输出文件名>]
选项:
-f <文件名> 指定输入文件
-o <文件名> 指定输出文件(可选,默认输出到与输入同名的.csv文件
-h 显示帮助信息
示例:
decode.exe -f 20241112.BIN
decode.exe -f 20241112.BIN -o output.csv
```
运行结果如:
```cmd
D:\Users\murmur\Desktop\test>decode.exe -f 20241112.BIN
系统类型: Windows
系统字节序: 小端序
共解析 46980 条记录
```
# 异常处理
可通过转换后文件内的日期数据判断解析是否正确,如不正确请重新导出。

View File

@ -1,315 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>输入框自动全选和放大提示</title>
<style>
/* 基本样式 */
body {
font-family: Arial, sans-serif;
padding: 20px;
}
input {
width: 200px;
padding: 8px;
font-size: 16px;
font-weight: bold;
font-family: 'Consolas';
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 10px;
text-align: right;
}
input:focus {
color: black;
}
/* 按钮样式 */
button {
padding: 10px 15px;
font-size: 16px;
border: none;
border-radius: 5px;
background-color: #007bff;
color: white;
cursor: pointer;
margin-right: 10px;
margin-bottom: 10px;
transition: background-color 0.3s;
}
/* 提示数字样式 */
.number-tip {
position: absolute;
font-size: 36px;
font-weight: bold;
font-family: 'Consolas';
color: #333;
background: rgba(255, 255, 255, 0.9);
border: 1px solid #ccc;
padding: 10px;
border-radius: 10px;
transform: scale(1);
opacity: 1;
transition: opacity 0.5s ease, transform 0.5s ease;
pointer-events: none;
}
.number-tip.hide {
opacity: 0;
transform: scale(0.5);
}
/* 颜色样式 */
.color-0 {
color: #153fea;
}
.color-1 {
color: #15f00e;
}
.color-2 {
color: #6963688a;
}
/* 错误状态样式 */
.number-tip.error {
background: rgba(255, 200, 200, 0.9);
border-color: #ff0000;
}
.form-group {
margin-bottom: 1rem;
}
label {
/* display: block; */
margin-bottom: 0.5rem;
}
</style>
</head>
<body>
<div class="form-group">
<label for="number1">数字 1:</label>
<input type="text" id="number1" placeholder="请输入数字 1">
</div>
<div class="form-group">
<label for="number2">数字 2:</label>
<input type="text" id="number2" placeholder="请输入数字 2">
</div>
<div class="form-group">
<label for="number3">数字 3:</label>
<input type="text" id="number3" placeholder="请输入数字 3">
</div>
<button id="focusNumber1">激活数字 1 输入框</button>
<button id="focusNumber2">激活数字 2 输入框</button>
<button id="focusNumber3">激活数字 3 输入框</button>
<div id="numberTip" class="number-tip hide"></div>
<script>
// 获取所有的输入框和提示元素
const inputBoxes = document.querySelectorAll('input[type="text"]');
const numberTip = document.getElementById('numberTip');
// 按钮点击事件
document.getElementById('focusNumber1').addEventListener('click', () => {
document.getElementById('number1').focus();
});
document.getElementById('focusNumber2').addEventListener('click', () => {
document.getElementById('number2').focus();
});
document.getElementById('focusNumber3').addEventListener('click', () => {
document.getElementById('number3').focus();
});
// 添加输入范围配置
const inputRanges = {
0: { min: 0, max: 100 }, // 第一个输入框0-100
1: { min: 100, max: 1000 }, // 第二个输入框100-1000
2: { min: 1000, max: 10000 } // 第三个输入框1000-10000
};
// 为所有输入框添加事件监听
inputBoxes.forEach((inputBox, index) => {
// 输入框获取焦点时
inputBox.addEventListener('focus', (event) => {
event.target.select();
const value = event.target.value;
if (value !== '') {
const rawValue = value.replace(/\s/g, '');
showNumberTip(formatNumberWithColor(rawValue), inputBox, index);
}
});
inputBox.addEventListener('input', (event) => {
const value = event.target.value;
if (value !== '') {
const rawValue = value.replace(/\s/g, '');
const numValue = parseFloat(rawValue);
const range = inputRanges[index];
// 只检查最大值,允许临时小于最小值
if (!isNaN(numValue) && numValue <= range.max) {
// 保存有效值
event.target.value = formatNumber(rawValue);
event.target.dataset.lastValidValue = event.target.value;
// 显示放大提示
showNumberTip(formatNumberWithColor(rawValue), inputBox, index, false);
} else if (!isNaN(numValue) && numValue > range.max) {
// 如果超出最大值,显示错误提示
showNumberTip(
`超出最大值 ${range.max}`,
inputBox,
index,
true
);
// 还原到上一个有效值或清空
if (event.target.dataset.lastValidValue) {
event.target.value = event.target.dataset.lastValidValue;
} else {
event.target.value = '';
}
}
}
});
// 输入框失去焦点时
inputBox.addEventListener('blur', (event) => {
const value = event.target.value;
let finalValue = value;
// 处理小数点
if (value.includes('.')) {
const [integerPart, decimalPart] = value.split('.');
if (!decimalPart || decimalPart.replace(/[^\d]/g, '').length === 0) {
finalValue = integerPart;
}
}
// 检查最小值
if (finalValue !== '') {
const numValue = parseFloat(finalValue.replace(/\s/g, ''));
const range = inputRanges[index];
if (!isNaN(numValue)) {
if (numValue < range.min) {
// 如果小于最小值,显示错误提示
showNumberTip(
`不能小于最小值 ${range.min}`,
inputBox,
index,
true
);
// 设置为最小值
event.target.value = range.min;
} else if (numValue <= range.max) {
// 值在有效范围内
event.target.value = finalValue;
// 隐藏提示
numberTip.classList.add('hide');
}
}
}
});
});
// 修改数字格式化函数,移除输入框的颜色格式化
function formatNumber(value) {
// 分割整数部分和小数部分
const [integerPart, decimalPart] = value.split('.');
// 格式化整数部分,只添加空格,不添加颜色
const formattedInteger = integerPart
.replace(/[^\d]/g, '')
.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
// 格式化小数部分,只添加空格,不添加颜色
if (decimalPart !== undefined) {
const formattedDecimal = decimalPart
.replace(/[^\d]/g, '')
.replace(/(\d{3})/g, '$1 ')
.trim();
return `${formattedInteger}.${formattedDecimal}`;
}
return formattedInteger;
}
// 修改彩色格式化函数
function formatNumberWithColor(value) {
if (!value.includes('.')) {
// 如果没有小数点,从右向左添加颜色
return value
.replace(/[^\d]/g, '')
.replace(/\B(?=(\d{3})+(?!\d))/g, ' ')
.split(' ')
.map((group, index, array) => `<span class="color-${(array.length - 1 - index) % 3}">${group}</span>`)
.join(' ');
}
// 有小数点的情况
const [integerPart, decimalPart] = value.split('.');
// 整数部分:从右向左添加颜色
const coloredInteger = integerPart
.replace(/[^\d]/g, '')
.replace(/\B(?=(\d{3})+(?!\d))/g, ' ')
.split(' ')
.map((group, index, array) => `<span class="color-${(array.length - 1 - index) % 3}">${group}</span>`)
.join(' ');
// 小数部分:从左向右添加颜色
const coloredDecimal = decimalPart
.replace(/[^\d]/g, '')
.replace(/(\d{3})/g, '$1 ')
.trim()
.split(' ')
.map((group, index) => `<span class="color-${index % 3}">${group}</span>`)
.join(' ');
return `${coloredInteger}.${coloredDecimal}`;
}
// 添加一个变量来存储定时器
let hideTimer;
// 更新显示提示的函数
function showNumberTip(value, inputBox, index, isError = false) {
if (hideTimer) {
clearTimeout(hideTimer);
}
numberTip.innerHTML = value;
numberTip.classList.toggle('error', isError);
const rect = inputBox.getBoundingClientRect();
const tipRect = numberTip.getBoundingClientRect();
let left = rect.left;
let top = rect.bottom;
if (top + tipRect.height > window.innerHeight) {
top = rect.top - tipRect.height;
}
numberTip.style.left = `${left}px`;
numberTip.style.top = `${top}px`;
numberTip.classList.remove('hide');
hideTimer = setTimeout(() => {
numberTip.classList.add('hide');
}, 6000);
}
</script>
</body>
</html>

View File

@ -1,176 +0,0 @@
import visa
from typing import Optional, Tuple, Union
import os
from datetime import datetime
import tempfile
class InstrumentInterface:
def __init__(self, resource_string: str):
"""
初始化仪器接口
Args:
resource_string: VISA资源字符串例如 "TCPIP::192.168.1.43::inst0::INSTR"
"""
self.rm = visa.ResourceManager()
self.instrument = self.rm.open_resource(resource_string)
self.instrument.timeout = 30000 # 30秒超时
# 查询仪器信息以确定系统类型
success, idn = self.query("*IDN?")
if success:
self.instrument_info = idn
# 根据IDN确定仪器类型和路径
if "R&S" in idn:
self.temp_path = "/tmp/" # R&S通常基于Linux
elif "Keysight" in idn or "Agilent" in idn:
self.temp_path = "C:/temp/" # Keysight通常基于Windows
else:
# 默认使用/tmp/因为大多数仪器基于Linux
self.temp_path = "/tmp/"
else:
raise ConnectionError("Failed to identify instrument")
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
def write(self, command: str) -> bool:
"""发送SCPI命令"""
try:
self.instrument.write(command)
return self._check_error()
except Exception as e:
print(f"Error writing command {command}: {str(e)}")
return False
def query(self, command: str) -> Tuple[bool, str]:
"""查询SCPI命令"""
try:
response = self.instrument.query(command)
success = self._check_error()
return success, response.strip()
except Exception as e:
print(f"Error querying {command}: {str(e)}")
return False, ""
def _check_error(self) -> bool:
"""检查仪器错误"""
try:
errors = self.instrument.query("SYST:ERR?")
if "No error" in errors:
return True
print(f"Instrument error: {errors}")
return False
except Exception as e:
print(f"Error checking system errors: {str(e)}")
return False
def _transfer_file_to_local(self,
instrument_path: str,
local_path: str,
delete_source: bool = True) -> bool:
"""
从仪器传输文件到本地
Args:
instrument_path: 仪器上的文件路径
local_path: 本地保存路径
delete_source: 传输后是否删除仪器上的源文件
Returns:
bool: 操作是否成功
"""
try:
# 确保本地目录存在
os.makedirs(os.path.dirname(os.path.abspath(local_path)), exist_ok=True)
# 读取仪器文件数据
success, data = self.query(f"MMEM:DATA? '{instrument_path}'")
if not success:
return False
# 保存到本地
with open(local_path, 'wb') as f:
f.write(data)
# 清理仪器上的源文件(如果需要)
if delete_source:
self.write(f"MMEM:DEL '{instrument_path}'")
return True
except Exception as e:
print(f"Error transferring file: {str(e)}")
return False
def screenshot_to_file(self,
local_path: str,
format: str = "PNG") -> bool:
"""
保存仪器截图到本地文件
"""
try:
# 生成临时文件名
temp_filename = f"screenshot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.{format.lower()}"
temp_filepath = os.path.join(self.temp_path, temp_filename).replace('\\', '/')
# 配置并执行截图
self.write(f":HCOP:DEV:LANG {format}")
self.write(f":MMEM:NAME '{temp_filepath}'")
self.write(":HCOP:IMM") # 执行截图
# 传输文件到本地
return self._transfer_file_to_local(temp_filepath, local_path)
except Exception as e:
print(f"Error saving screenshot: {str(e)}")
return False
def data_to_file(self,
local_path: str,
trace_number: int = 1,
format: str = "CSV") -> bool:
"""
保存轨迹数据到本地文件
"""
try:
# 生成临时文件名
temp_filename = f"trace_{datetime.now().strftime('%Y%m%d_%H%M%S')}.{format.lower()}"
temp_filepath = os.path.join(self.temp_path, temp_filename).replace('\\', '/')
# 配置数据导出格式
self.write(":FORM:DEXP:DSEP POIN")
self.write(f":FORM:DEXP:FORM {format}")
self.write(":FORM:DEXP:HEAD OFF")
self.write(":FORM:DEXP:TRAC ALL")
# 保存到仪器临时文件
self.write(f":MMEM:STOR{trace_number}:TRAC {trace_number},'{temp_filepath}'")
# 传输文件到本地
return self._transfer_file_to_local(temp_filepath, local_path)
except Exception as e:
print(f"Error saving trace data: {str(e)}")
return False
def file_to_local(self,
instrument_path: str,
local_path: str,
delete_source: bool = False) -> bool:
"""
从仪器复制任意文件到本地
Args:
instrument_path: 仪器上的文件路径
local_path: 本地保存路径
delete_source: 是否删除仪器上的源文件
"""
return self._transfer_file_to_local(instrument_path, local_path, delete_source)
def close(self):
"""关闭连接"""
try:
self.instrument.close()
self.rm.close()
except Exception as e:
print(f"Error closing connection: {str(e)}")

View File

View File

@ -1,153 +0,0 @@
// C++ script created by FSW: 04:12:2024 14:23:36
#include <string>
#include <iostream>
#include <visa.h>
// forward declarations
static bool write_command(const ViSession& handle, const std::string& command);
static bool write_query(const ViSession& handle, const std::string& query, ViPBuf result_buffer, const ViUInt32 buffer_size, ViPUInt32 read_count = nullptr);
static bool process_system_error(const ViSession& handle);
static unsigned char get_esr(const ViSession& handle);
static ViSession g_analyzer;
// assign your own variables
static ViByte g_result[1000000];
static bool write_command( const ViSession& handle, const std::string& command )
{
ViStatus status = viWrite(handle, (ViBuf)command.c_str(), command.length(), VI_NULL);
// return true if successful
return ((status >= VI_SUCCESS) && process_system_error(handle));
}
static bool write_query( const ViSession& handle, const std::string& query, ViPBuf result_buffer, const ViUInt32 buffer_size, ViPUInt32 read_count )
{
ViStatus status = viWrite(handle, (ViBuf)query.c_str(), query.length(), VI_NULL);
if (status >= VI_SUCCESS)
{
status = viRead(handle, result_buffer, buffer_size, read_count);
}
// return true if successful
return ((status >= VI_SUCCESS) && process_system_error(handle));
}
static bool process_system_error(const ViSession& handle)
{
bool success = true;
const unsigned char EsrErrorMask = 0x3C;
if ((get_esr(handle) & EsrErrorMask) != 0)
{
char err_buf[256];
ViUInt32 readCount;
viWrite(handle, (ViBuf)":SYST:ERR?", 10, VI_NULL);
viRead(handle, (ViPBuf)err_buf, sizeof(err_buf), &readCount);
err_buf[readCount] = '\0';
std::cout << err_buf << std::endl;
viWrite(handle, (ViBuf)"*CLS", 4, VI_NULL);
success = false;
}
return success;
}
static unsigned char get_esr(const ViSession& handle)
{
char esr_buf[16];
ViUInt32 readCount;
viWrite(handle, (ViBuf)"*ESR?", 5, VI_NULL);
viRead(handle, (ViPBuf)esr_buf, sizeof(esr_buf), &readCount);
esr_buf[readCount] = '\0';
return (static_cast<unsigned char>(std::stoi(std::string(esr_buf))));
}
int main ()
{
ViSession defaultRM;
bool success = true;
// create a VISA session and return a handle to it
viOpenDefaultRM(&defaultRM);
// create a VISA session to the connected device and return a handle to it
viOpen(defaultRM, (ViRsrc)"TCPIP::169.254.177.77::inst0::INSTR", VI_NULL, VI_NULL, &g_analyzer);
success = write_command( g_analyzer, "*RST" );
success = write_command( g_analyzer, "*CLS" );
success = write_command( g_analyzer, ":SYST:DISP:UPD ON" );
success = write_command( g_analyzer, ":INIT:CONT OFF" );
success = write_command( g_analyzer, ":SENS:FREQ:STAR 1000000000" );
success = write_command( g_analyzer, ":SENS:FREQ:STOP 2000000000" );
success = write_command( g_analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV -30" );
success = write_command( g_analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV 30" );
success = write_command( g_analyzer, ":SENS:BAND:RES:AUTO OFF" );
success = write_command( g_analyzer, ":SENS:BAND:RES:AUTO ON" );
success = write_command( g_analyzer, ":SENS:BAND:VID:AUTO OFF" );
success = write_command( g_analyzer, ":SENS:BAND:VID:AUTO ON" );
success = write_command( g_analyzer, ":SENS:FREQ:MODE SWE" );
success = write_command( g_analyzer, ":DISP:WIND1:SIZE LARG" );
success = write_command( g_analyzer, ":CALC1:MARK1:FUNC:STR:STAT ON" );
success = write_command( g_analyzer, ":CALC1:MARK1:FUNC:STR:STAT OFF" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN" );
success = write_command( g_analyzer, ":SENS:POW:ACH:BAND:CHAN 300000" );
success = write_command( g_analyzer, ":SENS:POW:ACH:PRES CN" );
success = write_command( g_analyzer, ":CALC:MARK1:STAT ON" );
success = write_command( g_analyzer, ":CALC:MARK1:X 1200000000" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN" );
success = write_command( g_analyzer, ":SENS:POW:ACH:PRES CN" );
success = write_command( g_analyzer, ":SENS:POW:ACH:PRES CN" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN0" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN" );
success = write_command( g_analyzer, ":SENS:FREQ:SPAN 1000000" );
success = write_command( g_analyzer, ":SENS:FREQ:SPAN 1000000000" );
success = write_command( g_analyzer, ":CALC:MARK1:STAT ON" );
success = write_command( g_analyzer, ":CALC:MARK1:X 1200000000" );
success = write_command( g_analyzer, ":CALC:DELT2:STAT ON" );
success = write_command( g_analyzer, ":CALC:DELT2:X 1600000000" );
success = write_command( g_analyzer, ":INIT:SPUR" );
success = write_command( g_analyzer, ":MMEM:NAME 'C:\R_S\Instr\user\FSW_ScreenShot_2024-12-04_14-22-12.PNG'" );
success = write_command( g_analyzer, ":HCOP:IMM1" );
viClose(g_analyzer);
viClose(defaultRM);
return 0;
}

View File

@ -1,35 +0,0 @@
*RST
*CLS
:SYST:DISP:UPD ON
:INIT:CONT OFF
:SENS:FREQ:STAR 1000000000
:SENS:FREQ:STOP 2000000000
:DISP:WIND:TRAC:Y:SCAL:RLEV 0
:DISP:WIND:TRAC:Y:SCAL:RLEV 0
:SENS:BAND:RES:AUTO OFF
:SENS:BAND:RES:AUTO ON
:SENS:BAND:VID:AUTO OFF
:SENS:BAND:VID:AUTO ON
:SENS:FREQ:MODE SWE
:DISP:WIND1:SIZE LARG
:CALC1:MARK1:FUNC:STR:STAT ON
:CALC1:MARK1:FUNC:STR:STAT OFF
:CALC:MARK:FUNC:POW:SEL CN
:SENS:POW:ACH:BAND:CHAN 300000
:SENS:POW:ACH:PRES CN
:CALC:MARK1:STAT ON
:CALC:MARK1:X 1200000000
:CALC:MARK:FUNC:POW:SEL CN
:SENS:POW:ACH:PRES CN
:SENS:POW:ACH:PRES CN
:CALC:MARK:FUNC:POW:SEL CN0
:CALC:MARK:FUNC:POW:SEL CN
:SENS:FREQ:SPAN 1000000
:SENS:FREQ:SPAN 1000000000
:CALC:MARK1:STAT ON
:CALC:MARK1:X 1200000000
:CALC:DELT2:STAT ON
:CALC:DELT2:X 1600000000
:INIT:SPUR
:MMEM:NAME 'C:\R_S\Instr\user\FSW_ScreenShot_2024-12-04_14-22-12.PNG'
:HCOP:IMM1

View File

@ -1,109 +0,0 @@
# python script created by FSW: 04:12:2024 14:23:54
import pyvisa as visa
def write_command(instrument, command) :
instrument.write(command)
return process_system_error(instrument)
def write_query(instrument, command) :
buffer = instrument.query(command)
bSuccess = process_system_error(instrument)
return bSuccess, buffer
def process_system_error(instrument) :
bSuccess = True
EsrErrorMask = 0x3C
if ((get_esr(instrument) & EsrErrorMask) != 0) :
print(instrument.query(":SYST:ERR?"))
instrument.write("*CLS")
bSuccess = False
return bSuccess
def get_esr(instrument) :
esr = instrument.query("*ESR?")
return int(esr)
VisaResourceManager = visa.ResourceManager()
# connect to analyzer
Analyzer = VisaResourceManager.open_resource("TCPIP::169.254.177.77::inst0::INSTR")
success = write_command( Analyzer, "*RST" )
success = write_command( Analyzer, "*CLS" )
success = write_command( Analyzer, ":SYST:DISP:UPD ON" )
success = write_command( Analyzer, ":INIT:CONT OFF" )
success = write_command( Analyzer, ":SENS:FREQ:STAR 1000000000" )
success = write_command( Analyzer, ":SENS:FREQ:STOP 2000000000" )
success = write_command( Analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV -30" )
success = write_command( Analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV 30" )
success = write_command( Analyzer, ":SENS:BAND:RES:AUTO OFF" )
success = write_command( Analyzer, ":SENS:BAND:RES:AUTO ON" )
success = write_command( Analyzer, ":SENS:BAND:VID:AUTO OFF" )
success = write_command( Analyzer, ":SENS:BAND:VID:AUTO ON" )
success = write_command( Analyzer, ":SENS:FREQ:MODE SWE" )
success = write_command( Analyzer, ":DISP:WIND1:SIZE LARG" )
success = write_command( Analyzer, ":CALC1:MARK1:FUNC:STR:STAT ON" )
success = write_command( Analyzer, ":CALC1:MARK1:FUNC:STR:STAT OFF" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN" )
success = write_command( Analyzer, ":SENS:POW:ACH:BAND:CHAN 300000" )
success = write_command( Analyzer, ":SENS:POW:ACH:PRES CN" )
success = write_command( Analyzer, ":CALC:MARK1:STAT ON" )
success = write_command( Analyzer, ":CALC:MARK1:X 1200000000" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN" )
success = write_command( Analyzer, ":SENS:POW:ACH:PRES CN" )
success = write_command( Analyzer, ":SENS:POW:ACH:PRES CN" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN0" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN" )
success = write_command( Analyzer, ":SENS:FREQ:SPAN 1000000" )
success = write_command( Analyzer, ":SENS:FREQ:SPAN 1000000000" )
success = write_command( Analyzer, ":CALC:MARK1:STAT ON" )
success = write_command( Analyzer, ":CALC:MARK1:X 1200000000" )
success = write_command( Analyzer, ":CALC:DELT2:STAT ON" )
success = write_command( Analyzer, ":CALC:DELT2:X 1600000000" )
success = write_command( Analyzer, ":INIT:SPUR" )
success = write_command( Analyzer, ":MMEM:NAME 'C:\R_S\Instr\user\FSW_ScreenShot_2024-12-04_14-22-12.PNG'" )
success = write_command( Analyzer, ":HCOP:IMM1" )
# back to local mode
success = write_command(Analyzer, "@LOC")
# cleanup
Analyzer.close()
VisaResourceManager.close()

View File

@ -1,9 +0,0 @@
{
":SENS:FREQ:STAR": "1000000000",
":SENS:FREQ:STOP": "2000000000",
":DISP:WIND:TRAC:Y:SCAL:RLEV": "0",
":SENS:POW:ACH:BAND:CHAN": "300000",
":CALC:MARK1:X": "1200000000",
":SENS:FREQ:SPAN": "1000000000",
":CALC:DELT2:X": "1600000000"
}

View File

@ -1,9 +0,0 @@
{
":SENS:FREQ:STAR": "\u8d77\u59cb\u9891\u7387",
":SENS:FREQ:STOP": " \u7ec8\u6b62\u9891\u7387",
":DISP:WIND:TRAC:Y:SCAL:RLEV": " \u53c2\u8003\u7535\u5e73",
":SENS:POW:ACH:BAND:CHAN": " \u4fe1\u9053\u5e26\u5bbd",
":CALC:MARK1:X": " MARK\u70b91",
":SENS:FREQ:SPAN": " \u9891\u7387\u533a\u95f4\uff08\u5bbd\u5ea6\uff09",
":CALC:DELT2:X": " MARK\u70b91\u504f\u79fb"
}

View File

@ -1,271 +0,0 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SCPI命令参数编辑器</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
box-sizing: border-box;
}
.command-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 10px;
}
.command-row {
position: relative;
box-sizing: border-box;
height: inherit;
/* margin: 10px 0; */
padding: 10px ;
border: 1px solid #ddd;
border-radius: 4px;
display: flex;
flex: 1 1 30%;
flex-direction: column;
/* width: calc(30% - 20px); */
}
.command-row::before {
content: attr(data-index);
position: absolute;
left: 50%;
top: 25%;
transform: translate(-50%,-50%);
font-size: 40px;
color: rgba(0, 0, 0, 0.1);
pointer-events: none;
z-index: 1;
}
.comment-input {
display: inline-block;
width: 100%;
height: 100%;
padding: 5px;
border: none;
background: none;
font-size: 14px;
cursor: text;
}
.command-label {
display: inline-block;
width: auto;
font-family: monospace;
margin-top: 5px;
}
.value-input {
width: auto;
padding: 5px;
margin-top: 5px;
}
.button-container {
display: flex;
justify-content: space-between;
gap: 10px;
}
#update-btn {
width: 50%;
margin-top: 10px;
padding: 5px 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#update-btn:hover {
background-color: #45a049;
}
#reset-btn {
width: 50%;
margin-top: 10px;
padding: 5px 10px;
background-color: #f44336;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#reset-btn:hover {
background-color: #e53935;
}
.highlight {
background-color: yellow; /* 高亮更新后的值 */
}
/* 添加 toast 样式 */
.toast {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #333;
color: white;
padding: 12px 24px;
border-radius: 4px;
font-size: 14px;
opacity: 0;
transition: opacity 0.3s ease-in-out;
z-index: 1000;
}
.toast.show {
opacity: 1;
}
.toast.success {
background-color: #4CAF50;
}
.toast.error {
background-color: #f44336;
}
.command-row.active {
background-color: rgba(173, 216, 230, 0.7) !important;
}
</style>
</head>
<body>
<h1>SCPI命令参数编辑器</h1>
<div class="command-container" id="commands-container"></div>
<div class="button-container">
<button id="reset-btn">复位</button>
<button id="update-btn">更新</button>
</div>
<script>
let commandsData = [];
async function loadCommands() {
const container = document.getElementById('commands-container');
container.innerHTML = '';
const response = await fetch('commands.json');
commandsData = await response.json();
const commentsResponse = await fetch('comments.json');
const comments = await commentsResponse.json();
commandsData.forEach(({ command, value }, index) => {
const row = document.createElement('div');
row.className = 'command-row';
row.setAttribute('data-index', index + 1);
const commentDisplay = document.createElement('span');
commentDisplay.className = 'comment-input';
commentDisplay.textContent = comments[command] || '';
commentDisplay.ondblclick = () => {
const commentInput = document.createElement('input');
commentInput.type = 'text';
commentInput.value = commentDisplay.textContent;
commentInput.onblur = async () => {
comments[command] = commentInput.value;
commentDisplay.textContent = commentInput.value;
row.replaceChild(commentDisplay, commentInput);
await fetch('/save_comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(comments)
});
};
row.replaceChild(commentInput, commentDisplay);
commentInput.focus();
};
const label = document.createElement('span');
label.className = 'command-label';
label.textContent = command;
const input = document.createElement('input');
input.className = 'value-input';
// 仅支持输入数字
input.type = 'number';
input.value = value;
input.onfocus = () => {
row.classList.add('active');
};
input.onblur = () => {
row.classList.remove('active');
};
// 与原值比较,变化则高亮
input.oninput = () => {
if (input.value !== value) {
input.classList.add('highlight');
}
else {
input.classList.remove('highlight');
}
};
row.appendChild(commentDisplay);
row.appendChild(label);
row.appendChild(input);
container.appendChild(row);
});
}
function showToast(message, type = 'success') {
// 移除现有的 toast
const existingToast = document.querySelector('.toast');
if (existingToast) {
existingToast.remove();
}
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
document.body.appendChild(toast);
// 触发重排以显示动画
setTimeout(() => toast.classList.add('show'), 10);
// 3秒后自动消失
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 1500);
}
document.getElementById('update-btn').onclick = async () => {
const updates = commandsData.map(({ command }, index) => ({
command: command,
value: document.querySelectorAll('.value-input')[index].value
}));
// 根据回应判断是否更新成功
const response = await fetch('/update_command', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(updates)
});
if (response.ok) {
const result = await response.json();
if (result.success) {
showToast('更新成功!');
loadCommands(); // 重新加载命令
} else {
showToast('更新失败!', 'error');
}
} else {
showToast('网络错误,无法更新!', 'error');
}
};
document.getElementById('reset-btn').onclick = () => {
loadCommands(); // 重新加载命令以复位
};
window.onload = loadCommands;
</script>
</body>
</html>

View File

@ -1,58 +0,0 @@
import re
import json
import os
def parse_inp_file(file_path):
commands_dict = []
comments_dict = {}
with open(file_path, 'r') as f:
lines = f.readlines()
for line in lines:
parts = line.strip().split(' ')
if len(parts) == 2: # 只处理有一个参数的指令
command, value = parts
# 检查参数是否为数字(包括科学计数法)
if re.match(r'^-?\d+\.?\d*([eE][-+]?\d+)?$', value):
commands_dict.append((command, value)) # 记录指令和参数的元组
# 读取注释文件
comments_file_path = './comments.json'
if not os.path.exists(comments_file_path):
with open(comments_file_path, 'w') as f:
comments_dict = {key: " " for key, _ in commands_dict}
json.dump(comments_dict, f)
else:
with open(comments_file_path, 'r') as f:
comments_dict = json.load(f)
# 保存为JSON文件
with open('./commands.json', 'w') as f:
json.dump([{ "command": cmd, "value": val } for cmd, val in commands_dict], f, indent=2) # 保存所有指令
return commands_dict, comments_dict
def save_comments(comments_dict):
with open('./comments.json', 'w') as f:
json.dump(comments_dict, f, indent=2)
def update_inp_file(file_path, command, new_values):
with open(file_path, 'r') as f:
lines = f.readlines()
updated_lines = []
new_values_set = set(new_values) # 使用集合以避免重复值
for line in lines:
parts = line.strip().split(' ')
if len(parts) == 2 and parts[0] == command:
# 如果当前行的指令在新值中,则更新为新值
if parts[1] in new_values_set:
updated_lines.append(f"{command} {parts[1]}\n")
else:
updated_lines.append(line) # 保留原行
else:
updated_lines.append(line)
with open(file_path, 'w') as f:
f.writelines(updated_lines)

View File

@ -1,70 +0,0 @@
from flask import Flask, request, jsonify, send_from_directory
from parse_inp import parse_inp_file, update_inp_file, save_comments
import os
app = Flask(__name__)
# 确保在启动时解析inp文件
INP_FILE_PATH = os.path.abspath('File.inp')
@app.route('/')
def index():
commands, comments = parse_inp_file(INP_FILE_PATH)
return send_from_directory(os.path.abspath('./'), 'index.html')
@app.route('/commands.json')
def get_commands():
return send_from_directory(os.path.abspath('./'), 'commands.json')
@app.route('/update_command', methods=['POST'])
def update_command():
data = request.json
try:
# 读取当前的指令和参数
with open(INP_FILE_PATH, 'r') as f:
lines = f.readlines()
# 创建一个列表来存储更新后的指令
updated_lines = []
# 遍历现有的指令行
for line in lines:
parts = line.strip().split(' ')
if len(parts) == 2: # 只处理有一个参数的指令
command, value = parts
# 检查是否需要更新该指令
for item in data:
if item['command'] == command:
# 如果指令匹配,使用新的值
updated_lines.append(f"{command} {item['value']}\n")
# 匹配后应删除data中对应的指令及参数
data.remove(item)
break
else:
# 如果没有匹配,保留原行
updated_lines.append(line)
# 将更新后的指令写回文件
with open(INP_FILE_PATH, 'w') as f:
f.writelines(updated_lines)
# 更新后重新解析文件
parse_inp_file(INP_FILE_PATH)
return jsonify({'success': True})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/save_comments', methods=['POST'])
def save_comments_route():
comments = request.json
save_comments(comments)
return jsonify({'success': True})
@app.route('/comments.json')
def get_comments():
return send_from_directory(os.path.abspath('./'), 'comments.json')
if __name__ == '__main__':
# 启动时先解析一次文件
parse_inp_file(INP_FILE_PATH)
app.run(debug=True)