编写信号发生器的控制脚本需要结合设备特性、通信协议和测试需求,通过编程实现参数设置、状态监控和自动化测试。以下是分步骤的详细指南,包含代码示例(Python)和关键注意事项:
一、前期准备
1. 确认设备信息
- 型号与接口:查阅设备手册,确认支持的接口(如LAN、USB、GPIB)和协议(如SCPI、IVI)。
- 示例:Keysight E4438C支持LAN(VXI-11)和GPIB,协议为SCPI。
- 参数范围:记录关键参数范围(如频率、幅度、调制类型)。
- 示例:频率范围
100Hz~6GHz,幅度范围 -130dBm~+20dBm。
2. 安装驱动与库
3. 连接设备
- 物理连接:通过网线、USB线或GPIB卡连接设备与电脑。
- 查找设备地址:
- 使用NI MAX(NI-VISA工具)或Keysight Connection Expert扫描设备。
- 记录设备的IP地址(LAN)或VISA资源字符串(如
TCPIP0::192.168.1.100::inst0::INSTR)。
二、脚本编写步骤
1. 初始化连接
| import pyvisa |
|
| # 创建资源管理器 |
| rm = pyvisa.ResourceManager() |
|
| # 打开设备连接(替换为实际资源字符串) |
| device = rm.open_resource("TCPIP0::192.168.1.100::inst0::INSTR") |
|
| # 设置超时(秒)和读写终止符 |
| device.timeout = 5000 |
| device.read_termination = 'n' |
| device.write_termination = 'n' |
|
| # 查询设备标识(验证连接) |
| print(device.query("*IDN?")) |
2. 基本参数设置
设置频率与幅度:
| def set_signal(freq_hz, amp_dbm): |
| # 设置频率(单位:Hz) |
| device.write(f"FREQ {freq_hz}Hz") |
| # 设置幅度(单位:dBm) |
| device.write(f"POW {amp_dbm}dBm") |
| # 启用输出 |
| device.write("OUTP ON") |
|
| # 示例:设置1GHz信号,幅度0dBm |
| set_signal(1e9, 0) |
设置调制类型(如AM、FM、脉冲):
| def set_modulation(mod_type, depth=50): |
| # 关闭调制(先重置) |
| device.write("MOD OFF") |
| # 设置调制类型(AM为例) |
| if mod_type.upper() == "AM": |
| device.write("MOD:AM:STAT ON") |
| device.write(f"MOD:AM:DEP {depth}%") |
| elif mod_type.upper() == "FM": |
| device.write("MOD:FM:STAT ON") |
| device.write(f"MOD:FM:DEV {10e3}Hz") |
| # 其他调制类型类似... |
|
| # 示例:启用AM调制,深度50% |
| set_modulation("AM", 50) |
3. 高级功能(AWG模式)
- 上传自定义波形:
| import numpy as np |
|
| def upload_arbitrary_waveform(waveform_data, sample_rate): |
| # 生成正弦波(示例) |
| t = np.linspace(0, 1, len(waveform_data)) |
| waveform = np.sin(2 * np.pi * 5e6 * t) |
| # 归一化到[-1, 1]并转换为16位整数 |
| waveform_scaled = np.int16((waveform / np.max(np.abs(waveform))) * 32767) |
| # 上传波形到设备(假设设备支持ARB:DATA命令) |
| device.write("SOUR:FUNC:ARB:STAT ON") |
| device.write_binary_values( |
| "SOUR:DATA:ARB:DATA", waveform_scaled, |
| datatype='h', is_big_endian=False |
| ) |
| # 设置采样率 |
| device.write(f"SOUR:FREQ:RAST {sample_rate}Hz") |
|
| # 示例:上传1000点的正弦波,采样率100MSa/s |
| upload_arbitrary_waveform(np.zeros(1000), 100e6) |
4. 状态查询与同步
查询当前状态:
| def query_status(): |
| freq = device.query("FREQ?") |
| amp = device.query("POW?") |
| status = device.query("OUTP:STAT?") |
| print(f"Frequency: {freq.strip()} Hz, Power: {amp.strip()} dBm, Output: {status.strip()}") |
|
| # 示例:查询并打印状态 |
| query_status() |
等待操作完成:
| def wait_for_operation(): |
| # 查询操作完成标志(*OPC?返回"1"表示完成) |
| while True: |
| if device.query("*OPC?").strip() == "1": |
| break |
| time.sleep(0.1) |
|
| # 示例:设置频率后等待完成 |
| device.write("FREQ 2GHz") |
| wait_for_operation() |
5. 错误处理与日志
三、完整示例脚本
| import pyvisa |
| import time |
| import logging |
|
| # 初始化日志 |
| logging.basicConfig(filename='signal_generator.log', level=logging.INFO) |
|
| def main(): |
| try: |
| # 连接设备 |
| rm = pyvisa.ResourceManager() |
| device = rm.open_resource("TCPIP0::192.168.1.100::inst0::INSTR") |
| device.timeout = 5000 |
| device.read_termination = 'n' |
| device.write_termination = 'n' |
| logging.info(f"Connected to: {device.query('*IDN?').strip()}") |
|
| # 设置信号 |
| set_signal(device, 1e9, 0) |
| set_modulation(device, "AM", 30) |
|
| # 查询状态 |
| query_status(device) |
|
| # 关闭输出 |
| device.write("OUTP OFF") |
| logging.info("Test completed successfully.") |
|
| except pyvisa.Error as e: |
| logging.error(f"VISA Error: {str(e)}") |
| except Exception as e: |
| logging.error(f"Unexpected Error: {str(e)}") |
| finally: |
| if 'device' in locals(): |
| device.close() |
|
| def set_signal(dev, freq_hz, amp_dbm): |
| dev.write(f"FREQ {freq_hz}Hz") |
| dev.write(f"POW {amp_dbm}dBm") |
| dev.write("OUTP ON") |
| logging.info(f"Set frequency: {freq_hz}Hz, power: {amp_dbm}dBm") |
|
| def set_modulation(dev, mod_type, depth): |
| dev.write("MOD OFF") |
| if mod_type.upper() == "AM": |
| dev.write("MOD:AM:STAT ON") |
| dev.write(f"MOD:AM:DEP {depth}%") |
| logging.info(f"Enabled AM modulation, depth: {depth}%") |
| # 其他调制类型类似... |
|
| def query_status(dev): |
| freq = dev.query("FREQ?").strip() |
| amp = dev.query("POW?").strip() |
| status = dev.query("OUTP:STAT?").strip() |
| print(f"Current Status - Freq: {freq} Hz, Power: {amp} dBm, Output: {'ON' if status == '1' else 'OFF'}") |
|
| if __name__ == "__main__": |
| main() |
四、关键注意事项
- 参数范围验证:
- 在设置前查询设备支持的参数范围(如
FREQ:MAX?、POW:MIN?),避免越界错误。
- 异步操作处理:
- 对耗时操作(如波形上传)使用异步模式或后台线程,避免阻塞主程序。
- 设备兼容性:
- 不同厂商的SCPI命令可能略有差异(如Keysight与R&S),需参考具体手册。
- 资源释放:
- 使用
try-finally确保设备连接关闭,防止资源泄漏。
- 调试技巧:
- 先用串口调试工具(如PuTTY)手动发送命令,验证设备响应后再集成到脚本中。
五、扩展功能
- 多设备协同控制:通过线程或消息队列同步多台信号发生器。
- 自动化测试集成:将脚本与TestStand、LabVIEW等测试框架结合,实现批量测试。
- 远程控制:通过Web接口(如Flask)封装脚本,实现跨网络控制。
通过以上步骤,您可以编写出稳定、高效的信号发生器控制脚本,满足从基础信号生成到复杂调制测试的需求。