nsqdriver 0.2.3__tar.gz → 0.2.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nsqdriver might be problematic. Click here for more details.

Files changed (25) hide show
  1. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/PKG-INFO +1 -1
  2. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/README.md +4 -1
  3. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/NS_MCI.py +3 -3
  4. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/NS_QSYNC.py +72 -47
  5. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/__init__.py +1 -1
  6. nsqdriver-0.2.5/nsqdriver/wrapper/ND_NSMCI.py +245 -0
  7. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/PKG-INFO +1 -1
  8. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/SOURCES.txt +10 -1
  9. nsqdriver-0.2.5/tests/test_cy_gen_wave.py +148 -0
  10. nsqdriver-0.2.5/tests/test_demod_speed.py +230 -0
  11. nsqdriver-0.2.5/tests/test_driver_info_memory.py +37 -0
  12. nsqdriver-0.2.5/tests/test_init_device.py +5 -0
  13. nsqdriver-0.2.5/tests/test_mixer_simulator.py +3 -0
  14. nsqdriver-0.2.5/tests/test_param_memory.py +101 -0
  15. nsqdriver-0.2.5/tests/test_rfskit_base.py +36 -0
  16. nsqdriver-0.2.5/tests/test_rpc_parser.py +102 -0
  17. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/common.py +0 -0
  18. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/setup.py +0 -0
  19. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/wrapper/AWG_ADC.py +0 -0
  20. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/wrapper/__init__.py +0 -0
  21. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/dependency_links.txt +0 -0
  22. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/requires.txt +0 -0
  23. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/top_level.txt +0 -0
  24. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/setup.cfg +0 -0
  25. {nsqdriver-0.2.3 → nsqdriver-0.2.5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nsqdriver
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Naishu Q series quantum measurement and control equipment driver interface
5
5
  Home-page: https://g2hoyqcmh4.feishu.cn/wiki/wikcnzvyMd82DLZUe2NsI6HxsFc
6
6
  Author: Naishu Technology
@@ -1,6 +1,8 @@
1
- # UltraMCI
1
+ # UltraMCI ()
2
+
2
3
  [![Tests](https://github.com/mianyan-echo/UltraMCI/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/mianyan-echo/UltraMCI/)
3
4
  ***
5
+
4
6
  ### 环境安装
5
7
  - 查看各操作帮助信息
6
8
  ```shell
@@ -40,3 +42,4 @@ make test
40
42
  - rfskit: 控制rfs等板卡设备的基础库
41
43
  - tests: 项目接口自动化测试相关文件
42
44
  - ultra_mci.ini: 借助supervisor的自动启动文件,会在`sudo make install`时被拷贝到`/etc/supervisord.d/`下
45
+ ****
@@ -336,9 +336,9 @@ class Driver(BaseDriver):
336
336
  _string = [f'*********设备{self.addr}开启成功*********']
337
337
  for key in keys:
338
338
  _string.append(f'{key}: {status.get(key, "nan")}')
339
- for i in range(len(status['rfsoc_addr'])):
340
- _string.append(f'sub_device{status["rfsoc_addr"][i]}: '
341
- f'{status["ref_clock_lock"][i]}{status["ref_clock_from"][i]}')
339
+ # for i in range(len(status['rfsoc_addr'])):
340
+ # _string.append(f'sub_device{status["rfsoc_addr"][i]}: '
341
+ # f'{status["ref_clock_lock"][i]}{status["ref_clock_from"][i]}')
342
342
  print('\n'.join(_string))
343
343
 
344
344
 
@@ -54,8 +54,8 @@ def retry(times):
54
54
 
55
55
  class Driver(BaseDriver):
56
56
  class ScannMode(enum.IntEnum):
57
- """
58
- QC/QR等被同步设备的发现方式,'local': 本地共享内存扫描, 'remote': 网络udp扫描
57
+ """!
58
+ @detail QC/QR等被同步设备的发现方式,'local': 本地共享内存扫描, 'remote': 网络udp扫描
59
59
  """
60
60
  local = 0
61
61
  """local: 本地共享内存扫描
@@ -98,6 +98,8 @@ class Driver(BaseDriver):
98
98
  Quantity('ResetTrig', value=None),
99
99
  Quantity('Shot', value=1024, ch=1), # set/get, 运行次数
100
100
  Quantity('TrigPeriod', value=200e-6, ch=1), # set/get, 触发周期
101
+ Quantity('TrigWidth', value=800e-9, ch=1), # set/get, 触发周期
102
+ Quantity('TrigDelay', value=0, ch=1), # set/get, 触发周期
101
103
  Quantity('TrigFrom', value=0, ch=1), # Trig来源: 0:内部产生;1:外部输入
102
104
  Quantity('RefClock', value='out', ch=1), # 参考时钟选择: ‘out’:外参考时钟;‘in’:内参考时钟
103
105
  Quantity('DiscoveryMode', value=ScannMode.local, ch=1), # QC/QR等被同步设备的发现方式,见DiscoveryMode说明
@@ -107,7 +109,9 @@ class Driver(BaseDriver):
107
109
  SystemParameter = {
108
110
  'RefClock': 'out', # 参考时钟选择: ‘out’:外参考时钟;‘in’:内参考时钟
109
111
  'TrigFrom': 0, # Trig来源: 0:内部产生;1:外部输入
110
- 'TrigPeriod': 200e-6,
112
+ 'TrigPeriod': 200e-6, # 触发信号重复周期
113
+ 'TrigWidth': 800e-9, # 触发信号高电平宽度 单位s
114
+ 'TrigDelay': 0, # 触发信号相对开启通知的延迟
111
115
  'DiscoveryMode': ScannMode.local, # QC/QR等被同步设备的发现方式,见DiscoveryMode说明
112
116
  }
113
117
 
@@ -119,7 +123,7 @@ class Driver(BaseDriver):
119
123
  self.gen_trig_num = 0
120
124
  self.addr = addr
121
125
 
122
- self.param = {'shots': 1024, 'period': 200e-6, 'MixMode': 2}
126
+ self.param = {'Shot': 1024, 'period': 200e-6, 'MixMode': 2}
123
127
  print_debug(f'QSYNC: 实例化成功{addr}')
124
128
 
125
129
  @property
@@ -138,9 +142,11 @@ class Driver(BaseDriver):
138
142
  return set()
139
143
 
140
144
  def open(self, **kw):
141
- """
145
+ """!
142
146
  输入IP打开设备,配置默认超时时间为5秒
143
147
  打开设备时配置RFSoC采样时钟,采样时钟以参数定义
148
+ @param kw:
149
+ @return:
144
150
  """
145
151
  # 配置系统初始值
146
152
  system_parameter = kw.get('system_parameter', {})
@@ -175,20 +181,30 @@ class Driver(BaseDriver):
175
181
  return result
176
182
 
177
183
  def set(self, name, value=None, channel=1):
178
- """
184
+ """!
179
185
  设置设备属性
186
+ @param name:
187
+ @param value:
188
+ @param channel:
189
+ @return:
180
190
  """
181
191
  print_debug(f'QSYNC: set操作被调用{name}')
182
192
  if name in {'SystemSync', 'ReInit'}:
183
193
  self.sync_system()
184
194
  elif name == 'TRIG':
185
195
  value = self.param['TrigPeriod']
186
- data = self.__fmt_qsync_start(self.param['TrigFrom'], value, self.param['Shot'])
196
+ data = self.__fmt_qsync_start(
197
+ self.param['TrigFrom'], value, self.param['Shot'],
198
+ self.param['TrigWidth'], self.param['TrigDelay']
199
+ )
187
200
  self._send_command(data, connect_timeout=2)
188
201
  self.gen_trig_num += 1
189
202
  elif name == 'GenerateTrig':
190
203
  value = self.param['TrigPeriod'] if value is None else value
191
- data = self.__fmt_qsync_start(self.param['TrigFrom'], value, self.param['Shot'])
204
+ data = self.__fmt_qsync_start(
205
+ self.param['TrigFrom'], value, self.param['Shot'],
206
+ self.param['TrigWidth'], self.param['TrigDelay']
207
+ )
192
208
  self._send_command(data, connect_timeout=2)
193
209
  self.gen_trig_num += 1
194
210
  elif name == 'ResetTrig':
@@ -203,8 +219,12 @@ class Driver(BaseDriver):
203
219
  self.param[name] = value
204
220
 
205
221
  def get(self, name, channel=1, value=0):
206
- """查询设备属性,获取数据
207
-
222
+ """!
223
+ 查询设备属性,获取数据
224
+ @param name:
225
+ @param channel:
226
+ @param value:
227
+ @return:
208
228
  """
209
229
  print_debug(f'QSYNC: get操作被调用{name}')
210
230
  if name == 'Status':
@@ -250,11 +270,11 @@ class Driver(BaseDriver):
250
270
  self._send_command(data)
251
271
 
252
272
  def _sendto_device(self, cmd_head, timeout=2):
253
- """
273
+ """!
254
274
  将指令发送给设备
255
-
256
- :param cmd_head:
257
- :return:
275
+ @param cmd_head:
276
+ @param timeout:
277
+ @return:
258
278
  """
259
279
  cmd_data = self.__fmt_qsync_common(cmd_head)
260
280
  devices = list(self.device_set)
@@ -283,11 +303,11 @@ class Driver(BaseDriver):
283
303
  return result
284
304
 
285
305
  def _sendto_qsync(self, cmd_head: int):
286
- """
306
+ """!
287
307
  将指令发送给qsync
288
308
 
289
- :param cmd_head:
290
- :return:
309
+ @param cmd_head:
310
+ @return:
291
311
  """
292
312
  cmd_data = self.__fmt_qsync_common(cmd_head)
293
313
  if not self._send_command(cmd_data, connect_timeout=2):
@@ -296,12 +316,12 @@ class Driver(BaseDriver):
296
316
  return True
297
317
 
298
318
  def update_firmware(self, file_path, boards=None):
299
- """
319
+ """!
300
320
  固件更新
301
321
 
302
- :param file_path: 固件路径
303
- :param boards:
304
- :return:
322
+ @param file_path: 固件路径
323
+ @param boards:
324
+ @return:
305
325
  """
306
326
  import os
307
327
  if not os.path.exists(file_path):
@@ -312,12 +332,12 @@ class Driver(BaseDriver):
312
332
  print(f'qsync: 固件更新 执行失败')
313
333
 
314
334
  def _connect(self, addr=None, port=5001, timeout=None):
315
- """
335
+ """!
316
336
  获取到指定ip的tcp连接
317
337
 
318
- :param addr:
319
- :param port:
320
- :return:
338
+ @param addr:
339
+ @param port:
340
+ @return:
321
341
  """
322
342
  timeout = self.timeout if timeout is None else timeout
323
343
  addr = self.addr if addr is None else addr
@@ -329,15 +349,16 @@ class Driver(BaseDriver):
329
349
  @retry(3)
330
350
  def _send_command(self, data: Union[str, bytes], wait=0, addr=None, port=5001,
331
351
  check_feedback=True, return_fdk=False, connect_timeout=10):
332
- """
352
+ """!
333
353
  发送指定内容到后端
334
354
 
335
- :param data: 指令内容
336
- :param wait: 指令发送完成后,等待一段时间再接收反馈,阻塞式等待
337
- :param addr: 后端IP
338
- :param port: 后端端口
339
- :param 是否解析反馈
340
- :return:
355
+ @param data: 指令内容
356
+ @param wait: 指令发送完成后,等待一段时间再接收反馈,阻塞式等待
357
+ @param addr: 后端IP
358
+ @param port: 后端端口
359
+ @param check_feedback: 是否解析反馈
360
+ @param connect_timeout:
361
+ @return:
341
362
  """
342
363
  command_bak = data
343
364
  try:
@@ -400,15 +421,17 @@ class Driver(BaseDriver):
400
421
  return struct.pack('=' + 'I' * len(cmd_pack), *cmd_pack)
401
422
 
402
423
  @lru_cache(maxsize=32)
403
- def __fmt_qsync_start(self, src, period, shots):
424
+ def __fmt_qsync_start(self, src, period, shots, width, delay):
404
425
  cmd_pack = (
405
426
  0x5F5F5F5F,
406
427
  0x41000001,
407
428
  0x00000000,
408
- 28,
429
+ 36,
409
430
  int(src),
410
431
  int(period * 1e9) & 0xFFFFFFFF,
411
- int(shots)
432
+ int(shots),
433
+ int(width * 1e9) & 0xFFFFFFFF,
434
+ int(delay * 1e9) & 0xFFFFFFFF
412
435
  )
413
436
 
414
437
  return struct.pack('=' + 'I' * len(cmd_pack), *cmd_pack)
@@ -433,10 +456,12 @@ class Driver(BaseDriver):
433
456
  self.set('TrigPeriod', 1 / rate)
434
457
  self.set('GenerateTrig')
435
458
 
436
- def BurstMode_init(self, count=2048, delay=200e-6, period=200e-6, **kwds):
459
+ def BurstMode_init(self, count=2048, delay=200e-6, period=200e-6, source=0, **kwds):
437
460
  self.set('ResetTrig')
438
461
  self.set('Shot', count)
439
462
  self.set('TrigPeriod', period)
463
+ self.set('TrigDelay', delay)
464
+ self.set('TrigFrom', source)
440
465
 
441
466
  def startGun(self):
442
467
  self.Trigger_singleshot()
@@ -479,8 +504,8 @@ def do_scanning():
479
504
 
480
505
 
481
506
  class DeviceCmdHandle:
482
- """
483
- 封装与QC/QR设备间的交互
507
+ """!
508
+ @brief 封装与QC/QR设备间的交互
484
509
  """
485
510
  error_map = {b'\x1a\x00\x001': {1: '指令Resync执行失败',
486
511
  2: 'REFCLK not Detected',
@@ -541,17 +566,17 @@ class DeviceCmdHandle:
541
566
  @classmethod
542
567
  def send_command(cls, data: Union[str, bytes], wait=0, addr=None, port=5001,
543
568
  check_feedback=True, return_fdk=False, connect_timeout=None):
544
- """
569
+ """!
545
570
  发送指定内容到后端
546
571
 
547
- :param data: 指令内容
548
- :param wait: 指令发送完成后,等待一段时间再接收反馈,阻塞式等待
549
- :param addr: 后端IP
550
- :param port: 后端端口
551
- :param check_feedback:
552
- :param return_fdk:
553
- :param connect_timeout:
554
- :return:
572
+ @param data: 指令内容
573
+ @param wait: 指令发送完成后,等待一段时间再接收反馈,阻塞式等待
574
+ @param addr: 后端IP
575
+ @param port: 后端端口
576
+ @param check_feedback:
577
+ @param return_fdk:
578
+ @param connect_timeout:
579
+ @return:
555
580
  """
556
581
  command_bak = data
557
582
  try:
@@ -1,7 +1,7 @@
1
1
  from .NS_MCI import Driver as MCIDriver
2
2
  from .NS_QSYNC import Driver as QSYNCDriver
3
3
 
4
- version_pack = (0, 2, 3)
4
+ version_pack = (0, 2, 5)
5
5
 
6
6
  __version__ = '.'.join(str(_) for _ in version_pack)
7
7
  __all__ = ['MCIDriver', 'QSYNCDriver', '__version__']
@@ -0,0 +1,245 @@
1
+ import numpy as np
2
+ from nsqdriver import MCIDriver, QSYNCDriver
3
+
4
+
5
+ class _XYChannel:
6
+ def __init__(self, mci: "DeviceBase", ch=1):
7
+ self.mci = mci
8
+ self.ch = ch
9
+ self.to_zero = np.zeros((16,))
10
+ self.to_one = np.ones((16,))
11
+ self.en = True
12
+ self.mode = 0
13
+ self.off = 0
14
+
15
+ def wave(self, w):
16
+ self.wavex(w, self.ch)
17
+
18
+ def wavex(self, w, idx):
19
+ if np.max(np.abs(w)) < 1e-30:
20
+ wr = np.zeros(16)
21
+ else:
22
+ wr = w
23
+ self.mci.mci_driver.set("Waveform", wr, idx)
24
+
25
+ def arm(self, k=None):
26
+ self.mci.mci_driver.set('PushWaveCache')
27
+
28
+ def trig_del(self, delay):
29
+ ...
30
+
31
+ def output_del(self, delay):
32
+ ...
33
+
34
+ def __del__(self):
35
+ pass
36
+
37
+ def output(self, b):
38
+ self.en = bool(b)
39
+ if not self.en:
40
+ self.mci.mci_driver.set("Waveform", self.to_zero, self.ch)
41
+
42
+ def mode(self, m_):
43
+ ...
44
+
45
+ def offsetx(self, off, idx):
46
+ self.mci.mci_driver.set('Waveform', off*self.to_one, idx)
47
+ self.off = off
48
+
49
+ def offset(self, off):
50
+ self.offsetx(off, self.ch)
51
+
52
+ W = {
53
+ "wave": wave,
54
+ "output": output,
55
+ "trig_del": trig_del,
56
+ "output_del": output_del,
57
+ "mode": mode,
58
+ "offset": offset,
59
+ }
60
+
61
+ Q = {"arm": arm}
62
+
63
+
64
+ class _ZChannel(_XYChannel):
65
+ pass
66
+
67
+
68
+ class _Probe:
69
+ def __init__(self, mci: "DeviceBase", ch=1):
70
+ self.mci = mci
71
+ self.ch = ch
72
+ self.freqList = []
73
+ self.SGS = None # single shot temp cache
74
+ self.AVG = None # average temp cache
75
+ self.depth = 2000
76
+ self._width = 1000
77
+ self.start = 500
78
+ self.demod = 1
79
+ self.averaged_I = np.zeros((16384, )) # 直播直采,相当于只有I路数据
80
+
81
+ def depth(self, depth_):
82
+ self.depth = depth_
83
+ self.mci.mci_driver.set('PointNumber', depth_, self.ch)
84
+
85
+ def demodulation_on(self, demod_):
86
+ self.demod = int(demod_)
87
+
88
+ def start(self, start_):
89
+ self.start = start_
90
+ self.mci.mci_driver.set('TriggerDelay', start_, self.ch)
91
+
92
+ def width(self, width_):
93
+ self._width = width_/4e9
94
+ self.mci.mci_driver.set('PointNumber', width_, self.ch)
95
+
96
+ def freqs(self, *freqList_):
97
+ self.freqList = freqList_
98
+ self.mci.mci_driver.set('FreqList', freqList_, self.ch)
99
+
100
+ def shot(self, _shot):
101
+ self.mci.mci_driver.set('Shot', _shot)
102
+
103
+ def measure(self, k=None):
104
+ self.mci.mci_driver.set('StartCapture')
105
+ if self.demod:
106
+ self.SGS = self.mci.mci_driver.get('IQ', self.ch)
107
+ self.AVG = np.mean(self.SGS, axis=0)
108
+ else:
109
+ self.averaged_I = np.mean(self.mci.mci_driver.get('TraceIQ', self.ch), axis=0)
110
+
111
+ def single_shot(self, k=None):
112
+ return self.SGS
113
+
114
+ def average(self, k=None):
115
+ return self.AVG
116
+
117
+ def trace_I(self, k=None):
118
+ return self.averaged_I
119
+
120
+ def trace_Q(self, k=None):
121
+ return self.averaged_I
122
+
123
+ def __del__(self):
124
+ pass
125
+
126
+ W = {
127
+ "demod": demodulation_on,
128
+ "depth": depth,
129
+ "width": width,
130
+ "start": start,
131
+ "freqs": freqs,
132
+ "shot": shot,
133
+ }
134
+
135
+ Q = {
136
+ "measure": measure,
137
+ "A": average,
138
+ "S": single_shot,
139
+ "traceI": trace_I,
140
+ "traceQ": trace_Q
141
+ };
142
+
143
+
144
+ # one box need one class
145
+ class DeviceBase:
146
+ def __init__(self):
147
+ self.mci_driver = MCIDriver('127.0.0.1')
148
+ self.qsync_driver = QSYNCDriver('127.0.0.1')
149
+
150
+
151
+ class NS_MCI(DeviceBase):
152
+ def __init__(self, addr, srate=10e9, mixmode=2, ref_clk='in'):
153
+ """!
154
+ 此类涉及到系统同步,放到最后实例化
155
+ @param addr: 设备ip
156
+ @param srate: OUT通道采样率
157
+ @param mixmode: 为2时开启OUT通道混合模式,增强第二奈奎斯特区输出
158
+ @param ref_clk: 设备参考信号来源,不接外输出100M时都配置为'in'
159
+ """
160
+ super(NS_MCI, self).__init__()
161
+ self.mci_driver = MCIDriver(addr)
162
+ self.qsync = QSYNCDriver(addr)
163
+ self.srate = srate
164
+ self.mixmode = mixmode
165
+ self.ref_clk = ref_clk
166
+ self.connect()
167
+
168
+ def connect(self):
169
+ mci_params = {'DArate': self.srate, 'MixMode': self.mixmode}
170
+ qsync_params = {'RefClock': self.ref_clk}
171
+
172
+ self.qsync.open(system_parameter=qsync_params)
173
+ self.mci_driver.open(system_parameter=mci_params)
174
+ self.qsync.sync_system()
175
+
176
+ self.mci_driver.set('EnableWaveCache', True)
177
+
178
+ for _ch in range(22):
179
+ xy_ch = _ch+1
180
+ setattr(self, f'OUT{xy_ch}', _XYChannel(self, xy_ch))
181
+ for _ch in range(2):
182
+ probe_ch = _ch+1
183
+ setattr(self, f'IN{probe_ch}', _Probe(self, probe_ch))
184
+
185
+ def trig_interval(self, interval):
186
+ self.interval = interval
187
+ self.qsync.set('TrigPeriod', int(interval))
188
+
189
+ def trig_count(self, count_):
190
+ self.qsync.set('Shot', int(count_))
191
+
192
+ def trig(self):
193
+ self.qsync.set('GenerateTrig', self.interval)
194
+
195
+ def awg_arm(self):
196
+ self.mci_driver.set('PushWaveCache')
197
+
198
+ def __del__(self):
199
+ pass
200
+
201
+ W = {
202
+ "trig_interval": trig_interval,
203
+ "trig_count": trig_count,
204
+ "connect": connect,
205
+ "trig": trig,
206
+ "awg_arm": awg_arm,
207
+ }
208
+
209
+ Q = {
210
+ }
211
+
212
+
213
+ class NS_Z(DeviceBase):
214
+ def __init__(self, addr, mixmode=2):
215
+ """!
216
+ 此类负责控制24 Z OUT通道的设备,采样率固定为2Gsps,mixmode固定为1
217
+ @param addr: 设备ip
218
+ @param mixmode: 为1时关闭OUT通道混合模式
219
+ """
220
+ super(NS_Z, self).__init__()
221
+ self.mci_driver = MCIDriver(addr)
222
+ self.qsync = QSYNCDriver(addr)
223
+ self.srate = 2e9
224
+ self.mixmode = 1
225
+ self.connect()
226
+
227
+ def connect(self):
228
+ mci_params = {'DArate': self.srate, 'MixMode': self.mixmode}
229
+ self.mci_driver.open(system_parameter=mci_params)
230
+
231
+ self.mci_driver.set('EnableWaveCache', True)
232
+
233
+ for _ch in range(24):
234
+ xy_ch = _ch+1
235
+ setattr(self, f'OUT{xy_ch}', _ZChannel(self, xy_ch))
236
+
237
+ def awg_arm(self):
238
+ self.mci_driver.set('PushWaveCache')
239
+
240
+ W = {
241
+ "connect": connect,
242
+ }
243
+
244
+ Q = {
245
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nsqdriver
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Naishu Q series quantum measurement and control equipment driver interface
5
5
  Home-page: https://g2hoyqcmh4.feishu.cn/wiki/wikcnzvyMd82DLZUe2NsI6HxsFc
6
6
  Author: Naishu Technology
@@ -11,4 +11,13 @@ nsqdriver.egg-info/dependency_links.txt
11
11
  nsqdriver.egg-info/requires.txt
12
12
  nsqdriver.egg-info/top_level.txt
13
13
  nsqdriver/wrapper/AWG_ADC.py
14
- nsqdriver/wrapper/__init__.py
14
+ nsqdriver/wrapper/ND_NSMCI.py
15
+ nsqdriver/wrapper/__init__.py
16
+ tests/test_cy_gen_wave.py
17
+ tests/test_demod_speed.py
18
+ tests/test_driver_info_memory.py
19
+ tests/test_init_device.py
20
+ tests/test_mixer_simulator.py
21
+ tests/test_param_memory.py
22
+ tests/test_rfskit_base.py
23
+ tests/test_rpc_parser.py
@@ -0,0 +1,148 @@
1
+ from functools import wraps
2
+ import platform
3
+ from concurrent.futures import ProcessPoolExecutor
4
+ import numpy as np
5
+ import pytest
6
+ from waveforms import *
7
+ from time import time
8
+
9
+ from cython_lib.lib_gen_waveform.gen_waveform import gen_wave
10
+
11
+ sample_rate = 4e9
12
+ width = 20e-9
13
+ time_line = np.linspace(0, width * 100, int(width * 100 * sample_rate))
14
+ waves = {
15
+ 'poly': poly([1, -1 / 2, 1 / 6, -1 / 12]),
16
+ 'cos': cos(2 * pi * 5.2e9),
17
+ 'sin': sin(2 * pi * 5.2e9),
18
+ 'gaussian': gaussian(width) >> (width * 2),
19
+ 'sinc': sinc(6e8),
20
+ 'square': square(width) >> (width * 2),
21
+ 'cosPulse': cosPulse(width) >> (width * 2),
22
+ 'chirp_linear': chirp(1e9, 1.5e9, width * 10, type='linear'),
23
+ 'chirp_exponential': chirp(1e9, 1.5e9, width * 10, type='exponential'),
24
+ 'chirp_hyperbolic': chirp(1e9, 1.5e9, width * 10, type='hyperbolic'),
25
+ 'cos*gaussian': cos(2 * pi * 5.2e9) * gaussian(width) >> (width * 2),
26
+ 'cos*cosPulse': cos(2 * pi * 5.2e9) * cosPulse(width) >> (width * 2),
27
+ 'gaussian_with_window': (gaussian(10) >> width*2) + square(width, edge=5, type='linear') * cos(2 * pi * 5.2e9),
28
+ }
29
+
30
+
31
+ def gen(_wave, _width, rate):
32
+ line = np.arange(0, _width, 1 / rate)
33
+ gen_wave(_wave, line)
34
+
35
+
36
+ def gen_numpy(_wave, _width, rate):
37
+ line = np.arange(0, _width, 1 / rate)
38
+ _wave(line)
39
+
40
+
41
+ class TestCyGenWave:
42
+ @pytest.mark.skipif(platform.system() == 'Windows', reason='gen_wave暂不支持windows')
43
+ @pytest.mark.parametrize('wave', [pytest.param(j, id=f'Wave<{i}>') for i, j in waves.items()])
44
+ def test_waveform_close(self, wave: Waveform):
45
+ """
46
+ 判断生成的float64数据是否全部接近
47
+ """
48
+ wave_numpy = wave(time_line)
49
+ wave_cython = gen_wave(wave, time_line)
50
+ assert np.allclose(wave_numpy, wave_cython)
51
+
52
+ @pytest.mark.skipif(platform.system() == 'Windows', reason='gen_wave暂不支持windows')
53
+ @pytest.mark.parametrize('wave', [pytest.param(j, id=f'Wave<{i}>') for i, j in waves.items()])
54
+ def test_waveform_equal(self, wave):
55
+ """
56
+ 判断生成的数据转为int16后是否完全相等
57
+ """
58
+ wave_numpy = wave(time_line)
59
+ wave_cython = gen_wave(wave, time_line)
60
+ assert ((wave_numpy * (2 ** 15 - 1)).astype(np.int16) == (wave_cython * (2 ** 15 - 1)).astype(np.int16)).all()
61
+
62
+ @pytest.mark.skipif(platform.system() == 'Windows', reason='gen_wave暂不支持windows')
63
+ def test_pulse_speed(self):
64
+ """
65
+ pulse信号生成速度测试
66
+ """
67
+ sample_rate = 6e9
68
+ width = 30e-9
69
+ width_all = 100e-6
70
+ frq = 4200e6
71
+ chnl_num = 24
72
+
73
+ wave_lo = cos(2 * pi * frq)
74
+ wave_30 = [(gaussian(width) >> (width / 2)) * wave_lo for i in range(chnl_num)]
75
+ for wave in wave_30:
76
+ wave.start = 0
77
+ wave.stop = width
78
+ wave_100 = [zero() for i in range(chnl_num)]
79
+ for index, wave in enumerate(wave_100):
80
+ for i in range(int(300)):
81
+ wave += (gaussian(width) >> (width * 2 * i + width / 2)) * wave_lo
82
+ wave.start = 0
83
+ wave.stop = width_all
84
+ wave_100[index] = wave
85
+
86
+ st = time()
87
+ for i in range(10):
88
+ for wave in wave_30:
89
+ line = np.arange(0, width_all, 1 / sample_rate)
90
+ wave_numpy = wave_lo(line)
91
+ print(f'\n{chnl_num}通道, numpy长波形生成耗时: {(time() - st) / 10}')
92
+
93
+ st = time()
94
+ for i in range(10):
95
+ for wave in wave_30:
96
+ line = np.arange(0, width_all, 1 / sample_rate)
97
+ wave_cython = gen_wave(wave_lo, line)
98
+ print(f'{chnl_num}通道, cython长波形生成耗时: {(time() - st) / 10}')
99
+
100
+ assert np.allclose(wave_numpy, wave_cython)
101
+
102
+ pool = ProcessPoolExecutor(max_workers=6)
103
+ st = time()
104
+ for i in range(5):
105
+ futures = [pool.submit(gen_numpy, wave_lo, width_all, sample_rate) for wave in wave_30]
106
+ [_.result() for _ in futures]
107
+ print(f'{chnl_num}通道, 进程池numpy长波形生成耗时: {(time() - st) / 5}')
108
+ pool.shutdown(wait=True)
109
+
110
+ pool = ProcessPoolExecutor(max_workers=6)
111
+ st = time()
112
+ for i in range(5):
113
+ futures = [pool.submit(gen, wave_lo, width_all, sample_rate) for wave in wave_30]
114
+ [_.result() for _ in futures]
115
+ print(f'{chnl_num}通道, 进程池cython长波形生成耗时: {(time() - st) / 5}')
116
+ pool.shutdown(wait=True)
117
+
118
+ st = time()
119
+ for i in range(100):
120
+ for wave in wave_30:
121
+ line = np.arange(0, width_all, 1/sample_rate)
122
+ wave_numpy = wave(line)
123
+ print(f'\n{chnl_num}通道, numpy简单波形生成耗时: {(time() - st) / 100}')
124
+
125
+ st = time()
126
+ for i in range(100):
127
+ for wave in wave_30:
128
+ line = np.arange(0, width_all, 1 / sample_rate)
129
+ wave_cython = gen_wave(wave, line)
130
+ print(f'{chnl_num}通道, cython简单波形生成耗时: {(time() - st) / 100}')
131
+
132
+ assert np.allclose(wave_numpy, wave_cython)
133
+
134
+ st = time()
135
+ for i in range(5):
136
+ for wave in wave_100:
137
+ line = np.arange(0, width_all, 1 / sample_rate)
138
+ wave_numpy = wave(line)
139
+ print(f'{chnl_num}通道, numpy复杂波形生成耗时: {(time() - st) / 10}')
140
+
141
+ st = time()
142
+ for i in range(5):
143
+ for wave in wave_100:
144
+ line = np.arange(0, width_all, 1 / sample_rate)
145
+ wave_cython = gen_wave(wave, line)
146
+ print(f'{chnl_num}通道, cython复杂波形生成耗时: {(time() - st) / 5}')
147
+
148
+ assert np.allclose(wave_numpy, wave_cython)
@@ -0,0 +1,230 @@
1
+ from functools import wraps
2
+ import numpy as np
3
+ import pytest
4
+ import torch
5
+ # import matplotlib.pyplot as plt
6
+ from waveforms import *
7
+ from time import time
8
+ from .conftest import skip_demod_speed_test, skip_numpy_demod_test
9
+
10
+ from backend.svqbit import coff_para, demodMatrix, demodTorch, demodTorch_no_complex
11
+
12
+ # import os
13
+ #
14
+ # cpu_num = 6 # 这里设置成你想运行的CPU个数
15
+ # os.environ ['OMP_NUM_THREADS'] = str(cpu_num)
16
+ # os.environ ['OPENBLAS_NUM_THREADS'] = str(cpu_num)
17
+ # os.environ ['MKL_NUM_THREADS'] = str(cpu_num)
18
+ # os.environ ['VECLIB_MAXIMUM_THREADS'] = str(cpu_num)
19
+ # os.environ ['NUMEXPR_NUM_THREADS'] = str(cpu_num)
20
+ # torch.set_num_threads(cpu_num)
21
+ torch.set_grad_enabled(False)
22
+
23
+
24
+ def no_tensor_grad(func):
25
+ @wraps(func)
26
+ def dec(*args, **kwargs):
27
+ with torch.no_grad():
28
+ return func(*args, **kwargs)
29
+
30
+ return dec
31
+
32
+
33
+ params = []
34
+ for chnl in [1, 6, 12]:
35
+ for frq in [6, 12, 24]:
36
+ for shots in [32, 64, 128, 256, 512, 1024]:
37
+ params.append(pytest.param(chnl, frq, shots, id=f'Param<{chnl, frq, shots}>'))
38
+
39
+
40
+ def test_pytorch_cuda_enabled():
41
+ print(torch.__config__.show())
42
+ print(torch.__config__.parallel_info())
43
+ print(f'\n pytorch_cuda_enable: {torch.cuda.is_available()}')
44
+ assert True
45
+
46
+
47
+ @pytest.mark.skipif(True, reason='两边算出来的值有差别')
48
+ def test_algorithm_equal():
49
+ lo, freq = 4.5e9, [i*1e6 for i in range(1, 9)]
50
+ sigs = []
51
+ for i in range(8):
52
+ wave = cos(2 * np.pi * (lo+freq[i]))
53
+ wave.start, wave.stop = 0, 4e-6
54
+ noise = 0.01*np.random.random((1024, 16000))
55
+ sig = np.empty((1024, 16000))
56
+ _sig = wave.sample(4e9)
57
+ for j in range(1024):
58
+ sig[j] = _sig
59
+ sig += noise
60
+ sig = (2 ** 15 - 1) * sig
61
+ sigs.append(sig)
62
+ sigs = np.array(sigs, dtype=np.int16)
63
+
64
+ tm = np.linspace(0, 4e-6, 16000)
65
+ coff = [coff_para(tm, lo).reshape(16000, 1) for _ in range(8)]
66
+ coff = np.array(coff)
67
+
68
+ numpy_res = np.zeros((8, 1024, 1), dtype='complex64')
69
+ for i in range(8):
70
+ numpy_res[i] = demodMatrix(sigs[i], coff[i])
71
+
72
+ torch_res = torch.zeros((8, 1024, 1), dtype=torch.complex64)
73
+ torch_sigs = torch.tensor(sigs).to(torch.complex64)
74
+ torch_coff = torch.tensor(coff).to(torch.complex64)
75
+ for i in range(4):
76
+ demodTorch(torch_sigs[:, i*256:(i+1)*256, :], torch_coff, out=torch_res[:, i*256:(i+1)*256, :])
77
+
78
+ assert np.allclose(numpy_res, torch_res.numpy())
79
+ assert (numpy_res == torch_res).all()
80
+
81
+
82
+ @pytest.mark.skipif(skip_demod_speed_test, reason='跳过硬解速度测试,过于耗时')
83
+ @pytest.mark.parametrize('chnl_num, frq_num, shots', params)
84
+ def test_pytorch_demodulator(chnl_num, frq_num, shots):
85
+ sample_rate = 4e9
86
+ width = 4e-6
87
+
88
+ freqlist = [[4550e6 + j * 300e6 for j in range(frq_num)] for i in range(chnl_num)]
89
+ cofflist = {i: [] for i in range(chnl_num)}
90
+
91
+ wav_readout = [zero() for i in range(chnl_num)]
92
+ for i in range(chnl_num):
93
+ for j in range(len(freqlist[i])):
94
+ wav_readout[i] = wav_readout[i] + cos(2 * np.pi * freqlist[i][j]) * (square(width) >> width / 2)
95
+ # wav_readout[i] = wav_readout[i] + (square(width) >> width/2+1e-6)
96
+ wav_readout[i] = wav_readout[i] / frq_num
97
+ wav_readout[i].start = 0
98
+ wav_readout[i].stop = width
99
+ wav_readout[i] = (2 ** 15 - 1) * wav_readout[i].sample(sample_rate).reshape((1, round(width * sample_rate)))
100
+ wav_readout[i] = np.vstack([wav_readout[i] for _ in range(shots)])
101
+ wav_readout = torch.tensor(np.array(wav_readout, dtype='int16'), dtype=torch.int16).to(torch.complex64)
102
+
103
+ tm = np.linspace(0, width, round(width * sample_rate))
104
+ for chnl in range(chnl_num):
105
+ _freqlist = freqlist[chnl]
106
+ cofflist[chnl] = np.empty((len(_freqlist), round(width * sample_rate))).astype(complex)
107
+ for i in range(len(_freqlist)):
108
+ cofflist[chnl][i] = coff_para(tm, _freqlist[i], 0)
109
+ cofflist[chnl] = cofflist[chnl].T
110
+ cofflist = torch.tensor(np.array([i for i in cofflist.values()]), dtype=torch.complex64)
111
+
112
+ st = time()
113
+ threads = []
114
+ # for i in range(2):
115
+ # _thread = threading.Thread(target=demodTorch, args=(wav_readout, cofflist), daemon=True)
116
+ # threads.append(_thread)
117
+ # for i in threads:
118
+ # i.start()
119
+ # for i in threads:
120
+ # i.join()
121
+
122
+ for i in range(5):
123
+ demodTorch(wav_readout, cofflist)
124
+ print(f'----{chnl_num}通道, {frq_num}频点, {shots}shots, 单个shots硬解耗时: {(time() - st) / 5 / shots * 1e6}-{200}μs')
125
+
126
+
127
+ @pytest.mark.skipif(skip_demod_speed_test, reason='跳过硬解速度测试,过于耗时')
128
+ @pytest.mark.parametrize('chnl_num, frq_num, shots', params)
129
+ def test_pytorch_no_complex(chnl_num, frq_num, shots):
130
+ """
131
+ 下变频速度测试,非复数运算版
132
+ """
133
+ sample_rate = 4e9
134
+ width = 4e-6
135
+ # chnl_num = 1
136
+ # frq_num = 1
137
+ # shots = 1
138
+
139
+ freqlist = [[4550e6 + j * 300e6 for j in range(frq_num)] for i in range(chnl_num)]
140
+ cofflist = {i: [] for i in range(chnl_num)}
141
+
142
+ wav_readout = [zero() for i in range(chnl_num)]
143
+ for i in range(chnl_num):
144
+ for j in range(len(freqlist[i])):
145
+ wav_readout[i] = wav_readout[i] + cos(2 * np.pi * freqlist[i][j]) * (square(width) >> width / 2)
146
+ # wav_readout[i] = wav_readout[i] + (square(width) >> width/2+1e-6)
147
+ wav_readout[i] = wav_readout[i] / frq_num
148
+ wav_readout[i].start = 0
149
+ wav_readout[i].stop = width
150
+ wav_readout[i] = (2 ** 15 - 1) * wav_readout[i].sample(sample_rate).reshape((1, round(width * sample_rate)))
151
+ wav_readout[i] = np.vstack([wav_readout[i] for _ in range(shots)])
152
+ wav_readout = torch.tensor(np.array(wav_readout, dtype='int16'), dtype=torch.float32)
153
+
154
+ tm = np.linspace(0, width, round(width * sample_rate))
155
+ for chnl in range(chnl_num):
156
+ _freqlist = freqlist[chnl]
157
+ cofflist[chnl] = np.empty((len(_freqlist), round(width * sample_rate))).astype(complex)
158
+ for i in range(len(_freqlist)):
159
+ cofflist[chnl][i] = coff_para(tm, _freqlist[i], 0)
160
+ cofflist[chnl] = cofflist[chnl].T
161
+ cofflist = torch.tensor(np.array([i for i in cofflist.values()]), dtype=torch.complex64)
162
+ cofflist = [cofflist.real.to(torch.float32), cofflist.imag.to(torch.float32)]
163
+
164
+ st = time()
165
+ threads = []
166
+ # for i in range(10):
167
+ # _thread = threading.Thread(target=demodTorch, args=(wav_readout, cofflist), daemon=True)
168
+ # threads.append(_thread)
169
+ # for i in threads:
170
+ # i.start()
171
+ # for i in threads:
172
+ # i.join()
173
+
174
+ for i in range(5):
175
+ demodTorch_no_complex(wav_readout, cofflist, [round(width * sample_rate)]*chnl_num)
176
+ print(f'----{chnl_num}通道, {frq_num}频点, {shots}shots, 单个shots硬解耗时: {(time() - st) / 5 / shots * 1e6}-{200}μs')
177
+
178
+
179
+ @pytest.mark.skipif(skip_demod_speed_test, reason='跳过硬解速度测试')
180
+ @pytest.mark.skipif(skip_numpy_demod_test, reason='跳过numpy硬解速度测试')
181
+ @pytest.mark.parametrize('chnl_num, frq_num, shots', params)
182
+ def test_numpy_demodulator(chnl_num, frq_num, shots):
183
+ """
184
+ numpy库硬解测试
185
+
186
+ :param chnl_num:
187
+ :param frq_num:
188
+ :param shots:
189
+ :return:
190
+ """
191
+ sample_rate = 4e9
192
+ width = 4e-6
193
+ # chnl_num = 1
194
+ # frq_num = 1
195
+ # shots = 1
196
+
197
+ freqlist = [[4550e6 + j * 300e6 for j in range(frq_num)] for i in range(chnl_num)]
198
+ cofflist = {i: [] for i in range(chnl_num)}
199
+
200
+ wav_readout = [zero() for i in range(chnl_num)]
201
+ for i in range(chnl_num):
202
+ for j in range(len(freqlist[i])):
203
+ wav_readout[i] = wav_readout[i] + cos(2 * np.pi * freqlist[i][j]) * (square(width) >> width / 2)
204
+ # wav_readout[i] = wav_readout[i] + (square(width) >> width/2+1e-6)
205
+ wav_readout[i] = wav_readout[i] / frq_num
206
+ wav_readout[i].start = 0
207
+ wav_readout[i].stop = width
208
+ wav_readout[i] = (2 ** 15 - 1) * wav_readout[i].sample(sample_rate).reshape((1, round(width * sample_rate)))
209
+ wav_readout[i] = np.vstack([wav_readout[i] for _ in range(shots)])
210
+ wav_readout = np.array(wav_readout, dtype='int16')
211
+
212
+ tm = np.linspace(0, width, round(width * sample_rate))
213
+ for chnl in range(chnl_num):
214
+ _freqlist = freqlist[chnl]
215
+ cofflist[chnl] = np.empty((len(_freqlist), round(width * sample_rate))).astype(complex)
216
+ for i in range(len(_freqlist)):
217
+ cofflist[chnl][i] = coff_para(tm, _freqlist[i], 0)
218
+ cofflist[chnl] = cofflist[chnl].T
219
+ cofflist = np.array([i for i in cofflist.values()], dtype=complex)
220
+
221
+ st = time()
222
+ threads = []
223
+
224
+ def demod(wave, coff):
225
+ for i in range(chnl_num):
226
+ demodMatrix(wave[i], coff[i])
227
+
228
+ for i in range(2):
229
+ demod(wav_readout, cofflist)
230
+ print(f'----{chnl_num}通道, {frq_num}频点, {shots}shots, 单个shots硬解耗时: {(time() - st) / 2 / (shots) * 1e6}-{200}μs')
@@ -0,0 +1,37 @@
1
+ import pytest
2
+ import multiprocessing
3
+
4
+ from nsqdriver.NS_MCI import SHARED_DEVICE_MEM as MCI_MEM
5
+ from nsqdriver.NS_QSYNC import SHARED_DEVICE_MEM as QSYNC_MEM
6
+
7
+ DEVICES_IP = ['192.168.1.205', '192.168.1.206', '192.168.1.207', '192.168.1.208']
8
+
9
+
10
+ def test_driver_info_shared():
11
+ """
12
+ 测试进程内确实可以共享info信息
13
+
14
+ :return:
15
+ """
16
+ for ip in DEVICES_IP:
17
+ MCI_MEM.ip = ip
18
+ assert set(QSYNC_MEM.ip) == set(DEVICES_IP)
19
+
20
+
21
+ def other_process():
22
+ for ip in DEVICES_IP:
23
+ MCI_MEM.ip = ip
24
+
25
+
26
+ def test_shared_to_other_process():
27
+ """
28
+ 测试跨进程增加信息
29
+
30
+ :return:
31
+ """
32
+ MCI_MEM.clear_ip()
33
+ assert QSYNC_MEM.ip == []
34
+ process = multiprocessing.Process(target=other_process, daemon=True)
35
+ process.start()
36
+ process.join(2)
37
+ assert set(QSYNC_MEM.ip) == set(DEVICES_IP)
@@ -0,0 +1,5 @@
1
+ from cython_lib.lib_init_device.init_device import get_board_info
2
+
3
+
4
+ def test_print_board_info():
5
+ print(get_board_info())
@@ -0,0 +1,3 @@
1
+ class TestUpMixer:
2
+ def test_conversion(self):
3
+ pass
@@ -0,0 +1,101 @@
1
+ import pytest
2
+ import numpy as np
3
+ import waveforms
4
+
5
+ from rfskit.config import dumps_dict
6
+ from backend.param_memory import ParamMemory, global_param_memory, AttributeWithMemory, BoardProperty
7
+
8
+
9
+ class ExampleClass(AttributeWithMemory):
10
+ def __init__(self):
11
+ self.attr_a = 'a'
12
+ self.attr_b = 156
13
+
14
+
15
+ EXAMPLE_OBJ = ExampleClass()
16
+
17
+
18
+ class TestParamMemory:
19
+ """
20
+ 测试ParamMemory
21
+ """
22
+
23
+ def test_is_singleton_memory(self):
24
+ """
25
+ 测试全局只有一个memory
26
+ """
27
+ print(f'\n{self.test_is_singleton_memory.__doc__}')
28
+ assert ParamMemory() is global_param_memory
29
+
30
+ @pytest.mark.parametrize('name, value',
31
+ [pytest.param('save_list', [1, 2, 3], id='Type<list>'),
32
+ pytest.param('save_waveforms', waveforms.cos(10), id='Type<waveforms>')])
33
+ def test_set_param(self, name, value):
34
+ """
35
+ 测试向memory里设置和取出参数
36
+ """
37
+ # print(f'\n{self.test_set_param.__doc__} {name}-{value}')
38
+ setattr(global_param_memory, name, value)
39
+ assert getattr(global_param_memory, name) == value
40
+
41
+ def test_like_obj_attr(self):
42
+ _value = np.array([1, 2, 3])
43
+ global_param_memory.data = _value
44
+ assert (global_param_memory.data == _value).all()
45
+ assert 'data' in global_param_memory._memory
46
+
47
+ def test_memory_like_dict(self):
48
+ _value = np.array([1, 2, 3])
49
+ global_param_memory['data_dict'] = _value
50
+ assert (global_param_memory['data_dict'] == _value).all()
51
+ assert 'data_dict' in global_param_memory['_memory']
52
+
53
+ def test_debug_param(self):
54
+ debug_name = 'debug_test'
55
+ assert global_param_memory.get_debug_value(debug_name) is None
56
+ # global_param_memory.debug_params.add(debug_name)
57
+ global_param_memory.add_debug_param(debug_name)
58
+ for i in range(10):
59
+ global_param_memory.debug_test = i
60
+
61
+ # print(f'\n{global_param_memory.debug_test}')
62
+ assert global_param_memory.debug_test == 9
63
+ assert list(global_param_memory.get_debug_value(debug_name).values()) == list(range(10))
64
+ print(f"\n{dumps_dict(global_param_memory.get_debug_value(debug_name))}")
65
+ # clear_debug_log
66
+ global_param_memory.clear_debug_log(debug_name)
67
+ assert global_param_memory.get_debug_value(debug_name) == {}
68
+
69
+ def test_print_memory(self):
70
+ print(f'\n keys: {global_param_memory.show_keys()}')
71
+ print(f'\n repr: {repr(global_param_memory)}')
72
+ print(f'\n str: {global_param_memory}')
73
+
74
+
75
+ class TestAttributeWithMemory:
76
+ def test_auto_memory_name(self):
77
+ assert getattr(EXAMPLE_OBJ, 'memory_name', None) == EXAMPLE_OBJ.__class__.__name__
78
+
79
+ def test_remember_obj_attr(self):
80
+ assert global_param_memory[EXAMPLE_OBJ.get_memory_name('attr_a')] == EXAMPLE_OBJ.attr_a
81
+ assert global_param_memory[EXAMPLE_OBJ.get_memory_name('attr_b')] == EXAMPLE_OBJ.attr_b
82
+
83
+
84
+ class Board(AttributeWithMemory):
85
+ aa = BoardProperty('aa_p', 10)
86
+
87
+ def __init__(self, aa):
88
+ self.aa = aa
89
+
90
+
91
+ class TestBoardProperty:
92
+ def test_set_prop(self):
93
+ a = Board(3)
94
+ b = Board(6)
95
+ c = Board({'aa_p': 8})
96
+ assert a.aa == 3 and b.aa == 6 and c.aa == 8
97
+
98
+ def test_immutable_prop(self):
99
+ a = Board({'!aa_p': 9})
100
+ a.aa = 15
101
+ assert a.aa == 9
@@ -0,0 +1,36 @@
1
+ import pytest
2
+ import time
3
+
4
+ from .conftest import FakeTCPHandler, skip_rfskit_test
5
+ from rfskit import RFSKit
6
+ from rfskit.interface import CommandTCPInterface, DataTCPInterface
7
+
8
+
9
+ class TestRFSKit:
10
+ @pytest.mark.skipif(skip_rfskit_test,
11
+ reason='越过rfskit测试')
12
+ def test_init_rfskit(self, fake_cmd_server):
13
+ CommandTCPInterface._target_id = '127.0.0.1'
14
+ kit = RFSKit(auto_load_icd=True,
15
+ auto_write_file=False,
16
+ cmd_interface=CommandTCPInterface,
17
+ data_interface=DataTCPInterface)
18
+ connected = kit.start_command('127.0.0.1')
19
+
20
+ assert isinstance(kit, RFSKit)
21
+ assert connected
22
+ assert connected == kit._connected
23
+
24
+ @pytest.mark.skipif(skip_rfskit_test,
25
+ reason='越过rfskit测试')
26
+ @pytest.mark.skipif(not FakeTCPHandler.finished,
27
+ reason='处理函数未完成')
28
+ def test_send_tcp_command(self, fake_cmd_server):
29
+ time.sleep(1)
30
+ CommandTCPInterface._target_id = '127.0.0.1'
31
+ kit = RFSKit(auto_load_icd=True,
32
+ auto_write_file=False,
33
+ cmd_interface=CommandTCPInterface,
34
+ data_interface=DataTCPInterface)
35
+ kit.start_command('127.0.0.1')
36
+ assert kit.execute_command('内部PRF产生')
@@ -0,0 +1,102 @@
1
+ import pytest
2
+ from copy import copy
3
+ import numpy as np
4
+ import waveforms
5
+
6
+ from nsqdriver.NS_MCI import RPCValueParser
7
+ from rfskit.config import dumps_dict
8
+
9
+
10
+ class TestRPCValueParser:
11
+ """
12
+ 测试RPCValueParser.dump与RPCValueParser.load的完备性
13
+ """
14
+ @pytest.mark.parametrize('value',
15
+ [pytest.param(['tom', 1, 2, [1, 2]], id='Type<list>'),
16
+ pytest.param(np.array([1], dtype=np.float64)[0], id='Type<np.float64>'),
17
+ pytest.param(np.array([1], dtype=np.int32)[0], id='Type<np.int32>'),
18
+ pytest.param(15.34, id='Type<num>'),
19
+ pytest.param(15 + 1j, id='Type<complex>'),
20
+ pytest.param(waveforms.cos(100), id='Type<waveforms.Waveform>')])
21
+ def test_parser_common(self, value):
22
+ """
23
+ 通用测试
24
+
25
+ :param value:
26
+ :return:
27
+ """
28
+ data = RPCValueParser.dump(value)
29
+ _res = RPCValueParser.load(data)
30
+ assert value == _res
31
+
32
+ def test_parser_ndarray(self):
33
+ """
34
+ 测试ndarray
35
+
36
+ :return:
37
+ """
38
+ # 普通array
39
+ _value = np.arange(100).reshape((10, 10))
40
+ data = RPCValueParser.dump(_value)
41
+ _res = RPCValueParser.load(data)
42
+ assert _value.dtype == _res.dtype
43
+ assert (_value == _res).all()
44
+
45
+ # 复数array
46
+ _value = np.arange(100).reshape((10, 10)).astype(complex)
47
+ data = RPCValueParser.dump(_value)
48
+ _res = RPCValueParser.load(data)
49
+ assert _value.dtype == _res.dtype
50
+ assert (_value == _res).all()
51
+
52
+ def test_parser_tuple(self):
53
+ """
54
+ 测试元组
55
+
56
+ :return:
57
+ """
58
+ _value = (1, 2, '2')
59
+ data = RPCValueParser.dump(_value)
60
+ _res = RPCValueParser.load(data)
61
+
62
+ assert _value == tuple(_res)
63
+
64
+ def test_parser_nested(self):
65
+ """
66
+ 多层嵌套测试
67
+
68
+ :return:
69
+ """
70
+ _list = [1, 2, 3]
71
+ _tuple = (4, 5, 6)
72
+ _ndarray = np.array([6, 7, 8])
73
+ _list_tuple = copy(_list)
74
+ _list_tuple.append(copy(_tuple))
75
+ _waveform = waveforms.sinc(10)
76
+
77
+ _value = [_list, _tuple, _ndarray, _list_tuple, _waveform]
78
+ data = RPCValueParser.dump(_value)
79
+ _res = RPCValueParser.load(data)
80
+
81
+ assert _list == _res[0]
82
+ assert _tuple == tuple(_res[1])
83
+ assert (_ndarray == _res[2]).all()
84
+ assert _list_tuple[:len(_list)] == _res[3][:len(_list)]
85
+ assert _list_tuple[len(_list)] == tuple(_res[3][len(_list)])
86
+ assert _waveform == _res[4]
87
+
88
+
89
+ @pytest.mark.parametrize('value',
90
+ [pytest.param({}, id='Type<empty>'),
91
+ pytest.param({0: ['34', 'list', {1: 1}]}, id='Type<list>'),
92
+ pytest.param({'array': np.arange(10000)}, id='Type<np.float64>'),
93
+ pytest.param({'np.int32': np.array([1], dtype=np.int32)[0]}, id='Type<np.int32>'),
94
+ pytest.param({'num': 15.34}, id='Type<num>'),
95
+ pytest.param({'complex': 15 + 1j}, id='Type<complex>'),
96
+ pytest.param({'waveform': waveforms.cos(100)}, id='Type<waveforms.Waveform>'),
97
+ pytest.param({'collection': {1, 2, 3}}, id='Type<collection>'),
98
+ pytest.param({'dict': {'num': 123.34345, 'array': np.arange(10000)}}, id='Type<nested>')])
99
+ def test_dumps_dict(value):
100
+ data = dumps_dict(value)
101
+ print('\n'+data)
102
+ assert isinstance(data, str)
File without changes
File without changes
File without changes
File without changes