nsqdriver 0.12.16__cp313-cp313-win_amd64.whl
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/NS_CST.py +260 -0
- nsqdriver/NS_DDS_v3.py +591 -0
- nsqdriver/NS_DDS_v4.py +778 -0
- nsqdriver/NS_MCI.py +594 -0
- nsqdriver/NS_QSYNC.py +780 -0
- nsqdriver/__init__.py +10 -0
- nsqdriver/common.py +20 -0
- nsqdriver/compiler/__init__.py +0 -0
- nsqdriver/compiler/assembler.cp313-win_amd64.pyd +0 -0
- nsqdriver/compiler/ns_wave.cp313-win_amd64.pyd +0 -0
- nsqdriver/compiler/ns_wave.pyi +151 -0
- nsqdriver/compiler/py_wave_asm.cp313-win_amd64.pyd +0 -0
- nsqdriver/compiler/py_wave_asm.pyi +29 -0
- nsqdriver/nswave/__init__.py +9 -0
- nsqdriver/nswave/_asm.pyi +97 -0
- nsqdriver/nswave/_checkers.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_checkers.pyi +47 -0
- nsqdriver/nswave/_errors.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_errors.pyi +24 -0
- nsqdriver/nswave/_functions.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_functions.pyi +34 -0
- nsqdriver/nswave/_ir.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_ir.pyi +283 -0
- nsqdriver/nswave/_ir_pass.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_ir_pass.pyi +7 -0
- nsqdriver/nswave/_optimizations.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_optimizations.pyi +16 -0
- nsqdriver/nswave/_rules.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_rules.pyi +56 -0
- nsqdriver/nswave/_simulator.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_translate.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/_translate.pyi +12 -0
- nsqdriver/nswave/kernel.cp313-win_amd64.pyd +0 -0
- nsqdriver/nswave/kernel.pyi +57 -0
- nsqdriver/wrapper/AWG_ADC.py +534 -0
- nsqdriver/wrapper/ND_NSMCI.py +245 -0
- nsqdriver/wrapper/__init__.py +0 -0
- nsqdriver-0.12.16.dist-info/METADATA +117 -0
- nsqdriver-0.12.16.dist-info/RECORD +41 -0
- nsqdriver-0.12.16.dist-info/WHEEL +5 -0
- nsqdriver-0.12.16.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
import abc
|
|
3
|
+
import dataclasses
|
|
4
|
+
from typing import List, Union, Dict, Iterable, Sized
|
|
5
|
+
from functools import wraps
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from ..NS_MCI import Driver as MCIDriver
|
|
9
|
+
from ..NS_QSYNC import Driver as QSYNCDriver
|
|
10
|
+
|
|
11
|
+
MIX_BIT_WIDTH = 32767
|
|
12
|
+
SEGMENT_ENABLE = False
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclasses.dataclass
|
|
16
|
+
class DAChannelData:
|
|
17
|
+
seg_waves: "Sized|Iterable[np.ndarray]" = tuple()
|
|
18
|
+
delays: "Sized|Iterable[float]" = tuple()
|
|
19
|
+
data = np.array([0])
|
|
20
|
+
updated: bool = False
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def right(self) -> bool:
|
|
24
|
+
return len(self.seg_waves) == len(self.delays)
|
|
25
|
+
|
|
26
|
+
def compute_data(self, rate):
|
|
27
|
+
"""计算最后可下发给设备的data
|
|
28
|
+
|
|
29
|
+
:param rate: DA采样率,单位Hz
|
|
30
|
+
:return:
|
|
31
|
+
"""
|
|
32
|
+
if not self.updated:
|
|
33
|
+
return
|
|
34
|
+
# if not self.right:
|
|
35
|
+
# print(f'警告:波形片段数{len(self.seg_waves)}与波形延迟数{len(self.delays)}不匹配')
|
|
36
|
+
# return
|
|
37
|
+
data = []
|
|
38
|
+
for seg, delay in zip(self.seg_waves, self.delays):
|
|
39
|
+
seg = seg / MIX_BIT_WIDTH
|
|
40
|
+
data.append(np.zeros((round(float(delay) * rate),)))
|
|
41
|
+
data.append(seg)
|
|
42
|
+
self.data = np.hstack(data)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ChannelDataPara(DAChannelData):
|
|
46
|
+
def __check_waveform(self, wave):
|
|
47
|
+
if wave.stop is None:
|
|
48
|
+
raise ValueError('waveform.stop为None,应为一确定波形时宽')
|
|
49
|
+
wave.start = 0 if wave.start is None else wave.start
|
|
50
|
+
|
|
51
|
+
def compute_data(self, rate):
|
|
52
|
+
import waveforms
|
|
53
|
+
if not self.updated:
|
|
54
|
+
return
|
|
55
|
+
if not self.right:
|
|
56
|
+
print(f'警告:波形片段数{len(self.seg_waves)}与波形延迟数{len(self.delays)}不匹配')
|
|
57
|
+
return
|
|
58
|
+
data = waveforms.zero()
|
|
59
|
+
wave_width = 0
|
|
60
|
+
for seg, delay in zip(self.seg_waves, self.delays):
|
|
61
|
+
seg: waveforms.Waveform
|
|
62
|
+
self.__check_waveform(seg)
|
|
63
|
+
wave_width += delay
|
|
64
|
+
window = waveforms.square(seg.stop - seg.start) >> seg.start
|
|
65
|
+
data += ((window*seg) >> wave_width)
|
|
66
|
+
wave_width += (seg.stop - seg.start)
|
|
67
|
+
self.data = np.array(data)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclasses.dataclass
|
|
71
|
+
class ADConfig:
|
|
72
|
+
mixer_table: "np.ndarray" = np.zeros((1, 4096, 12, 2))
|
|
73
|
+
delays: "List[float]" = tuple()
|
|
74
|
+
updated: bool = False
|
|
75
|
+
coff_param: "Union[np.ndarray, List[np.ndarray]]" = (np.zeros((12, 4096), dtype=np.complex64), )
|
|
76
|
+
seg_conf: "List[List[float]]" = tuple()
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def right(self) -> bool:
|
|
80
|
+
return self.mixer_table.shape[0] == len(self.delays)
|
|
81
|
+
|
|
82
|
+
def compute_conf(self, rate):
|
|
83
|
+
"""计算最后可下发给设备的采集conf
|
|
84
|
+
|
|
85
|
+
:param rate: AD采样率,单位Hz
|
|
86
|
+
:return:
|
|
87
|
+
"""
|
|
88
|
+
if not self.updated:
|
|
89
|
+
return
|
|
90
|
+
if not self.right:
|
|
91
|
+
print(f'警告:mixer table片段数{len(self.mixer_table.shape[0])}与波形延迟数{len(self.delays)}不匹配')
|
|
92
|
+
return
|
|
93
|
+
coff_param = []
|
|
94
|
+
seg_conf = []
|
|
95
|
+
delay_count = 0
|
|
96
|
+
seg_length = self.mixer_table.shape[1]/rate
|
|
97
|
+
for idx, (table, delay) in enumerate(zip(self.mixer_table, self.delays)):
|
|
98
|
+
table: "np.ndarray"
|
|
99
|
+
table = table[:, :, 0] + table[:, :, 1]*1j
|
|
100
|
+
coff_param.append(table.T)
|
|
101
|
+
seg_conf.append([seg_length, delay_count])
|
|
102
|
+
delay_count += seg_length+delay if idx != 0 else seg_length
|
|
103
|
+
self.coff_param = coff_param
|
|
104
|
+
self.seg_conf = seg_conf
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class _BaseDriver(abc.ABC):
|
|
108
|
+
class DARunMode(enum.IntEnum):
|
|
109
|
+
TRIGGER_MODE = 1
|
|
110
|
+
"""触发模式"""
|
|
111
|
+
CONTINUOUS_MODE = 2
|
|
112
|
+
"""连续模式"""
|
|
113
|
+
|
|
114
|
+
class ADRunMode(enum.IntEnum):
|
|
115
|
+
ALGORITHMIC_MODE = 1
|
|
116
|
+
"""算法采集模式"""
|
|
117
|
+
TRACE_MODE = 2
|
|
118
|
+
"""时域采集模式"""
|
|
119
|
+
|
|
120
|
+
mode_map = {}
|
|
121
|
+
|
|
122
|
+
def __init__(self, *args):
|
|
123
|
+
self.driver: "MCIDriver" = MCIDriver()
|
|
124
|
+
self.sys_param = {
|
|
125
|
+
'MixMode': 2, # Mix模式,1:第一奈奎斯特去; 2:第二奈奎斯特区
|
|
126
|
+
'PLLFreq': 100e6, # 参考时钟频率, 单位为Hz
|
|
127
|
+
'RefClock': 'out', # 参考时钟选择: ‘out’:外参考时钟;‘in’:内参考时钟
|
|
128
|
+
'ADrate': 4e9, # AD采样率,单位Hz
|
|
129
|
+
'DArate': 6e9, # DA采样率,单位Hz
|
|
130
|
+
'KeepAmp': 0, # DA波形发射完毕后,保持最后一个值
|
|
131
|
+
'Delay': 0, # 配置DA的原生Delay
|
|
132
|
+
'SegmentSampling': [] # 配置分段采样
|
|
133
|
+
}
|
|
134
|
+
self.connected = False
|
|
135
|
+
|
|
136
|
+
self.run_mode = None
|
|
137
|
+
self.run_count = 1024
|
|
138
|
+
|
|
139
|
+
def connect(self, address, *args) -> bool:
|
|
140
|
+
"""连接设备
|
|
141
|
+
|
|
142
|
+
:param address: 设备ip
|
|
143
|
+
:param args:
|
|
144
|
+
:return:
|
|
145
|
+
"""
|
|
146
|
+
if self.connected and self.driver.addr != address:
|
|
147
|
+
raise ValueError(f'系统已连接到{self.driver.addr}')
|
|
148
|
+
self.driver = MCIDriver(address)
|
|
149
|
+
self.driver.open()
|
|
150
|
+
return self.init_system(*args)
|
|
151
|
+
|
|
152
|
+
def disconnect(self, address, *args):
|
|
153
|
+
if self.connected and self.driver.addr != address:
|
|
154
|
+
raise ValueError(f'系统已连接到{self.driver.addr},不可与{address}断开连接')
|
|
155
|
+
self.connected = False
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def with_connected(func):
|
|
159
|
+
@wraps(func)
|
|
160
|
+
def wrapper(*args, **kwargs):
|
|
161
|
+
self: "_BaseDriver" = args[0]
|
|
162
|
+
if not self.connected:
|
|
163
|
+
raise RuntimeError(f'系统未连接,不可调用{self.__class__.__name__}.{func.__name__}')
|
|
164
|
+
return func(*args, **kwargs)
|
|
165
|
+
|
|
166
|
+
return wrapper
|
|
167
|
+
|
|
168
|
+
def update_sys_parm(self, _input):
|
|
169
|
+
if len(_input) > 0 and isinstance(_input[0], dict):
|
|
170
|
+
self.sys_param.update(_input[0])
|
|
171
|
+
|
|
172
|
+
def init_system(self, *args) -> bool:
|
|
173
|
+
self.update_sys_parm(args)
|
|
174
|
+
self.connected = self.driver.init_device(system_parameter=self.sys_param)
|
|
175
|
+
return self.connected
|
|
176
|
+
|
|
177
|
+
def setRunMode(self, mode):
|
|
178
|
+
"""设置运行模式
|
|
179
|
+
|
|
180
|
+
:param mode:
|
|
181
|
+
:return:
|
|
182
|
+
"""
|
|
183
|
+
self.run_mode = self.mode_map.get(mode, 1)
|
|
184
|
+
|
|
185
|
+
# @with_connected
|
|
186
|
+
def setCount(self, N):
|
|
187
|
+
self.driver.set('Shot', N)
|
|
188
|
+
self.run_count = N
|
|
189
|
+
|
|
190
|
+
@abc.abstractmethod
|
|
191
|
+
def start(self, channels):
|
|
192
|
+
...
|
|
193
|
+
|
|
194
|
+
def stop(self, channels): # 停止channels里面指定的通道的运行
|
|
195
|
+
...
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class DAC(_BaseDriver):
|
|
199
|
+
with_connected = _BaseDriver.with_connected
|
|
200
|
+
mode_map = {
|
|
201
|
+
2: _BaseDriver.DARunMode.CONTINUOUS_MODE,
|
|
202
|
+
1: _BaseDriver.DARunMode.TRIGGER_MODE
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
def __init__(self, *args):
|
|
206
|
+
super(DAC, self).__init__(*args)
|
|
207
|
+
self.run_mode = self.DARunMode.TRIGGER_MODE
|
|
208
|
+
self.run_wave_points = 0
|
|
209
|
+
self.run_da_seg_cache: "Dict[int, DAChannelData]" = {}
|
|
210
|
+
|
|
211
|
+
def initDAC(self):
|
|
212
|
+
self.init_system()
|
|
213
|
+
self.driver.set('EnableWaveCache', True)
|
|
214
|
+
|
|
215
|
+
@with_connected
|
|
216
|
+
def write_wave(self, waves, channeli):
|
|
217
|
+
"""
|
|
218
|
+
给其中一个通道写波形,waves:[wave0,wave1,wave2,...]
|
|
219
|
+
其中wave0,wave1,...为能直接写入fpga的int数组或uint数组,这里可以写一段或多段波形,
|
|
220
|
+
触发模式下,仪器接收一个触发信号后,每段波形依次运行,波形之间的延迟可以通过setTriggerDelays函数设置
|
|
221
|
+
注意,对于每一个触发信号,waves里的波形都会被运行
|
|
222
|
+
|
|
223
|
+
:param waves: List[np.array] int16
|
|
224
|
+
:param channeli: int
|
|
225
|
+
:return:
|
|
226
|
+
"""
|
|
227
|
+
da_data = self.run_da_seg_cache.get(channeli, DAChannelData())
|
|
228
|
+
da_data.seg_waves = waves
|
|
229
|
+
da_data.updated = True
|
|
230
|
+
self.run_da_seg_cache[channeli] = da_data
|
|
231
|
+
# self._upload_wave([channeli])
|
|
232
|
+
|
|
233
|
+
@with_connected
|
|
234
|
+
def setTriggerDelays(self, delays, channeli):
|
|
235
|
+
"""
|
|
236
|
+
设置trigger和发出波形之间的delays,只用于trig的运行模式,接收到trig后会前后相继的运行写入的[wave0,wave1,wave2,...]
|
|
237
|
+
delays=[delay0,delay1,delay2,....]一一对应于[wave0,wave1,wave2,...]
|
|
238
|
+
delay0为trig信号和wave0的起始时刻之间的延迟,delay1为wave0的末尾时刻和wave1的起始时刻之间的延迟,依次类推
|
|
239
|
+
|
|
240
|
+
:param delays: List[float]
|
|
241
|
+
:param channeli:
|
|
242
|
+
:return:
|
|
243
|
+
"""
|
|
244
|
+
da_data = self.run_da_seg_cache.get(channeli, DAChannelData())
|
|
245
|
+
da_data.delays = delays
|
|
246
|
+
da_data.updated = True
|
|
247
|
+
self.run_da_seg_cache[channeli] = da_data
|
|
248
|
+
self._upload_wave([channeli])
|
|
249
|
+
|
|
250
|
+
@with_connected
|
|
251
|
+
def write_param_waveform(self, wave, channeli):
|
|
252
|
+
"""发送要求wave为waveforms的Waveform对象
|
|
253
|
+
|
|
254
|
+
:param wave:
|
|
255
|
+
:param channeli:
|
|
256
|
+
:return:
|
|
257
|
+
"""
|
|
258
|
+
self.driver.set('GenWave', wave, channeli)
|
|
259
|
+
|
|
260
|
+
@with_connected
|
|
261
|
+
def start(self, channels):
|
|
262
|
+
"""当前后台仅能支持配置过波形的所有通道一起播放,后续支持
|
|
263
|
+
|
|
264
|
+
:param channels:
|
|
265
|
+
:return:
|
|
266
|
+
"""
|
|
267
|
+
# 生效缓存的数据。支持ping-pang模式
|
|
268
|
+
self.driver.set('PushWaveCache')
|
|
269
|
+
if self.run_mode is self.DARunMode.CONTINUOUS_MODE:
|
|
270
|
+
period = self.run_wave_points / self.sys_param['DArate']
|
|
271
|
+
self.driver.set('GenerateTrig', period)
|
|
272
|
+
|
|
273
|
+
def _upload_wave(self, channels=None):
|
|
274
|
+
"""按需计算要下发的data,并将缓存中“updated”的数据更新到设备中
|
|
275
|
+
|
|
276
|
+
:param channels:
|
|
277
|
+
:return:
|
|
278
|
+
"""
|
|
279
|
+
channels = self.run_da_seg_cache.keys() if channels is None else channels
|
|
280
|
+
rate = self.sys_param['DArate']
|
|
281
|
+
for chnl in channels:
|
|
282
|
+
if chnl not in self.run_da_seg_cache:
|
|
283
|
+
continue
|
|
284
|
+
da_data = self.run_da_seg_cache[chnl]
|
|
285
|
+
da_data.compute_data(rate)
|
|
286
|
+
if not da_data.updated:
|
|
287
|
+
continue
|
|
288
|
+
self.driver.set('Waveform', da_data.data, chnl)
|
|
289
|
+
da_data.updated = False
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class ADC(_BaseDriver):
|
|
293
|
+
with_connected = _BaseDriver.with_connected
|
|
294
|
+
mode_map = {
|
|
295
|
+
1: _BaseDriver.ADRunMode.TRACE_MODE,
|
|
296
|
+
2: _BaseDriver.ADRunMode.ALGORITHMIC_MODE
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
def __init__(self, *args):
|
|
300
|
+
super(ADC, self).__init__(*args)
|
|
301
|
+
self.run_mode = self.ADRunMode.ALGORITHMIC_MODE
|
|
302
|
+
self.chnl_id = 0 if len(args) == 0 else args[0]
|
|
303
|
+
self.run_ad_chnl_conf: "Dict[int, ADConfig]" = {}
|
|
304
|
+
|
|
305
|
+
def initADC(self):
|
|
306
|
+
"""连接ADC后进行初始化
|
|
307
|
+
|
|
308
|
+
:return:
|
|
309
|
+
"""
|
|
310
|
+
self.init_system()
|
|
311
|
+
|
|
312
|
+
@with_connected
|
|
313
|
+
def write_mixerTable(self, mixData, channeli=None):
|
|
314
|
+
"""算法采集模式下,事先把要用于算法采集模式的权重数据写入ADC
|
|
315
|
+
|
|
316
|
+
:param mixData: 如果ADC可以采集Y段波形,M为解模频点数,每段波形要在M个频率点做解模,时域波形一共L个点,
|
|
317
|
+
那mixData的shape为:(Y,L,M,2),类型为int数组 或uint数组 np.array int16
|
|
318
|
+
:param channeli:
|
|
319
|
+
:return:
|
|
320
|
+
"""
|
|
321
|
+
channeli = self.chnl_id if channeli is None else channeli
|
|
322
|
+
ad_conf = self.run_ad_chnl_conf.get(channeli, ADConfig())
|
|
323
|
+
ad_conf.mixer_table = mixData
|
|
324
|
+
ad_conf.updated = True
|
|
325
|
+
self.run_ad_chnl_conf[channeli] = ad_conf
|
|
326
|
+
|
|
327
|
+
@with_connected
|
|
328
|
+
def setTriggerDelays(self, delays, channeli=None):
|
|
329
|
+
"""设置trigger和采集波形之间的delays,接收到trig后会前后相继的采集waveDatas=[waveData0,waveData1,waveData2,...]
|
|
330
|
+
delays = [delay0,delay1,delay2,....]一一对应于[waveData0,waveData1,waveData2,...]
|
|
331
|
+
delay0为trig信号和waveData0的起始时刻之间的延迟,delay1为waveData0的末尾时刻和waveData1的起始时刻之间的延迟,依次类推
|
|
332
|
+
|
|
333
|
+
:param delays: List[float]
|
|
334
|
+
:param channeli:
|
|
335
|
+
:return:
|
|
336
|
+
"""
|
|
337
|
+
channeli = self.chnl_id if channeli is None else channeli
|
|
338
|
+
ad_conf = self.run_ad_chnl_conf.get(channeli, ADConfig())
|
|
339
|
+
ad_conf.delays = delays
|
|
340
|
+
ad_conf.updated = True
|
|
341
|
+
self.run_ad_chnl_conf[channeli] = ad_conf
|
|
342
|
+
|
|
343
|
+
@with_connected
|
|
344
|
+
def collectWaveData(self, channeli=None):
|
|
345
|
+
"""采集波形数据,waveDatas=[waveData0,waveData1,waveData2,...],waveData? 为int数组,每接收一个trig,采集一次waveDatas
|
|
346
|
+
时域采集模式下,waveData0为第一段时域波形数据,shape为(N,L),N为采集波形的次数,算法采集模式下,waveData0为解模后的数据,shape为(N,M)
|
|
347
|
+
!注意该命令应该能在波形运行的过程中能采集,如果计划要采集N次,不能AWG的波形运行N次之后才采集,而是AWG边运行边采集,以加快速度
|
|
348
|
+
|
|
349
|
+
:return:
|
|
350
|
+
"""
|
|
351
|
+
try:
|
|
352
|
+
channeli = self.chnl_id if channeli is None else channeli
|
|
353
|
+
if channeli not in self.run_ad_chnl_conf:
|
|
354
|
+
raise ValueError(f'未配置通道{channeli}的相关采集信息')
|
|
355
|
+
ad_conf = self.run_ad_chnl_conf[channeli]
|
|
356
|
+
seg_num = len(ad_conf.seg_conf)
|
|
357
|
+
if self.run_mode is self.ADRunMode.TRACE_MODE:
|
|
358
|
+
data = self.driver.get('TraceIQ', channeli)
|
|
359
|
+
seg_length = data.shape[1]//seg_num
|
|
360
|
+
data = [data[:, i:i+seg_length] for i in range(seg_num)]
|
|
361
|
+
else:
|
|
362
|
+
data = self.driver.get('IQ', channeli)
|
|
363
|
+
print(data)
|
|
364
|
+
if SEGMENT_ENABLE:
|
|
365
|
+
data = [data[i] for i in range(seg_num)]
|
|
366
|
+
return data
|
|
367
|
+
except Exception as e:
|
|
368
|
+
print(e)
|
|
369
|
+
|
|
370
|
+
def clearBuf(self):
|
|
371
|
+
"""清理ADC缓存的命令,假设上次运行报错,ADC能清理掉上次报错前所采集到的波形数据
|
|
372
|
+
|
|
373
|
+
:return:
|
|
374
|
+
"""
|
|
375
|
+
self.driver.write('ResetCollect', None)
|
|
376
|
+
|
|
377
|
+
@with_connected
|
|
378
|
+
def start(self, channels):
|
|
379
|
+
"""启动ADC的运行
|
|
380
|
+
|
|
381
|
+
:param channels: QMAC有4个ad通道编号为 [1, 2, 3, 4]
|
|
382
|
+
:return:
|
|
383
|
+
"""
|
|
384
|
+
self._upload_collect_conf(channels)
|
|
385
|
+
self.driver.set('StartCapture')
|
|
386
|
+
|
|
387
|
+
def _upload_collect_conf(self, channels=None):
|
|
388
|
+
"""按需计算要下发的data,并将缓存中“updated”的数据更新到设备中
|
|
389
|
+
|
|
390
|
+
:param channels:
|
|
391
|
+
:return:
|
|
392
|
+
"""
|
|
393
|
+
channels = self.run_ad_chnl_conf.keys() if channels is None else channels
|
|
394
|
+
rate = self.sys_param['ADrate']
|
|
395
|
+
for chnl in channels:
|
|
396
|
+
if chnl not in self.run_ad_chnl_conf:
|
|
397
|
+
continue
|
|
398
|
+
ad_conf = self.run_ad_chnl_conf[chnl]
|
|
399
|
+
ad_conf.compute_conf(rate)
|
|
400
|
+
if not ad_conf.updated:
|
|
401
|
+
continue
|
|
402
|
+
self.driver.set('TriggerDelay', float(ad_conf.delays[0]), int(chnl))
|
|
403
|
+
if SEGMENT_ENABLE:
|
|
404
|
+
self.driver.set('SegmentSampling', ad_conf.seg_conf, int(chnl))
|
|
405
|
+
self.driver.set('DemodulationParam', ad_conf.coff_param, int(chnl))
|
|
406
|
+
else:
|
|
407
|
+
self.driver.set('SegmentSampling', [], int(chnl))
|
|
408
|
+
self.driver.set('DemodulationParam', ad_conf.coff_param[0], int(chnl))
|
|
409
|
+
ad_conf.updated = False
|
|
410
|
+
|
|
411
|
+
class Trig(_BaseDriver):
|
|
412
|
+
class RunMode(enum.IntEnum):
|
|
413
|
+
INSIDE_MODE = 1
|
|
414
|
+
"""内部触发模式"""
|
|
415
|
+
EXTERNAL_MODE = 2
|
|
416
|
+
"""外部触发模式"""
|
|
417
|
+
|
|
418
|
+
mode_map = {
|
|
419
|
+
1: RunMode.INSIDE_MODE,
|
|
420
|
+
2: RunMode.EXTERNAL_MODE
|
|
421
|
+
}
|
|
422
|
+
with_connected = _BaseDriver.with_connected
|
|
423
|
+
|
|
424
|
+
def __init__(self, *args):
|
|
425
|
+
super(Trig, self).__init__(*args)
|
|
426
|
+
self.sys_param = {
|
|
427
|
+
'RefClock': 'in', # 参考时钟选择: ‘out’:外参考时钟;‘in’:内参考时钟
|
|
428
|
+
'TrigFrom': 0, # Trig来源: 0:内部产生;1:外部输入
|
|
429
|
+
'TrigPeriod': 200e-6,
|
|
430
|
+
'DiscoveryMode': QSYNCDriver.ScannMode.local, # QC/QR等被同步设备的发现方式,见DiscoveryMode说明
|
|
431
|
+
}
|
|
432
|
+
self.run_mode = self.RunMode.INSIDE_MODE
|
|
433
|
+
self.driver: "QSYNCDriver" = QSYNCDriver()
|
|
434
|
+
|
|
435
|
+
def connect(self, address, *args):
|
|
436
|
+
self.driver = QSYNCDriver(address)
|
|
437
|
+
self.update_sys_parm(args)
|
|
438
|
+
self.driver.open(system_parameter=self.sys_param)
|
|
439
|
+
self.connected = True
|
|
440
|
+
|
|
441
|
+
@with_connected
|
|
442
|
+
def initTrig(self):
|
|
443
|
+
self.driver.set('ResetTrig')
|
|
444
|
+
self.driver.sync_system()
|
|
445
|
+
|
|
446
|
+
@with_connected
|
|
447
|
+
def setClock(self, **kws):
|
|
448
|
+
"""设置时钟运行相关参数,比如外部或内部时钟,时钟频率等等
|
|
449
|
+
|
|
450
|
+
:param kws: 参考信号 RefClock,TrigFrom
|
|
451
|
+
:return:
|
|
452
|
+
"""
|
|
453
|
+
self.update_sys_parm((kws, ))
|
|
454
|
+
self.driver.open(system_parameter=self.sys_param)
|
|
455
|
+
|
|
456
|
+
def checkStatus(self): # 查看相关状态,比如时钟是多少MHz,是外部接入还是内部产生,trig信号的间隔,宽度,每个通道发出trig信号的延迟
|
|
457
|
+
print(self.sys_param)
|
|
458
|
+
|
|
459
|
+
@with_connected
|
|
460
|
+
def setTrigOffset(self, time, channel): # 设置通道channel的trigger信号的延迟
|
|
461
|
+
self.driver.set('TrigOffset', time)
|
|
462
|
+
|
|
463
|
+
@with_connected
|
|
464
|
+
def setIntervalTime(self, time): # 设置触发
|
|
465
|
+
"""
|
|
466
|
+
:param time: 秒
|
|
467
|
+
"""
|
|
468
|
+
self.driver.set('TrigPeriod', time)
|
|
469
|
+
|
|
470
|
+
def setIntervalShape(self, width, amplitude): # 设置触发信号宽度和高度
|
|
471
|
+
self.driver.set('TrigWidth', width)
|
|
472
|
+
|
|
473
|
+
def start(self, channels): # 启动trig信号的运行
|
|
474
|
+
if self.run_mode is self.RunMode.INSIDE_MODE:
|
|
475
|
+
self.driver.set('GenerateTrig')
|
|
476
|
+
|
|
477
|
+
def stop(self, channels): # 停止trig信号的运行
|
|
478
|
+
if self.run_mode is self.RunMode.INSIDE_MODE:
|
|
479
|
+
self.driver.set('ResetTrig')
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
trig = Trig
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
if __name__ == '__main__':
|
|
486
|
+
from waveforms import *
|
|
487
|
+
|
|
488
|
+
sample_rate = 6e9
|
|
489
|
+
width = 20e-9
|
|
490
|
+
time_line = np.linspace(0, width*10, int(width * 10 * sample_rate))
|
|
491
|
+
waves = {
|
|
492
|
+
'poly': poly([1, -1 / 2, 1 / 6, -1 / 12]),
|
|
493
|
+
'cos': cos(2 * pi * 5.2e9),
|
|
494
|
+
'sin': sin(2 * pi * 5.2e9),
|
|
495
|
+
'gaussian': gaussian(width) >> (width * 2),
|
|
496
|
+
'sinc': sinc(6e8),
|
|
497
|
+
'square': square(width) >> (width * 2),
|
|
498
|
+
'cosPulse': cosPulse(width) >> (width * 2),
|
|
499
|
+
'chirp_linear': chirp(1e9, 1.5e9, width * 10, type='linear'),
|
|
500
|
+
'chirp_exponential': chirp(1e9, 1.5e9, width * 10, type='exponential'),
|
|
501
|
+
'chirp_hyperbolic': chirp(1e9, 1.5e9, width * 10, type='hyperbolic'),
|
|
502
|
+
'cos*gaussian': cos(2 * pi * 5.2e9) * gaussian(width) >> (width * 2),
|
|
503
|
+
'cos*cosPulse': cos(2 * pi * 5.2e9) * cosPulse(width) >> (width * 2),
|
|
504
|
+
'gaussian_with_window': (gaussian(10) >> width * 2) + square(width, edge=5, type='linear') * cos(
|
|
505
|
+
2 * pi * 5.2e9),
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
ip = '192.168.1.141'
|
|
509
|
+
trig = Trig()
|
|
510
|
+
adc = ADC()
|
|
511
|
+
dac = DAC()
|
|
512
|
+
|
|
513
|
+
trig.connect(ip, {'RefClock': 'in'})
|
|
514
|
+
adc.connect(ip)
|
|
515
|
+
dac.connect(ip)
|
|
516
|
+
adc.initADC()
|
|
517
|
+
dac.initDAC()
|
|
518
|
+
trig.initTrig()
|
|
519
|
+
|
|
520
|
+
dac.write_wave([MIX_BIT_WIDTH*waves['cos*gaussian'](time_line), MIX_BIT_WIDTH*waves['chirp_linear'](time_line)], 1)
|
|
521
|
+
dac.setTriggerDelays([100e-9, 200e-9], 1)
|
|
522
|
+
dac.setCount(1024)
|
|
523
|
+
dac.start([1])
|
|
524
|
+
|
|
525
|
+
adc.setCount(1024)
|
|
526
|
+
adc.write_mixerTable(np.ones((1, 16384, 1, 2)), 1)
|
|
527
|
+
adc.setTriggerDelays([0], 1)
|
|
528
|
+
adc.start([1])
|
|
529
|
+
|
|
530
|
+
trig.setIntervalTime(200e-6)
|
|
531
|
+
trig.setCount(1024)
|
|
532
|
+
trig.start([])
|
|
533
|
+
|
|
534
|
+
data = adc.collectWaveData(1)
|