nsqdriver 0.12.16__cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.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.

Files changed (41) hide show
  1. nsqdriver/NS_CST.py +260 -0
  2. nsqdriver/NS_DDS_v3.py +591 -0
  3. nsqdriver/NS_DDS_v4.py +778 -0
  4. nsqdriver/NS_MCI.py +594 -0
  5. nsqdriver/NS_QSYNC.py +780 -0
  6. nsqdriver/__init__.py +10 -0
  7. nsqdriver/common.py +20 -0
  8. nsqdriver/compiler/__init__.py +0 -0
  9. nsqdriver/compiler/assembler.cpython-313-x86_64-linux-gnu.so +0 -0
  10. nsqdriver/compiler/ns_wave.cpython-313-x86_64-linux-gnu.so +0 -0
  11. nsqdriver/compiler/ns_wave.pyi +151 -0
  12. nsqdriver/compiler/py_wave_asm.cpython-313-x86_64-linux-gnu.so +0 -0
  13. nsqdriver/compiler/py_wave_asm.pyi +29 -0
  14. nsqdriver/nswave/__init__.py +9 -0
  15. nsqdriver/nswave/_asm.pyi +97 -0
  16. nsqdriver/nswave/_checkers.cpython-313-x86_64-linux-gnu.so +0 -0
  17. nsqdriver/nswave/_checkers.pyi +47 -0
  18. nsqdriver/nswave/_errors.cpython-313-x86_64-linux-gnu.so +0 -0
  19. nsqdriver/nswave/_errors.pyi +24 -0
  20. nsqdriver/nswave/_functions.cpython-313-x86_64-linux-gnu.so +0 -0
  21. nsqdriver/nswave/_functions.pyi +34 -0
  22. nsqdriver/nswave/_ir.cpython-313-x86_64-linux-gnu.so +0 -0
  23. nsqdriver/nswave/_ir.pyi +283 -0
  24. nsqdriver/nswave/_ir_pass.cpython-313-x86_64-linux-gnu.so +0 -0
  25. nsqdriver/nswave/_ir_pass.pyi +7 -0
  26. nsqdriver/nswave/_optimizations.cpython-313-x86_64-linux-gnu.so +0 -0
  27. nsqdriver/nswave/_optimizations.pyi +16 -0
  28. nsqdriver/nswave/_rules.cpython-313-x86_64-linux-gnu.so +0 -0
  29. nsqdriver/nswave/_rules.pyi +56 -0
  30. nsqdriver/nswave/_simulator.cpython-313-x86_64-linux-gnu.so +0 -0
  31. nsqdriver/nswave/_translate.cpython-313-x86_64-linux-gnu.so +0 -0
  32. nsqdriver/nswave/_translate.pyi +12 -0
  33. nsqdriver/nswave/kernel.cpython-313-x86_64-linux-gnu.so +0 -0
  34. nsqdriver/nswave/kernel.pyi +57 -0
  35. nsqdriver/wrapper/AWG_ADC.py +534 -0
  36. nsqdriver/wrapper/ND_NSMCI.py +245 -0
  37. nsqdriver/wrapper/__init__.py +0 -0
  38. nsqdriver-0.12.16.dist-info/METADATA +117 -0
  39. nsqdriver-0.12.16.dist-info/RECORD +41 -0
  40. nsqdriver-0.12.16.dist-info/WHEEL +6 -0
  41. nsqdriver-0.12.16.dist-info/top_level.txt +1 -0
