如何通过PyVisa解决Jeti光谱仪自定义起始块的二进制数据提取问题
问题
尝试以字节模式从Jeti GmbH光谱仪获取数据,但无法提取二进制数据,怀疑数据起始块为\x06\x07。使用PyVisa的query_binary_values方法并指定header_fmt='ieee'时出现警告,提示块起始位置异常。ASCII模式可正常获取数据但耗时过长,询问是否有方法指定自定义起始块。
环境信息
- Win10
- Python3.9
- PyVisa1.13.0
相关代码
二进制模式尝试代码
import pyvisa def start(cr): resource_manager = pyvisa.ResourceManager() device_0 = resource_manager.list_resources() jeti = resource_manager.open_resource(device_0[0], read_termination=cr, baud_rate=115200, # send_end=True, # open_timeout=3000, ) jeti.clear() return jeti def collect_responses(jeti): exposue_tint = 0.01 # ms av = 1 # average spectras format_scpi = 1 visa_res = jeti.query_binary_values(f"*MEAS:LIGHT {exposue_tint} {av} {format_scpi}", datatype='f', is_big_endian=False, header_fmt='ieee') print(visa_res) return visa_res if __name__ == "__main__": cr = '\r' # carriage return jeti = start(cr) response = collect_responses(jeti) jeti.close()
ASCII模式可行代码
def collect_responses(visa_res): res_s = [] while True: try: res = visa_res.read().split("\t")[1] except: break res_s.append(res) return res_s format_scpi = 2 jeti.write(f"*MEAS:LIGHT {exposue_tint} {av} {format_scpi}") response_s = collect_responses(jeti)
解决方案
PyVisa的query_binary_values仅支持IEEE、HP等标准头部格式,不支持自定义起始块,因此需要手动处理原始字节流来实现需求,具体步骤如下:
- 发送测量命令后读取原始字节数据
- 在原始数据中定位自定义起始块
\x06\x07 - 跳过起始块后,根据光谱仪的二进制格式解析数据
修改后的示例代码:
import pyvisa import struct def start(cr): resource_manager = pyvisa.ResourceManager() device_0 = resource_manager.list_resources() jeti = resource_manager.open_resource(device_0[0], read_termination=cr, baud_rate=115200, timeout=5000, # 增加超时确保读取完整数据 ) jeti.clear() return jeti def collect_responses(jeti): exposue_tint = 0.01 # ms av = 1 # average spectras format_scpi = 1 # 发送测量命令 jeti.write(f"*MEAS:LIGHT {exposue_tint} {av} {format_scpi}") # 读取原始字节数据 raw_data = jeti.read_raw() # 定位自定义起始块 start_marker = b'\x06\x07' start_idx = raw_data.find(start_marker) if start_idx == -1: raise ValueError("未找到自定义起始块") # 跳过起始块,截取实际数据部分 data_bytes = raw_data[start_idx + len(start_marker):] # 解析小端序单精度浮点数(每个占4字节) num_points = len(data_bytes) // 4 visa_res = struct.unpack(f'<{num_points}f', data_bytes[:num_points*4]) print(visa_res) return list(visa_res) if __name__ == "__main__": cr = '\r' # carriage return jeti = start(cr) response = collect_responses(jeti) jeti.close()
注意事项
- 需确认光谱仪返回的二进制格式:如果是双精度浮点数,将
'<f'改为'<d',每个数据占8字节;若为大端序,将'<'改为'>'。 - 若起始块后包含数据长度标识,需先解析长度再读取对应字节数的数据,避免解析无效字节。
- 若
read_raw无法一次性获取完整数据,可循环读取直到满足终止条件(比如读取到特定结束符或达到预期数据长度)。
内容的提问来源于stack exchange,提问作者Toedsjgewg
相关产品推荐
相关产品推荐

