nsqdriver 0.2.6__py3-none-any.whl → 0.3.0__py3-none-any.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_MCI.py CHANGED
@@ -10,7 +10,23 @@ from functools import wraps
10
10
  import numpy as np
11
11
  import waveforms
12
12
 
13
- from .common import BaseDriver, Quantity, get_coef
13
+ try:
14
+ from .common import BaseDriver, Quantity, get_coef
15
+ except ImportError as e:
16
+ class BaseDriver:
17
+ def __init__(self, addr, timeout, **kw):
18
+ self.addr = addr
19
+ self.timeout = timeout
20
+
21
+
22
+ class Quantity(object):
23
+ def __init__(self, name: str, value=None, ch: int = 1, unit: str = ''):
24
+ self.name = name
25
+ self.default = dict(value=value, ch=ch, unit=unit)
26
+
27
+
28
+ def get_coef(*args):
29
+ return '', '', '', ''
14
30
 
15
31
  DEBUG_PRINT = False
16
32
 
nsqdriver/NS_QSYNC.py CHANGED
@@ -11,7 +11,26 @@ from multiprocessing import shared_memory
11
11
  from functools import lru_cache, wraps
12
12
  from typing import Union, TYPE_CHECKING, Tuple, Iterable
13
13
 
14
- from .common import BaseDriver, Quantity, QInteger
14
+ try:
15
+ from .common import BaseDriver, Quantity, QInteger
16
+ except ImportError as e:
17
+ class BaseDriver:
18
+ def __init__(self, addr, timeout, **kw):
19
+ self.addr = addr
20
+ self.timeout = timeout
21
+
22
+
23
+ class Quantity(object):
24
+ def __init__(self, name: str, value=None, ch: int = 1, unit: str = ''):
25
+ self.name = name
26
+ self.default = dict(value=value, ch=ch, unit=unit)
27
+
28
+
29
+ class QInteger:
30
+ def __init__(self, name, value=None, unit='', ch=None,
31
+ get_cmd='', set_cmd='', ):
32
+ self.name = name
33
+
15
34
 
16
35
  if TYPE_CHECKING:
17
36
  from backend.board_parser import MCIBoard
nsqdriver/__init__.py CHANGED
@@ -1,8 +1,9 @@
1
1
  from .NS_MCI import Driver as MCIDriver
2
2
  from .NS_QSYNC import Driver as QSYNCDriver
3
3
  from .NS_CST import Driver as CSTDriver
4
+ from .compiler.ns_wave import InsChannel
4
5
 
5
- version_pack = (0, 2, 6)
6
+ version_pack = (0, 3, 0)
6
7
 
7
8
  __version__ = '.'.join(str(_) for _ in version_pack)