nsqdriver/NS_DDS_v4.py ADDED
@@ -0,0 +1,778 @@
1
+ import copy
2
+ import time
3
+ from enum import Enum
4
+ from math import ceil
5
+ from collections import namedtuple
6
+ from waveforms import Waveform, wave_eval, WaveVStack
7
+ from waveforms.waveform import _zero
8
+ # from waveforms.math.signal import getFTMatrix, shift
9
+ import nsqdriver.nswave as nw
10
+
11
+ import numpy as np
12
+
13
+ try:
14
+ import waveforms
15
+
16
+ HAS_WAVEFORMS = True
17
+ except ImportError as e:
18
+ HAS_WAVEFORMS = False
19
+
20
+ try:
21
+ from .common import BaseDriver, Quantity, get_coef
22
+ except ImportError as e:
23
+
24
+ class BaseDriver:
25
+
26
+ def __init__(self, addr, timeout, **kw):
27
+ self.addr = addr
28
+ self.timeout = timeout
29
+
30
+
31
+ class Quantity(object):
32
+
33
+ def __init__(self, name: str, value=None, ch: int = 1, unit: str = ''):
34
+ self.name = name
35
+ self.default = dict(value=value, ch=ch, unit=unit)
36
+
37
+ # def get_coef(*args):
38
+ # return '', '', '', ''
39
+
40
+ DEBUG_PRINT = False
41
+
42
+
43
+ def get_coef(coef_info, sampleRate):
44
+ start, stop = coef_info['start'], coef_info['stop']
45
+ numberOfPoints = int(
46
+ (stop - start) * sampleRate)
47
+ if numberOfPoints % 64 != 0:
48
+ numberOfPoints = numberOfPoints + 64 - numberOfPoints % 64
49
+ t = np.arange(numberOfPoints) / sampleRate + start
50
+
51
+ fList = []
52
+ wList = []
53
+ phases = []
54
+
55
+ for kw in coef_info['wList']:
56
+ Delta, t0, weight, w, phase = kw['Delta'], kw['t0'], kw['weight'], kw['w'], kw['phase']
57
+ fList.append(Delta)
58
+
59
+ if w is not None:
60
+ w = np.zeros(numberOfPoints, dtype=complex)
61
+ w[:len(w)] = w
62
+ w = shift(w, t0 - start)
63
+ phases.append(np.mod(phase + 2 * np.pi * Delta * start, 2 * np.pi))
64
+ else:
65
+ weight = weight
66
+ if isinstance(weight, np.ndarray):
67
+ pass
68
+ else:
69
+ if isinstance(weight, str):
70
+ fun = wave_eval(weight) >> t0
71
+ elif isinstance(weight, Waveform):
72
+ fun = weight >> t0
73
+ else:
74
+ raise TypeError(f'Unsupported type {weight}')
75
+ weight = fun(t)
76
+ phase += 2 * np.pi * Delta * start
77
+ w = getFTMatrix([Delta],
78
+ numberOfPoints,
79
+ phaseList=[phase],
80
+ weight=weight,
81
+ sampleRate=sampleRate)[:, 0]
82
+ phases.append(np.mod(phase, 2 * np.pi))
83
+ wList.append(w)
84
+ return np.asarray(wList), fList, numberOfPoints, phases, round((stop - t0) * sampleRate), t
85
+
86
+
87
+ def get_demod_envelope(coef_info, demod_map, freq_map, sampleRate):
88
+ start, stop = coef_info['start'], coef_info['stop']
89
+ # t0 = coef_info['wList']['t0']
90
+ # numberOfPoints = int(
91
+ # (stop - start) * sampleRate)
92
+ # if numberOfPoints % 64 != 0:
93
+ # numberOfPoints = numberOfPoints + 64 - numberOfPoints % 64
94
+ # t = np.arange(numberOfPoints) / sampleRate
95
+ demod_width = 2.048e-6
96
+ t_p = int(demod_width * sampleRate)
97
+ t = np.linspace(0, demod_width, round(demod_width*sampleRate), endpoint=False)
98
+ demod_map_list = demod_map
99
+ weight_sum = np.zeros((len(freq_map), t_p))
100
+
101
+ for idx, weight in enumerate(demod_map_list):
102
+ if isinstance(weight, np.ndarray):
103
+ weight_sum[idx] = weight
104
+ else:
105
+ if isinstance(weight, str):
106
+ fun = wave_eval(weight)
107
+ elif isinstance(weight, Waveform):
108
+ fun = weight
109
+ else:
110
+ raise TypeError(f'Unsupported type {weight}')
111
+ weight_sum[idx] = fun(t)
112
+ print(f'{freq_map=}, {len(freq_map)=}')
113
+ combined_wave = []
114
+ for idx, freq in enumerate(freq_map):
115
+ wave = (np.exp(2 * np.pi * freq * t * 1j)).reshape((1, -1))
116
+ print(f"wave {wave} {weight_sum[idx, :]}")
117
+ wave = weight_sum[idx, :] * wave
118
+ # plt.figure()
119
+ # plt.plot(weight_sum[idx, :])
120
+ # plt.plot(wave.T)
121
+ # plt.show()
122
+ combined_wave.append(wave)
123
+ combined_wave = np.concatenate(combined_wave, axis=0)
124
+ return weight_sum, combined_wave
125
+
126
+
127
+ @nw.kernel
128
+ def program_cap(param: nw.Var, indelay: nw.Var):
129
+
130
+ nw.wait_for_trigger()
131
+ i: nw.Var
132
+ # param: [[100e-9, 1e-6], [200e-9, 1e-6]]
133
+ nw.wait(indelay)
134
+ for i in param:
135
+ nw.wait(i[0])
136
+ nw.capture(i[1], 0, i[1])
137
+
138
+
139
+ @nw.kernel
140
+ def program_da(p: nw.Var):
141
+ i: nw.Var
142
+ e: nw.Var
143
+ nw.init_frame(0, 0)
144
+ nw.wait_for_trigger()
145
+ # nw.reset_frame()
146
+ e = nw.ins_envelope(p[0][1])
147
+ for i in p:
148
+ nw.wait(i[0])
149
+ # e = nw.ins_envelope(i[1])
150
+ nw.play_wave(e, 1, 0, 0)
151
+
152
+
153
+ ProbeSegment = namedtuple('ProbeSegment', ['start', 'stop', 'freq', 'demod', 'idx'])
154
+
155
+ CaptureCmd = namedtuple('CaptureCmd', [
156
+ 'start', 'ad_duration', 'delay', 'da_duration', 'freqs', 'delays', 'demod_wave_list', 'idx_list'
157
+ ])
158
+
159
+
160
+ class DemodulateMode(str, Enum):
161
+ MORE_QUBIT = 'more_qubit'
162
+ COMPLEX_SEQ = 'complex_seq'
163
+
164
+
165
+ class Driver(BaseDriver):
166
+ CHs = list(range(1, 25))
167
+ segment = ('ns', '111|112|113|114|115')
168
+ res_map = []
169
+
170
+ quants = [
171
+ Quantity('ReInit', value={}, ch=1), # set, 设备重新初始化
172
+ Quantity('Instruction', value=None, ch=1), # set 参数化波形指令队列配置
173
+ # 采集运行参数
174
+ Quantity('Shot', value=1024, ch=1), # set,运行次数
175
+ Quantity('PointNumber', value=16384, unit='point'), # set/get,AD采样点数
176
+ Quantity('TriggerDelay', value=0, ch=1, unit='s'), # set/get,AD采样延时
177
+ Quantity('FrequencyList', value=[], ch=1,
178
+ unit='Hz'), # set/get,解调频率列表,list,单位Hz
179
+ Quantity('PhaseList', value=[], ch=1,
180
+ unit='Hz'), # set/get,解调频率列表,list,单位Hz
181
+ Quantity('Coefficient', value=None, ch=1),
182
+ Quantity('DemodulationParam', value=None, ch=1),
183
+ Quantity('CaptureMode'),
184
+ Quantity('StartCapture'), # set,开启采集(执行前复位)
185
+ Quantity('TraceIQ', ch=1), # get,获取原始时域数据
186
+ # 返回:array(shot, point)
187
+ Quantity('IQ', ch=1), # get,获取解调后数据,默认复数返回
188
+ # 系统参数,宏定义修改,open时下发
189
+ # 复数返回:array(shot,frequency)
190
+ # 实数返回:array(IQ,shot,frequency)
191
+
192
+ # 任意波形发生器
193
+ Quantity('Waveform', value=np.array([]), ch=1), # set/get,下发原始波形数据
194
+ Quantity('Delay', value=0, ch=1), # set/get,播放延时
195
+ Quantity('KeepAmp', value=0
196
+ ), # set, 电平是否维持在波形最后一个值, 0:波形播放完成后归0,1:保持波形最后一个值,2:保持波形第一个值
197
+ Quantity('Biasing', value=0, ch=1), # set, 播放延迟
198
+ Quantity('LinSpace', value=[0, 30e-6, 1000],
199
+ ch=1), # set/get, np.linspace函数,用于生成timeline
200
+ Quantity('Output', value=True, ch=1), # set/get,播放通道开关设置
201
+ Quantity('GenWave', value=None,
202
+ ch=1), # set/get, 设备接收waveform对象,根据waveform对象直接生成波形
203
+ # set/get, 设备接收IQ分离的waveform对象列表,根据waveform对象列表直接生成波形
204
+ Quantity('GenWaveIQ', value=None, ch=1),
205
+ Quantity('MultiGenWave', value={1: np.ndarray([])}), # 多通道波形同时下发
206
+ Quantity('EnableWaveCache', value=False), # 是否开启waveform缓存
207
+ Quantity('PushWaveCache'), # 使waveform缓存中的波形数据生效
208
+ # 混频相关配置
209
+ Quantity('EnableDAMixer', value=False, ch=1), # DA通道混频模式开关
210
+ Quantity('MixingWave', ), # 修改完混频相关参数后,运行混频器
211
+ Quantity('DAIQRate', value=1e9, ch=1), # 基带信号采样率
212
+ Quantity('DALOFreq', value=100e6, ch=1), # 中频信号频率
213
+ Quantity('DALOPhase', value=0, ch=1), # 基带信号相位,弧度制
214
+ Quantity('DASideband', value='lower', ch=1), # 混频后取的边带
215
+ Quantity('DAWindow', value=None, ch=1),
216
+ # 基带信号升采样率时所使用的窗函数,默认不使用任何窗,
217
+ # 可选:None、boxcar、triang、blackman、hamming、hann、bartlett、flattop、parzen、bohman、blackmanharris、nuttall、
218
+ # barthann、cosine、exponential、tukey、taylor
219
+
220
+ # 内触发
221
+ Quantity('GenerateTrig', value=1e7,
222
+ unit='ns'), # set/get,触发周期单位ns,触发数量=shot
223
+ Quantity('UpdateFirmware', value='', ch=1), # qsync固件更新
224
+ Quantity('PipInstall'), # pip install in instance
225
+ Quantity('Timeout'),
226
+ ]
227
+
228
+ def __init__(self, addr: str = '', timeout: float = 20.0, **kw):
229
+ super().__init__(addr, timeout=timeout, **kw)
230
+ self.handle = None
231
+ self.model = 'NS_MCI' # 默认为设备名字
232
+ self.srate = 8e9
233
+ self.ad_srate = 4e9
234
+ self.addr = addr
235
+ self.timeout = timeout
236
+ self.chs = set() # 记录配置过的ch通道
237
+ self.IQ_cache = {}
238
+ self.coef_cache = {}
239
+ self.res_maps = {}
240
+ self.demod_maps = {}
241
+ self.probe_da_wave = {}
242
+ self.programout_para = {} # {ch : para}
243
+ self.programin_para = {}
244
+ self.programin_para_indelay = {i: 136e-9 for i in range(1, 13)}
245
+ # self.probe_delay = 32e-9
246
+ self.probe_delay = 0
247
+ self.capture_cmds: "dict[int, list[CaptureCmd]]" = {}
248
+ self.capture_cali_param: "dict[int, np.ndarray]" = {}
249
+ self.capture_points: "dict[int, np.ndarray]" = {}
250
+ self.demodulate_mode = DemodulateMode.MORE_QUBIT
251
+ self.demode_calculus: "dict[int, np.ndarray]" = {}
252
+
253
+ def open(self, **kw):
254
+ """
255
+ 输入IP打开设备,配置默认超时时间为5秒
256
+ 打开设备时配置RFSoC采样时钟,采样时钟以参数定义
257
+ """
258
+ from nsqdriver import MCIDriver
259
+
260
+ DArate = 8e9
261
+ ADrate = 4e9
262
+ sysparam = {
263
+ "MixMode": 2,
264
+ "RefClock": "out",
265
+ "DArate": DArate,
266
+ "ADrate": ADrate,
267
+ "CaptureMode": 0,
268
+ "INMixMode": 2, # 4~6 GHz 取 1, 6 ~ 8 GHz 取 2
269
+ }
270
+ sysparam.update(kw.get('system_parameter', {}))
271
+ print(f"{self.timeout=}")
272
+ device = MCIDriver(self.addr, self.timeout)
273
+ device.open(system_parameter=sysparam)
274
+ self.handle = device
275
+
276
+ def granularity4ns(self, delay):
277
+ # points_4ns = 16 # self.ad_srate*4e-6
278
+ return delay // 4 * 4
279
+
280
+ @staticmethod
281
+ def _delay2_phase(delay, freq):
282
+ return 2 * np.pi * freq * (delay * 1e-9)
283
+
284
+ def in_sequence_in_time(self, coef_info: dict) -> list[CaptureCmd]:
285
+ """
286
+ 合并重叠项,取并集,记录合并延迟时间,合并频点,合并包络
287
+ """
288
+
289
+ w_list = coef_info.get('wList', [])
290
+ time_segments: "list[ProbeSegment]" = []
291
+
292
+ for idx, wave in enumerate(w_list):
293
+ t0 = int(round(wave['t0'] * 1e9))
294
+ weight_expr = wave['weight']
295
+
296
+ # 假设 weight 表达式格式为 "square(X) >> Y",我们提取实际时间宽度
297
+ # duration = float(weight_expr.split('>>')[1].strip())
298
+ _start, _stop, _ = wave_eval(weight_expr).bounds
299
+ _start, _stop = int(round(_start * 1e9)), int(round(_stop * 1e9))
300
+
301
+ # 将区间加入列表
302
+ seg = ProbeSegment(t0 + _start, t0 + _stop, wave['Delta'], weight_expr, idx)
303
+ time_segments.append(seg)
304
+
305
+ # 按起始时间排序
306
+ time_segments.sort()
307
+
308
+ # 结果存储
309
+ non_overlapping_segments: list[CaptureCmd] = []
310
+ current_start, current_end = time_segments[0].start, time_segments[0].stop
311
+ current_cmd = CaptureCmd(0, 0, 0, 0, [time_segments[0].freq], [0.], [time_segments[0].demod],
312
+ [time_segments[0].idx])
313
+ pointer = 0
314
+ for seg in time_segments[1:]:
315
+ if seg.start > current_end:
316
+ # 如果不重叠,保存当前段并移动到下一段
317
+ if pointer == 0:
318
+ current_cmd = current_cmd._replace(start=current_start)
319
+ else:
320
+ current_cmd = current_cmd._replace(start=current_start - self.probe_delay)
321
+ current_cmd = current_cmd._replace(ad_duration=current_end - current_start)
322
+ current_cmd = current_cmd._replace(delay=self.probe_delay)
323
+ current_cmd = current_cmd._replace(da_duration=current_end - current_start)
324
+ non_overlapping_segments.append(current_cmd)
325
+
326
+ current_cmd = CaptureCmd(0, 0, 0, 0, [seg.freq], [0.], [seg.demod], [seg.idx])
327
+ pointer = current_end
328
+ current_start, current_end = seg.start, seg.stop
329
+ else:
330
+ # 如果有重叠,扩展当前段
331
+ current_end = max(current_end, seg.stop)
332
+ current_cmd.idx_list.append(seg.idx)
333
+ current_cmd.freqs.append(seg.freq)
334
+ current_cmd.demod_wave_list.append(seg.demod)
335
+ # 由delay换算解缠绕相位
336
+ current_cmd.delays.append(seg.start - current_start)
337
+ print(f'{current_cmd=}')
338
+ else:
339
+ # 添加最后一个段
340
+ current_cmd = current_cmd._replace(start=current_start - self.probe_delay)
341
+ current_cmd = current_cmd._replace(ad_duration=current_end - current_start)
342
+ current_cmd = current_cmd._replace(delay=self.probe_delay)
343
+ current_cmd = current_cmd._replace(da_duration=current_end - current_start)
344
+ non_overlapping_segments.append(current_cmd)
345
+ return non_overlapping_segments
346
+
347
+ def generate_in_program(self, coef_info, ch):
348
+ freq_map = []
349
+ demod_wave_map = []
350
+ seq_param = []
351
+
352
+ self.capture_cmds[ch] = seq = self.in_sequence_in_time(coef_info) # 得到合并重叠后的list
353
+ print(f'{seq=}')
354
+ # for segment in seq:
355
+ # demod_wave_map.extend(segment.demod_wave_list)
356
+ # demod_wave_map = list(set(demod_wave_map))
357
+ # freq_map.extend(segment.freqs)
358
+ # freq_map = list(set(freq_map))
359
+
360
+ for segment in seq:
361
+ for n, f in enumerate(segment.freqs):
362
+ if f not in freq_map:
363
+ demod_wave_map.append(segment.demod_wave_list[n])
364
+ freq_map.append(f)
365
+
366
+ _t_end = 0
367
+ res_map = [[]] * len(coef_info['wList'])
368
+ phase_map = [0] * len(coef_info['wList'])
369
+ points_map = [0] * len(coef_info['wList'])
370
+ for cap_num, segment in enumerate(seq):
371
+ _align_start = self.granularity4ns(segment.start) # 向前取整
372
+ _start_diff = segment.start - _align_start
373
+ # _align_end = ceil((segment.start + segment.ad_duration) / 4) * 4 # 向上取整
374
+ _align_end = (segment.start + segment.ad_duration) // 4 * 4 # 向上取整
375
+ seq_param.append([
376
+ (_align_start - _t_end) * 1e-9,
377
+ (_align_end - _align_start) * 1e-9,
378
+ segment.delay * 1e-9,
379
+ (_align_end - _align_start) * 1e-9,
380
+ ])
381
+ print(f"{_align_start=} {_align_end=} {(_align_start - _t_end)} {_t_end=}")
382
+ _t_end = _align_end
383
+ for idx, delay, freq, demod_wave in zip(segment.idx_list, segment.delays, segment.freqs,
384
+ segment.demod_wave_list):
385
+ res_map[idx] = [freq_map.index(freq), cap_num]
386
+ # print("下面 + t0")
387
+ # phase_map[idx] = self._delay2_phase(delay + _start_diff, freq) # 向前取整的缩进加上起始时间的差值来计算相位
388
+ # phase_map[idx] = self._delay2_phase(_align_start + _start_diff, freq) # 向前取整的缩进加上起始时间的差值来计算相位
389
+ # phase_map[idx] = self._delay2_phase(0, freq) # 向前取整的缩进加上起始时间的差值来计算相位
390
+ points_map[idx] = (_align_end - _align_start) * 1e-9 * self.ad_srate
391
+ # points_map[idx] = segment.ad_duration * 1e-9 * self.ad_srate
392
+
393
+ ad_abs_end = 0
394
+ da_abs_end = 0
395
+ # 根据ad 的延迟重新下发da program
396
+ delta_t = self.programout_para[ch][0][0] - seq_param[0][0]
397
+ for n, i in enumerate(self.programout_para[ch]):
398
+ if n == 0:
399
+ continue
400
+ ad_abs_end += seq_param[n-1][0] + seq_param[n-1][1]
401
+ da_abs_end += self.programout_para[ch][n-1][0] + self.programout_para[ch][n-1][1].shape[0] / self.srate
402
+ da_next_start = ad_abs_end + seq_param[n][0] + delta_t
403
+ da_wait = da_next_start - da_abs_end
404
+ i[0] = da_wait
405
+ # kernel_da = program_da(self.programout_para[ch])
406
+ # self.handle.set("ProgramOUT", kernel_da, ch)
407
+ print(f"重下da 程序 {self.programout_para[ch]=}")
408
+
409
+ for idx, freq in zip(segment.idx_list, segment.freqs):
410
+ phase_map[idx] = self._delay2_phase(0 , freq)
411
+
412
+ self.res_maps[ch] = res_map
413
+ self.capture_cali_param[ch] = np.exp(-1j * np.array(phase_map)).reshape((-1, 1))
414
+ self.capture_points[ch] = np.array(points_map).reshape((-1, 1))
415
+ print(f"{seq_param=} para_angle {np.angle(self.capture_cali_param[ch], deg=True)} {self.capture_points}")
416
+ self.programin_para[ch] = seq_param
417
+ return program_cap(seq_param, self.programin_para_indelay[ch]), freq_map, demod_wave_map
418
+
419
+ def out_sequence_in_time(self, wave_list: list):
420
+ last_start = wave_list[0][0]
421
+ last_stop = wave_list[0][1]
422
+ temp_w = [wave_list[0][2]]
423
+ _res = []
424
+
425
+ for idx, (start, stop, seg) in enumerate(wave_list[1:]):
426
+ if start > last_stop:
427
+ _res.append([last_start, last_stop, np.hstack(temp_w)])
428
+ last_start = start
429
+ last_stop = stop
430
+ temp_w.clear()
431
+ temp_w.append(seg)
432
+ else:
433
+ last_stop = max(last_stop, stop)
434
+ temp_w.append(seg)
435
+ else:
436
+ _res.append([last_start, last_stop, np.hstack(temp_w)])
437
+ return _res
438
+
439
+ def gen_wave_frag(self, x, wave: "Waveform"):
440
+ range_list = np.searchsorted(x, wave.bounds)
441
+ # ret = np.zeros_like(x)
442
+ ret = []
443
+ start, stop = 0, 0
444
+ for i, stop in enumerate(range_list):
445
+ if start < stop and wave.seq[i] != _zero:
446
+ _w = copy.deepcopy(wave)
447
+ _w.start = start / self.srate
448
+ _w.stop = stop / self.srate
449
+ part = _w.sample(self.srate)
450
+ part = part if part is None else part[:(stop - start)]
451
+ ret.append((start, stop, part))
452
+ start = stop
453
+ else:
454
+ if not ret:
455
+ ret.append((0, 128, np.zeros((128,))))
456
+ return ret
457
+
458
+ def generate_out_program(self, _wave, ch):
459
+ align_points = 32 # 4ns*8e9
460
+ if isinstance(_wave, WaveVStack):
461
+ _wave = _wave.simplify()
462
+ if len(_wave.seq) == 1 and _wave.seq[0] == _zero:
463
+ wave_list = [(0, 128, np.zeros((128,)))]
464
+ else:
465
+ _wave.stop = _wave.bounds[-2]
466
+ wave_list = self.gen_wave_frag(
467
+ np.linspace(_wave.start, _wave.stop, int((_wave.stop - _wave.start) * self.srate)), _wave)
468
+ print(f'generate_out_program: {_wave.start=}, {_wave.stop=}, {len(wave_list)=}, {ch=}')
469
+ _t_end = 0
470
+ para = []
471
+ wave = self.out_sequence_in_time(wave_list) # 得到合并重叠后的list
472
+
473
+ for num, i in enumerate(wave):
474
+ wait = (i[0] - _t_end)
475
+ # if wait % 32 != 0:
476
+ # # 若wait 不是4ns整倍数,根据ad的逻辑会往后多财季4ns
477
+ align_wait = wait // align_points * align_points
478
+ zero_num = wait - align_wait
479
+ align_end = i[1] // align_points * align_points
480
+ align_wave = [i[2],]
481
+ para.append([align_wait / self.srate, np.hstack(align_wave)])
482
+ _t_end = align_end
483
+ print(f"out {para=}")
484
+ self.programout_para[ch] = para
485
+ # print(para[0][1].max())
486
+ # plt.plot(para[0][1])
487
+ # plt.show()
488
+ return program_da(para)
489
+
490
+ def get_coef_res(self, iq_res, ch):
491
+ res = []
492
+ print(f'{self.res_maps[ch]=}')
493
+ for (freq_num, cap_num) in self.res_maps[ch]:
494
+ res.append(iq_res[freq_num][cap_num::len(self.capture_cmds[ch])])
495
+ # 采样点归一化
496
+ res = np.array(res) / self.demode_calculus[ch]
497
+ # 校准相位
498
+ res *= self.capture_cali_param[ch]
499
+
500
+ return res
501
+
502
+ def close(self, **kw):
503
+ """
504
+ 关闭设备
505
+ """
506
+ if getattr(self, 'handle', None) is not None:
507
+ self.handle.close()
508
+ self.handle = None
509
+
510
+ def set(self, *args, **kwargs):
511
+ return self.handle.set(*args, **kwargs)
512
+
513
+ def get(self, *args, **kwargs):
514
+
515
+ return self.handle.get(*args, **kwargs)
516
+
517
+ # def generate_demo(self, co):
518
+ # _wave = wf.zero()
519
+ # min_t0 = 10
520
+ # for _w in co['wList']:
521
+ # t0 = _w['t0']
522
+ # min_t0 = min(min_t0, t0)
523
+ # _wave += (wf.wave_eval(_w['weight']) * wf.cos(2 * np.pi * _w['Delta'])) >> t0
524
+ # _wave /= 8
525
+ # # _wave = _wave << 50e-9
526
+ # _wave.start = 0
527
+ # _wave.stop = co['stop']
528
+ # bk = self.srate
529
+ # self.srate = self.ad_srate
530
+ # _, para = self.generate_out_program(co, 1)
531
+ # self.srate = bk
532
+ # demo = para[0][1]
533
+ # return demo
534
+
535
+ def write(self, name: str, value, **kw):
536
+ channel = kw.get('ch', 1)
537
+ print(f'NS_DDS_v3 write: {name=}, {channel=}')
538
+ if name in {'Coefficient'}:
539
+ print("Coefficient" * 3)
540
+ coef_info = value
541
+ self.chs.add(channel)
542
+ kernel, freq_map, demod_wave_map = self.generate_in_program(coef_info, channel)
543
+ self.handle.set("ProgramIN", kernel, channel)
544
+ demode_weight, demode_wave = get_demod_envelope(coef_info, demod_wave_map, freq_map, sampleRate=4e9)
545
+ self.demode_calculus[channel] = np.sum(demode_weight[0])
546
+ self.handle.set("DemodulationParam", demode_wave, channel)
547
+ # print(f"demode_wave {demode_wave}")
548
+ # plt.figure()
549
+ # plt.plot(demode_wave[0].real)
550
+ # plt.plot(demode_wave[0].imag)
551
+ # plt.show()
552
+ self.handle.set('TimeWidth', self.capture_points[channel].max()/self.ad_srate, channel)
553
+ # self.handle.set('TimeWidth', 87 / self.ad_srate, channel)
554
+ # self.handle.set("FreqList", freq_map, channel)
555
+ self.coef_cache.update({channel: coef_info})
556
+ elif name in {"TriggerDelay", "INDelay"}:
557
+ print("INDelay" * 3)
558
+ self.programin_para_indelay[channel] = value
559
+ # kernel = program_cap(self.programin_para[channel], self.programin_para_indelay[channel])
560
+ # self.handle.set("ProgramIN", kernel, channel)
561
+ elif name in {
562
+ 'CaptureMode', 'SystemSync', 'ResetTrig', 'TrigPeriod',
563
+ 'TrigFrom'
564
+ }:
565
+ pass
566
+ elif name in {
567
+ 'GenWave', 'Waveform'
568
+ } and isinstance(value, Waveform):
569
+ kernel_da = self.generate_out_program(value, channel)
570
+ # self.handle.set("ProgramOUT", kernel_da, channel)
571
+ elif name in {
572
+ 'StartCapture', 'Capture'
573
+ }:
574
+ for channel, param in self.programin_para.items():
575
+ kernel = program_cap(self.programin_para[channel], self.programin_para_indelay[channel])
576
+ self.handle.set("ProgramIN", kernel, channel)
577
+ for channel in self.programout_para:
578
+ kernel = program_da(self.programout_para[channel])
579
+ self.handle.set("ProgramOUT", kernel, channel)
580
+ print(f"{self.programin_para=} {self.programin_para_indelay=} {self.programout_para=}")
581
+ return self.handle.set(name, value)
582
+ else:
583
+ if name in {"Shot"}:
584
+ self.shots = value
585
+ return self.handle.set(name, value, channel)
586
+
587
+ def read(self, name: str, **kw):
588
+ channel = kw.get('ch', 1)
589
+ if name in {"IQ"}:
590
+ iq_res = self.handle.get(
591
+ "IQ", channel, round(self.shots * len(self.capture_cmds[channel]))
592
+ )
593
+ result = self.get_coef_res(iq_res, channel).T
594
+ if len(self.chs) != 0 and channel in self.chs:
595
+ self.chs.remove(channel)
596
+ # self.IQ_cache.update({channel: result})
597
+ if len(self.chs) == 0:
598
+ self.write("TerminateUpload", 1) # 实验的开始必须加此句话
599
+ elif name in {'TraceIQ'}:
600
+ print(f"{self.shots=} {len(self.capture_cmds[channel])=}")
601
+ result = self.handle.get(
602
+ "TraceIQ", channel, round(self.shots * len(self.capture_cmds[channel]))
603
+ )
604
+ else:
605
+ result = self.handle.get(name, channel)
606
+ return result
607
+
608
+
609
+ if __name__ == '__main__':
610
+ # 7.052186177715091e9 1.418e-6 7.062146892655367e9 1.416e-6 6.191950464396285e9 1.615e-6
611
+ # 6.188118811881188e9 1.616e-6
612
+ # 6.184291898577612e9 1.617e-6
613
+ # 6.180469715698393e9 1.618e-6
614
+ # 6.176652254478073e9 1.619e-6
615
+ co = {'start': 0.0, 'stop': 70.605e-06, 'wList': [
616
+ {'Delta': 6967500000.0, 'phase': -0.0, 'weight': 'square(0.8e-06)>>(4e-07)', 'window': (0, 1024), 'w': None,
617
+ 't0': 1.618e-6, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
618
+ # {'Delta': 4.176652254478073e9, 'phase': -0.0, 'weight': 'gaussian(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
619
+ # 't0': 1.618e-6, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
620
+ # {'Delta': 6.180469715698393e9, 'phase': -0.0, 'weight': 'gaussian(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
621
+ # 't0': 1.618e-6 * 20, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
622
+ # {'Delta': 4.176652254478073e9, 'phase': -0.0, 'weight': 'gaussian(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
623
+ # 't0': 1.618e-6 * 20, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
624
+ # {'Delta': 6.180469715698393e9, 'phase': -0.0, 'weight': 'gaussian(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
625
+ # 't0': 1.618e-6 * 40, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
626
+ # {'Delta': 6.176652254478073e9, 'phase': -0.0, 'weight': 'gaussian(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
627
+ # 't0': 1.618e-6 * 40, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
628
+ # {'Delta': 5.12311e9, 'phase': -0.0, 'weight': 'square(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
629
+ # 't0': 1/5.12311 * 1e-4 * 2, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
630
+ # {'Delta': 5.2231e9, 'phase': -0.0, 'weight': 'square(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
631
+ # 't0': 1/5.12311 * 1e-4 * 2, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
632
+ # {'Delta': 5.1e9, 'phase': -0.0, 'weight': 'square(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
633
+ # 't0': 6.401e-06, 'phi': 2.1739656328752264, 'threshold': 20.36802101135254},
634
+ # {'Delta': 5.2e9, 'phase': -0.0, 'weight': 'square(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
635
+ # 't0': 6.401e-06, 'phi': 1.851749364542847, 'threshold': 21.65827751159668},
636
+ # {'Delta': 1e9, 'phase': -0.0, 'weight': 'square(8e-07) >> 4e-07', 'window': (0, 1024), 'w': None,
637
+ # 't0': 5.5e-06, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
638
+ # {'Delta': 1.1e9, 'phase': -0.0, 'weight': 'square(8e-07) >> 4e-07', 'window': (0, 1024), 'w': None,
639
+ # 't0': 5.5e-06, 'phi': 2.1739656328752264, 'threshold': 20.36802101135254},
640
+ # {'Delta': 1.2e9, 'phase': -0.0, 'weight': 'square(8e-07) >> 4e-07', 'window': (0, 1024), 'w': None,
641
+ # 't0': 5.5e-06, 'phi': 1.851749364542847, 'threshold': 21.65827751159668},
642
+ # {'Delta': 1e9, 'phase': -0.0, 'weight': 'square(8e-07) >> 4e-07', 'window': (0, 1024), 'w': None,
643
+ # 't0': 7.805e-06, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
644
+ # {'Delta': 1e9, 'phase': -0.0, 'weight': 'square(8e-07) >> 4e-07', 'window': (0, 1024), 'w': None,
645
+ # 't0': 8.805e-06, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
646
+ # {'Delta': 1.1e9, 'phase': -0.0, 'weight': 'square(8e-07) >> 4e-07', 'window': (0, 1024), 'w': None,
647
+ # 't0': 9.005e-06, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926}
648
+ ]}
649
+ co = {'start': 5.760000000000001e-07, 'stop': 1.581e-06, 'wList': [{'Delta': 6967500000.0, 'phase': -0.0, 'weight': '(sin(3141592.6535897935)**3)*(square(1e-06)>>(5e-07))',
650
+ 'window': (0, 1024), 'w': None, 't0': 5.81e-07, 'phi': -0.16222877291938465, 'threshold': 0.4922424554824829}]}
651
+ co = {'start': 5.760000000000001e-07, 'stop': 9.310000000000001e-07, 'wList': [{'Delta': 6967500000.0, 'phase': -0.0, 'weight': '(sin(8975979.010256553)**3)*(square(3.5e-07)>>(1.75e-07))', 'window': (0, 1024), 'w': None, 't0': 5.81e-07,
652
+ 'phi': 2.4011441876721005, 'threshold': 3.5368497371673584}]}
653
+ co = {'start': 5.760000000000001e-07, 'stop': 9.310000000000001e-07, 'wList': [{'Delta': 6967500000.0, 'phase': -0.0, 'weight': '(sin(8975979.010256553)**3)*(square(3.5e-07)>>(1.74e-07))', 'window': (0, 1024), 'w': None, 't0': 5.81e-07,
654
+ 'phi': 2.4011441876721005, 'threshold': 3.5368497371673584}]}
655
+
656
+ import numpy as np
657
+ # from nsqdriver.NS_DDS_v3_2 import Driver, get_coef
658
+ from nsqdriver import QSYNCDriver
659
+ from nsqdriver.NS_MCI import SHARED_DEVICE_MEM
660
+ import matplotlib.pyplot as plt
661
+ import waveforms as wf
662
+
663
+ SHARED_DEVICE_MEM.clear_ip()
664
+ _d = Driver('192.168.0.229', 50)
665
+ _q = QSYNCDriver('192.168.0.229')
666
+ _q.open(system_parameter={'RefClock': 'in'})
667
+ _d.open(system_parameter={'MixMode': 2, 'CaptureMode': 0, "DArate": 8e9, "RefClock": "out"})
668
+ _q.sync_system()
669
+ time.sleep(2)
670
+ _wave = wf.zero()
671
+ min_t0 = 10
672
+ for _w in co['wList']:
673
+ t0 = _w['t0']
674
+ min_t0 = min(min_t0, t0)
675
+ _wave += (wf.wave_eval(_w['weight']) * wf.cos(2 * np.pi * _w['Delta'])) >> t0
676
+ _wave /= 8
677
+ # _wave = _wave << 50e-9
678
+ _wave.start = 0
679
+ _wave.stop = co['stop']
680
+
681
+ _wave(np.linspace(0, _wave.stop, int(_wave.stop * 8e9)), frag=True)
682
+
683
+ wave = _wave.sample(8e9)
684
+ # plt.figure()
685
+ # plt.plot(wave)
686
+ # plt.show()
687
+ ch = 1
688
+ _wave.start = 0
689
+ _wave.stop = co["stop"]
690
+ shots = 8192
691
+
692
+ _q.set('Shot', shots)
693
+ _d.write('Shot', shots)
694
+
695
+
696
+ # 测试解模数据
697
+
698
+ # _d.write("INDelay", 136e-9, ch=ch) # INDelay 要在 Coefficient前面
699
+ # _d.write("Coefficient", co, ch=ch)
700
+ # _d.write("GenWave", _wave, ch=ch)
701
+
702
+ # _d.set('StartCapture')
703
+ # _q.set('GenerateTrig', 90e-6)
704
+ # data = _d.read("IQ", ch=ch)
705
+ # print(f"angle= {np.angle(data.mean(axis=0), deg=True)}")
706
+ # print(f"abs= {np.abs(data.mean(axis=0))}")
707
+
708
+ # 测试原始数据
709
+ # 将采集间隔改大
710
+ _d.set('CaptureMode', 1)
711
+ _d.write("GenWave", _wave, ch=ch)
712
+ _d.write("Coefficient", co, ch=ch) # 获取原始数据也要下发,用于配置indelay
713
+ _d.write("INDelay", 136e-9, ch=ch) # INDelay 要在 Coefficient前面
714
+
715
+ _d.write('StartCapture', 1)
716
+ _q.set('GenerateTrig', 500e-6)
717
+ data = _d.read("TraceIQ", ch=ch)
718
+ data = data.reshape((shots, -1))
719
+ plt.figure()
720
+ plt.plot(data.mean(axis=0))
721
+ plt.show()
722
+
723
+ # 测试波形连续播放
724
+ # 修改波形频率,在示波器可见
725
+
726
+ # _q.set("Shot", 0xFFFFFFFF)
727
+ # _q.set("GenerateTrig", 500e-6)
728
+ # time.sleep(10)
729
+ # _q.set("ResetTrig")
730
+
731
+ # 带包络扫描S21
732
+ # freq_range = np.linspace(4.01e9, 6.01e9, 51)
733
+ # s21_res = []
734
+ # _d.write("INDelay", 136e-9, ch=ch) # INDelay 要在 Coefficient前面
735
+ # for f in freq_range:
736
+ # co = {'start': 0.0, 'stop': 70.605e-06, 'wList': [
737
+ # {'Delta': f, 'phase': -0.0, 'weight': 'square(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
738
+ # 't0': 1.618e-6, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
739
+ # {'Delta': 6.176652254478073e9, 'phase': -0.0, 'weight': 'gaussian(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
740
+ # 't0': 1.618e-6, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
741
+ # {'Delta': f, 'phase': -0.0, 'weight': 'square(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
742
+ # 't0': 1.618e-6 * 20, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
743
+ # {'Delta': 6.176652254478073e9, 'phase': -0.0, 'weight': 'gaussian(0.8e-06) >> 4e-07', 'window': (0, 1024), 'w': None,
744
+ # 't0': 1.618e-6 * 20, 'phi': 2.4311851282940524, 'threshold': 9.645718574523926},
745
+ # ]}
746
+ # _wave = wf.zero()
747
+ # for _w in co['wList']:
748
+ # t0 = _w['t0']
749
+ # min_t0 = min(min_t0, t0)
750
+ # _wave += (wf.wave_eval(_w['weight']) * wf.cos(2 * np.pi * _w['Delta'])) >> t0
751
+ # _wave /= 8
752
+ # # _wave = _wave << 50e-9
753
+ # _wave.start = 0
754
+ # _wave.stop = co['stop']
755
+ # # plt.figure()
756
+ # # plt.plot(_wave.sample(8e9))
757
+ # # plt.show()
758
+ # _d.write("Coefficient", co, ch=ch)
759
+ # _d.write("GenWave", _wave, ch=ch)
760
+
761
+ # _d.set('StartCapture')
762
+ # _q.set('GenerateTrig', 90e-6)
763
+ # data = _d.read("IQ", ch=ch)
764
+ # s21_res.append(data)
765
+ # # 取第一次采集的第一个频点画图
766
+ # cap1 = np.array(s21_res)
767
+ # cap1 = cap1[:, :, 0].mean(axis=1)
768
+ # cap1 = 20 * np.log10(np.abs(cap1))
769
+ # plt.figure()
770
+ # plt.plot(freq_range, cap1)
771
+ # plt.show()
772
+ # # 取第二次采集的第一个频点画图
773
+ # cap2 = np.array(s21_res)
774
+ # cap2 = cap2[:, :, 2].mean(axis=1)
775
+ # cap2 = 20 * np.log10(np.abs(cap2))
776
+ # plt.figure()
777
+ # plt.plot(freq_range, cap2)
778
+ # plt.show()