目录
前言
MT8820C简介
结构图
实现原理
Step 1:添加设备
Step 2:验证
代码介绍
Step 1: 建立连接
Step 2:构建发送SCPI指令的底层私有函数
Step 3:具体功能的封装
后记
前言
因为要开发一款GSM TX In RX Band Noise Power 的测试工具,所以需要同时实现对MT8820C无线通讯测试仪和频谱仪的控制。关于频谱仪的控制可以参考我上一篇文章https://blog.csdn.net/xgh1951/article/details/128644801?spm=1001.2014.3001.5502
这篇文章就简单介绍一下如何实现对MT8820C仪表的控制!
MT8820C简介
MT8820C是安立公司研发和制造LTE/2G/3G终端的新一体化测试平台设备);它是基于2G/3G市场流行的MT8820B。MT8820C支持LTEAdvanced DL CA手机的制造,包括射频校准,射频参数测试和功能测试。
它向后兼容MT8820B/15B。它支持LTE-Advanced DL CA/3G/2G UE RF开发以及多系统制造。与 MT28820A/B有助于减少设置时间和MT8820B到MT8820C升级选项降低了安装成本。
更详细的介绍至安立官网查询:https://www.anritsu.com/zh-cn/test-measurement/products/mt8820c
结构图
GSM TX In RX Band Noise Power 测试的硬件接线图如下(画的不好各位凑合看):
实现原理
由上图的硬件接线结构可以看出PC和MT8820C的通讯主要时依靠网线。其实一般的NI设备都支持GPIB或者LAN的通讯方式,我这里使用网线的原因是因为我们研发GPIB的资源比较紧张,采购的话呢成本也较高,所以果断采用网线的通讯方式。
关于实现的方法和我上一篇文章提到的一样,还是通过VISA的方式通讯,我这边使用的是Pyvisa库来实现。所以就需要安装NI软件,安装完毕后打开NI MAX添加测试仪表:
Step 1:添加设备
打开NI MAX,点击展开->右键设备和接口 -> 新建 -> 选择VISA TCP/IP Resources
此处要选择Manual Entry of Raw Socket 。
Step 2:验证
点击下一步 -> 输入MT8820C的IP地址 -> 输入MT8820C的端口号(MT8820 Port1 的端口号是56001,Port2的端口号是56002) -> 点击Validate -> 点击完成。若验证失败请检查PC的IP地址和仪表的IP地址是否在同一网段
如上图所示表示添加成功。只有添加成功,Pyvisa库才可以与仪表建立通讯。NI VISA是桥梁,Pyvisa是工具;概念要理清楚。
代码介绍
前面的准备工作做好以后就开始开始实现具体的功能了
Step 1: 建立连接
该函数主要时传入IP地址和端口,然后存放入字典中
@classmethod def _open_mt8820c_connection(cls, ipAddress, port): """建立连接函数,传入IP地址和端口号""" ipAddress = str(ipAddress) port = Utils.to_enum(port, InstRFPorts) resourceName = 'TCPIP0::{}::{}::SOCKET'.format(ipAddress, port.value) connectionID = cls.get_connectionID(resourceName) if connectionID not in cls._connections: cls._connections[connectionID] = cls._mt8820c_connection(resourceName) # 该函数会去验证resourceName是否在当前的资源列表中 cls._active_connection = connectionID logger.info('Connect to MT8820C successful') return (connectionID, cls._connections[connectionID])
其中又调用了_mt8820c_connection()的私有函数,该私有函数其实就是传入上面函数中的resourceName,然后检查该名称是否在当前的资源列表中:
@classmethod def _mt8820c_connection(cls, resourceName): resourceName = str(resourceName) rm = pyvisa.ResourceManager() resource_list = rm.list_resources(query='?*::SOCKET') if resourceName in resource_list: cls.inst = rm.open_resource(resourceName) cls.inst.clear() cls.inst.timeout = 3000 cls.inst.read_termination = '\n' return cls.inst else: raise AssertionError("The signal analyzer is not online.")
Step 2:构建发送SCPI指令的底层私有函数
def _send_raw_command(cls, command, connectionID=None, timeout=2): command = str(command) connectionID = cls._check_connectionID(connectionID) if not command: raise ValueError('Command string is empty') _RCAKeywords._connections[connectionID].write('*CLS') _RCAKeywords._connections[connectionID].write(command) timeoutAbs = time.time() + timeout while time.time() < timeoutAbs: opStatus = _RCAKeywords._connections[connectionID].query('*OPC?') if int(opStatus) == 1: break try: cls._error_query() # 每次发送指令后会去检查是否有Error出现 except AssertionError: raise AssertionError('Send command ({}) to MT8820C failed.'.format(command))
Step 3:具体功能的封装
上述两个基本功能完成后就可以开始根据需求对具体的功能进行封装了,这里简单举几个例子。
1. 设置Standard
可以设置当前制式为GSM/WCDMA/LTE等
def select_standard(self, std): std = Utils.to_enum(std, CommunicationStd) command = 'STDSEL {:s}'.format(std.value) _RCAKeywords._send_raw_command(command) _RCAKeywords._send_raw_command('PRESET')
这里用到的CommunicationStd是一个网络制式的枚举类:
class CommunicationStd(enum.Enum): WCDMA = 'WCDMA' GSM = 'GSM' LTE = 'LTE'
2.建立呼叫
def start_call(self, timeout=20): timeout = float(timeout) success = False count = 0 status = self.get_call_processing_status() if status != SequenceCode.IDLE: self.end_call() while count < 3: # 这里会循环尝试三次呼叫,如果三次都未能呼叫成功则报错 _RCAKeywords._send_raw_command('CALLSA') timeoutAbs = time.time() + timeout while time.time() < timeoutAbs: time.sleep(1) status = self.get_call_processing_status() if status == SequenceCode.COMMUNICATION: success = True break if success: break count += 1 if success: logger.info('Start Call success') else: raise AssertionError('Start Call not successful within {} seconds, pls check DUT and retest'.format(timeout * 3))
关于建立呼叫这个功能,通过查阅仪器的SCPI指令手册,发现呼叫的指令为“CALLSA”,所以直接用之前写好的发送指令底层函数_send_raw_command() 将命令发送至设备。
我会尝试去呼叫测试终端3次,每次间隔20s,如果成功则退出,三次未能呼叫成功则抛出错误提示。
3. 终止呼叫,挂断
通过查阅仪器手册可知,End call的指令是“CALLSO”, 所以还是用_send_raw_command()将指令发送至仪表并检查其状态即可,实现如下:
def end_call(self, timeout=20): timeout = float(timeout) success = False _RCAKeywords._send_raw_command('CALLSO') timeoutAbs = time.time() + timeout while time.time() < timeoutAbs: time.sleep(1) status = self.get_call_processing_status() if status == SequenceCode.IDLE: success = True break if success: logger.info('End call success') else: raise AssertionError('End Call not successful within {} seconds, pls check DUT'.format(timeout))
4.其他设置
关于其他的设置都是同样的方法,重点在于找到相关功能的SCPI指令,然后直接封装即可,我这里还封装了一些其他功能,比如common部分的参数设置, 测试模式的设置等等;这里就不过多赘述了。
后记
其实关于频谱仪也罢,无线通信测试仪也罢,这些只要是符合NI标准的可编程设备的远程控制方法都是差不多的。只要你掌握SCPI指令的格式,VISA的基本知识,控制任何NI设备都很简单。
当你基本的功能实现以后,你可以集成到你的测试框架中来执行自动化的测试,提升测试效率。当然,你也可以将你的功能集成至你写的GUI客户端中,供测试人员远程操作仪表!
以上内容若有错误的地方欢迎各位指正!感谢!
有需要源码的同学,可以私聊我!我经常在线!