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.
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/PKG-INFO +1 -1
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/README.md +4 -1
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/NS_MCI.py +3 -3
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/NS_QSYNC.py +72 -47
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/__init__.py +1 -1
- nsqdriver-0.2.5/nsqdriver/wrapper/ND_NSMCI.py +245 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/PKG-INFO +1 -1
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/SOURCES.txt +10 -1
- nsqdriver-0.2.5/tests/test_cy_gen_wave.py +148 -0
- nsqdriver-0.2.5/tests/test_demod_speed.py +230 -0
- nsqdriver-0.2.5/tests/test_driver_info_memory.py +37 -0
- nsqdriver-0.2.5/tests/test_init_device.py +5 -0
- nsqdriver-0.2.5/tests/test_mixer_simulator.py +3 -0
- nsqdriver-0.2.5/tests/test_param_memory.py +101 -0
- nsqdriver-0.2.5/tests/test_rfskit_base.py +36 -0
- nsqdriver-0.2.5/tests/test_rpc_parser.py +102 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/common.py +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/setup.py +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/wrapper/AWG_ADC.py +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver/wrapper/__init__.py +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/dependency_links.txt +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/requires.txt +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/nsqdriver.egg-info/top_level.txt +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/setup.cfg +0 -0
- {nsqdriver-0.2.3 → nsqdriver-0.2.5}/setup.py +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# UltraMCI
|
|
1
|
+
# UltraMCI ()
|
|
2
|
+
|
|
2
3
|
[](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
|
-
|
|
341
|
-
|
|
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 = {'
|
|
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(
|
|
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(
|
|
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
|
-
|
|
257
|
-
|
|
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
|
-
|
|
290
|
-
|
|
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
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
:
|
|
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
|
-
|
|
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
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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:
|
|
@@ -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
|
+
}
|
|
@@ -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/
|
|
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,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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|