8
- __all__ = ['MCIDriver', 'QSYNCDriver', '__version__']
9
+ __all__ = ['MCIDriver', 'QSYNCDriver', 'CSTDriver', 'InsChannel', '__version__']
File without changes
@@ -0,0 +1,483 @@
1
+ import copy
2
+ from typing import Union, List, Dict
3
+ from itertools import chain, repeat
4
+ from enum import IntEnum
5
+ from collections import namedtuple
6
+
7
+ import numpy as np
8
+ import waveforms as wf
9
+
10
+ from .py_wave_asm import *
11
+
12
+
13
+ class QInsPlaceholder(NSQCommand):
14
+ ...
15
+
16
+
17
+ class Wave(GenTagMixin):
18
+ Identity = namedtuple('Relation', ['frame', 'envelop'])
19
+
20
+ class Tag(IntEnum):
21
+ none = 0
22
+ frame = 1
23
+ envelope = 2
24
+ signal = 3
25
+
26
+ def __init__(self, ins_obj: "InstructionQ", ins_id: dict):
27
+ cls = self.__class__
28
+ self.instruction = ins_obj
29
+ self.id = cls.Identity(**ins_id)
30
+ if ins_id['frame'] != -1 and ins_id['envelop'] != -1:
31
+ self.wtag = cls.Tag.signal
32
+ elif ins_id['frame'] != -1:
33
+ self.wtag = cls.Tag.envelope
34
+ elif ins_id['envelop'] != -1:
35
+ self.wtag = cls.Tag.frame
36
+ else:
37
+ self.wtag = cls.Tag.none
38
+
39
+ def __repr__(self):
40
+ return f'<{self.__class__}::{self.id}::{self.wtag}>'
41
+
42
+
43
+ class Frame(Wave):
44
+ def __init__(self, ins_obj: "InstructionQ", ins_id: int, freq: float):
45
+ super().__init__(ins_obj, {'frame': ins_id, 'envelop': -1})
46
+ self.tag = self.generate_tag
47
+ self.freq = freq
48
+
49
+ @property
50
+ def freq(self):
51
+ return self._freq
52
+
53
+ @freq.setter
54
+ def freq(self, value):
55
+ self._freq = value
56
+ self._ins = QInsFrame(freq=value, tag=self.tag)
57
+
58
+ def __mul__(self, other: Wave):
59
+ if isinstance(other, Envelope) or isinstance(other, Signal):
60
+ if other.instruction is not self.instruction:
61
+ raise ValueError(f'隶属于的instruction不同,不能直接相乘')
62
+ res = Signal(self.instruction, {'frame': self.id.frame, 'envelop': other.id.envelop})
63
+ res.frame = self
64
+ res.envelope = other
65
+ return res
66
+ else:
67
+ raise ValueError(f'{self.__class__}不能与{other.__class__}做乘法运算')
68
+
69
+ def format(self):
70
+ return self._ins
71
+
72
+
73
+ class Envelope(Wave):
74
+ def __init__(self, ins_obj: "InstructionQ", ins_id: int, content):
75
+ super().__init__(ins_obj, {'frame': -1, 'envelop': ins_id})
76
+ self.tag = self.generate_tag
77
+ self.content = content
78
+
79
+ @property
80
+ def content(self):
81
+ return self._content
82
+
83
+ @content.setter
84
+ def content(self, value):
85
+ self._content = value
86
+ self._ins = QInsEnvelop(envelop=self.content, tag=self.tag)
87
+
88
+ def __mul__(self, other: Wave):
89
+ if isinstance(other, Frame) or isinstance(other, Signal):
90
+ if other.instruction is not self.instruction:
91
+ raise ValueError(f'They belong to different instructions and cannot be directly multiplied')
92
+ res = Signal(self.instruction, {'frame': other.id.frame, 'envelop': self.id.envelop})
93
+ res.frame = other
94
+ res.envelope = self
95
+ return res
96
+ else:
97
+ raise ValueError(f'{self.__class__}不能与{other.__class__}做乘法运算')
98
+
99
+ def format(self):
100
+ return self._ins
101
+
102
+
103
+ class Signal(Wave):
104
+ def __init__(self, ins_obj: "InstructionQ", ins_id: dict):
105
+ super().__init__(ins_obj, ins_id)
106
+ self.frame = None
107
+ self.envelope = None
108
+
109
+
110
+ class InstructionQ(GenTagMixin):
111
+ """!
112
+ 包含各种具体的指令
113
+ """
114
+
115
+ def __init__(self, freqs=None, envelopes=None):
116
+ """!
117
+
118
+ @param freqs:
119
+ @param envelopes:
120
+ """
121
+ if freqs is None:
122
+ freqs = []
123
+ if envelopes is None:
124
+ envelopes = []
125
+ self.i_set: "List[Union[NSQCommand, InstructionQ]]" = []
126
+ self.f_set: "Dict[int, Frame]" = {}
127
+ self.e_set: "Dict[int, Envelope]" = {}
128
+ self.symbol_set: Dict[str, int] = {}
129
+ self.symbol_idx = -1
130
+ self.is_first_trig = True
131
+ self.last_ins = None
132
+
133
+ for i, f in enumerate(freqs):
134
+ self.ins_frame(f)
135
+ for i, e in enumerate(envelopes):
136
+ self.ins_envelope(e)
137
+
138
+ def __enter__(self):
139
+ return self
140
+
141
+ def __exit__(self, exc_type, exc_val, exc_tb):
142
+ ...
143
+
144
+ def clear(self):
145
+ self.i_set.clear()
146
+ self.symbol_set: Dict[str, int] = {}
147
+ self.symbol_idx = -1
148
+ self.is_first_trig = True
149
+
150
+ @property
151
+ def length(self):
152
+ return len(self.i_set)
153
+
154
+ def ins_frame(self, freq, idx=None) -> Frame:
155
+ raise RuntimeError(f'Cannot create a new frame in the branch')
156
+
157
+ def ins_envelope(self, envelope: "Union[np.ndarray, wf.Waveform, str]", idx=None) -> Envelope:
158
+ raise RuntimeError(f'Cannot create a new envelope in the branch')
159
+
160
+ def evlp_gaussian(self, width) -> Envelope:
161
+ wave = wf.gaussian(width) >> (width/2)
162
+ wave.start = 0
163
+ wave.stop = width
164
+ return self.ins_envelope(wave)
165
+
166
+ def evlp_cospulse(self, width) -> Envelope:
167
+ wave = wf.cosPulse(width) >> (width / 2)
168
+ wave.start = 0
169
+ wave.stop = width
170
+ return self.ins_envelope(wave)
171
+
172
+ def evlp_square(self, width) -> Envelope:
173
+ wave = wf.square(width) >> (width / 2)
174
+ wave.start = 0
175
+ wave.stop = width
176
+ return self.ins_envelope(wave)
177
+
178
+ def _append_ins(self, cmd: "Union[NSQCommand, InstructionQ]"):
179
+ self.last_ins = cmd
180
+ self.i_set.append(cmd)
181
+
182
+ def _map_var(self, var):
183
+ if var in self.symbol_set:
184
+ return self.symbol_set[var]
185
+ self.symbol_idx += 1
186
+ if self.symbol_idx >= 16:
187
+ raise RuntimeError(f'Up to 16 variables can be configured')
188
+ self.symbol_set[var] = self.symbol_idx
189
+ return self.symbol_set[var]
190
+
191
+ def wait_for_trigger(self):
192
+ if not self.is_first_trig:
193
+ self.wait()
194
+ cmd = QInsWaitTrig(tag=self.generate_tag)
195
+ self._append_ins(cmd)
196
+ return cmd
197
+
198
+ def ins_variable(self, reg: str, value: int):
199
+ cmd = QInsMov(self._map_var(reg), value, type='=', tag=self.generate_tag)
200
+ self._append_ins(cmd)
201
+ return cmd
202
+
203
+ def ins_add(self, reg: str, value: int):
204
+ cmd = QInsMov(self._map_var(reg), value, type='+', tag=self.generate_tag)
205
+ self._append_ins(cmd)
206
+ return cmd
207
+
208
+ def ins_reset_frame(self, flag, frame=''):
209
+ cmd = QInsResetF(flag, frame, tag=self.generate_tag)
210
+ self._append_ins(cmd)
211
+ return cmd
212
+
213
+ def inc_phase(self, frame, phase):
214
+ cmd = QInsIncPhase(phase, frame.tag, tag=self.generate_tag)
215
+ self._append_ins(cmd)
216
+ return cmd
217
+
218
+ def play_wave(self, wave: Signal, amp=1, freq=0, phase=0):
219
+ if not isinstance(wave, Signal):
220
+ raise RuntimeError(f'The parameter wave should be Signal, not {type(wave)}')
221
+ cmd = QInsPlayWave(wave.frame.tag, wave.envelope.tag, amp, freq, phase, tag=self.generate_tag)
222
+ self._append_ins(cmd)
223
+ return cmd
224
+
225
+ def play_zero(self, width):
226
+ cmd = QInsPlayZero(width, tag=self.generate_tag)
227
+ self._append_ins(cmd)
228
+ return cmd
229
+
230
+ def wait(self):
231
+ cmd = QInsWait(tag=self.generate_tag)
232
+ self._append_ins(cmd)
233
+ return cmd
234
+
235
+ def end(self):
236
+ cmd = QInsEnd(tag=self.generate_tag)
237
+ self._append_ins(cmd)
238
+ return cmd
239
+
240
+ def capture(self, width, delay=0):
241
+ cmd = QInsCapture(width=width, probe_delay=delay, tag=self.generate_tag)
242
+ self._append_ins(cmd)
243
+ return cmd
244
+
245
+ def _compile(self) -> "List[NSQCommand]":
246
+ res = []
247
+ for ins in self.i_set:
248
+ if isinstance(ins, InstructionQ):
249
+ res.extend(ins._compile())
250
+ else:
251
+ res.append(copy.copy(ins))
252
+ return res
253
+
254
+ def compile(self) -> "List[NSQCommand]":
255
+ queue = []
256
+ for idx in sorted(self.f_set.keys()):
257
+ ins = self.f_set[idx]
258
+ queue.append(ins.format())
259
+ for idx in sorted(self.e_set.keys()):
260
+ ins = self.e_set[idx]
261
+ queue.append(ins.format())
262
+
263
+ queue.extend(self._compile())
264
+ # 向指令队列中添加End指令
265
+ if not isinstance(queue[-1], QInsEnd):
266
+ queue.append(self.end())
267
+
268
+ res = []
269
+ for idx, ins in enumerate(queue):
270
+ if isinstance(ins, QInsPlaceholder):
271
+ f_tag = ins.tag
272
+ t_tag = queue[idx+1].tag
273
+ for _ins in queue:
274
+ if getattr(_ins, 'target', '') == f_tag:
275
+ _ins.target = t_tag
276
+ continue
277
+ res.append(ins)
278
+ return res
279
+
280
+ def lookup(self):
281
+ import json
282
+ ins_list = [str(ins) for ins in self.compile()]
283
+ print(json.dumps(ins_list, indent=4))
284
+
285
+
286
+ class InsChannel(InstructionQ):
287
+ def __init__(self, freqs=None, envelopes=None):
288
+ super(InsChannel, self).__init__(freqs, envelopes)
289
+ self.if_stack: "List[InsIF]" = []
290
+ self.looping = False
291
+
292
+ def clear(self):
293
+ super().clear()
294
+ self.looping = False
295
+
296
+ def ins_frame(self, freq, idx=None) -> Frame:
297
+ if idx is None:
298
+ idx = sorted(self.f_set)[-1]+1 if len(self.f_set) != 0 else 0
299
+ if not isinstance(idx, int):
300
+ raise ValueError(f'frame的idx应为整数,而不是{type(idx)}')
301
+ frame = Frame(self, idx, freq)
302
+ self.f_set[idx] = frame
303
+ return frame
304
+
305
+ def ins_envelope(self, envelope: "Union[np.ndarray, wf.Waveform, str]", idx=None) -> Envelope:
306
+ if idx is None:
307
+ idx = sorted(self.e_set)[-1] + 1 if len(self.e_set) != 0 else 0
308
+ if not isinstance(idx, int):
309
+ raise ValueError(f'envelop的idx应为整数,而不是{type(idx)}')
310
+ obj = Envelope(self, idx, envelope)
311
+ self.e_set[idx] = obj
312
+ return obj
313
+
314
+ def ins_if(self, formula) -> "InsIF":
315
+ channel = self if self.__class__ is InsChannel else self.channel
316
+ if_ins = InsIF.from_channel(channel)
317
+ if_ins.formula = formula
318
+ self._append_ins(if_ins)
319
+ self.if_stack.append(if_ins)
320
+ return if_ins
321
+
322
+ def ins_else(self) -> "InsElse":
323
+ # if与else之间不能间隔其它指令
324
+ if not isinstance(self.last_ins, InsIF):
325
+ raise RuntimeError(f'The last call of ins_else must be ins_if, not {type(self.last_ins)}')
326
+ # 不能没有if直接调用else
327
+ if len(self.if_stack) == 0:
328
+ raise RuntimeError(f'Please call if before calling else')
329
+ channel = self if self.__class__ is InsChannel else self.channel
330
+ _if = self.if_stack.pop()
331
+ _else = InsElse.from_channel(channel)
332
+ _else._if = _if
333
+ _if.ins_else = _else
334
+ return _else
335
+
336
+ def ins_loop(self, times) -> "InsLoop":
337
+ if self.looping:
338
+ raise RuntimeError(f'The current object is already in the loop')
339
+ channel = self if self.__class__ is InsChannel else self.channel
340
+ loop_ins = InsLoop.from_channel(channel)
341
+ loop_ins.times = times
342
+ self._append_ins(loop_ins)
343
+ return loop_ins
344
+
345
+
346
+ class InsIF(InsChannel):
347
+ ch_judge_name = {f'FREQ_{i}': 1<<i for i in range(6)}
348
+
349
+ def __init__(self, freqs=None, envelopes=None):
350
+ """!
351
+
352
+ @param freqs:
353
+ @param envelopes:
354
+ """
355
+ super().__init__(freqs, envelopes)
356
+ self.channel: "InsChannel" = None
357
+ self.key_ins = None
358
+ self.ins_else = None
359
+
360
+ @classmethod
361
+ def from_channel(cls, channel):
362
+ self = cls()
363
+ self.channel = channel
364
+ return self
365
+
366
+ @property
367
+ def formula(self):
368
+ raise RuntimeError(f'{self.__class__.__name__}.formula is a static property')
369
+
370
+ @formula.setter
371
+ def formula(self, formula: str):
372
+ formula = formula.replace(' ', '')
373
+ ast = formula.split('==')
374
+ if len(ast) != 2:
375
+ raise RuntimeError(f'The format of formula should be [name] == [value]')
376
+ name, value = ast
377
+ if name in self.channel.symbol_set:
378
+ self.key_ins = QInsJumpWithReg(self.channel.symbol_set[name], int(value), None, tag=self.generate_tag)
379
+ elif name in self.ch_judge_name:
380
+ self.key_ins = QInsJumpWithJudge(int(value), self.ch_judge_name[name], None, tag=self.generate_tag)
381
+ else:
382
+ raise RuntimeError(f'The specified variable {name} does not exist')
383
+
384
+ def _compile(self) -> "List[NSQCommand]":
385
+ """!
386
+ 递归生成分支结构,支持结构嵌套
387
+ @return:
388
+ """
389
+ res = []
390
+ if_group = super()._compile()
391
+ else_group = self.ins_else._compile() if isinstance(self.ins_else, InsElse) else []
392
+ while len(else_group) < 3:
393
+ else_group.append(QInsWait(tag=self.generate_tag))
394
+ if_group.append(QInsPlaceholder(tag=self.generate_tag))
395
+ jump = QInsJump(None, tag=self.generate_tag)
396
+ self.key_ins.target = if_group[0].tag
397
+ jump.target = if_group[-1].tag
398
+
399
+ res.append(self.key_ins)
400
+ res.extend(else_group)
401
+ res.append(jump)
402
+ res.extend(if_group)
403
+ return res
404
+
405
+ def capture(self, width, delay=0):
406
+ raise RuntimeError(f'Capture is not allowed to call in a branch structure')
407
+
408
+
409
+ class InsElse(InsChannel):
410
+ def __init__(self, freqs=None, envelopes=None):
411
+ """!
412
+
413
+ @param freqs:
414
+ @param envelopes:
415
+ """
416
+ super().__init__(freqs, envelopes)
417
+ self.channel = None
418
+ self._if = None
419
+
420
+ @classmethod
421
+ def from_channel(cls, channel):
422
+ self = cls()
423
+ self.channel = channel
424
+ return self
425
+
426
+ def capture(self, width, delay=0):
427
+ raise RuntimeError(f'Capture is not allowed to call in a branch structure')
428
+
429
+
430
+ class InsLoop(InsChannel):
431
+ def __init__(self, freqs=None, envelopes=None):
432
+ """!
433
+
434
+ @param freqs:
435
+ @param envelopes:
436
+ """
437
+ super().__init__(freqs, envelopes)
438
+ self.channel: "InsChannel" = None
439
+ self.times = None
440
+ self.var = self.generate_tag
441
+
442
+ def __enter__(self):
443
+ self.channel.looping = True
444
+ return self
445
+
446
+ def __exit__(self, exc_type, exc_val, exc_tb):
447
+ self.looping = False
448
+
449
+ @classmethod
450
+ def from_channel(cls, channel):
451
+ self = cls()
452
+ self.channel = channel
453
+ return self
454
+
455
+ def capture(self, width, delay=0):
456
+ raise RuntimeError(f'Calling capture in a loop construct is not allowed')
457
+
458
+ def _compile(self) -> "List[NSQCommand]":
459
+ body = super()._compile()
460
+ res = []
461
+ set_cmd = QInsMov(self.channel._map_var(self.var), 0, type='=', tag=self.generate_tag)
462
+ body.append(QInsMov(self.channel._map_var(self.var), 1, type='+', tag=self.generate_tag))
463
+ placeholder = QInsPlaceholder(tag=self.generate_tag)
464
+ jump = [
465
+ QInsJumpWithReg(self.channel._map_var(self.var), self.times, placeholder.tag, tag=self.generate_tag),
466
+ QInsWait(tag=self.generate_tag),
467
+ QInsWait(tag=self.generate_tag),
468
+ QInsJump(body[0].tag, tag=self.generate_tag),
469
+ placeholder
470
+ ]
471
+ res.append(set_cmd)
472
+ res.extend(body)
473
+ res.extend(jump)
474
+ return res
475
+
476
+ # def _compile(self) -> "List[NSQCommand]":
477
+ # ins_list = super()._compile()
478
+ # res = []
479
+ # for ins in chain.from_iterable(repeat(ins_list, self.times)):
480
+ # _ins: "NSQCommand" = copy.copy(ins)
481
+ # _ins.tag = self.generate_tag
482
+ # res.append(_ins)
483
+ # return res