pulserdriver.cpp
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 //---------------------------------------------------------------------------
15 #include "pulserdriver.h"
16 #include "ui_pulserdriverform.h"
17 #include "ui_pulserdrivermoreform.h"
18 #include "pulserdriverconnector.h"
19 #include "interface.h"
20 #include "analyzer.h"
21 #include "xnodeconnector.h"
22 #include <QStatusBar>
23 
24 #include <gsl/gsl_sf.h>
25 #define bessel_i0 gsl_sf_bessel_I0
26 
27 #include <set>
28 
29 struct __PulseFunc {
30  const char *name;
31  FFT::twindowfunc fp;
32 };
33 const __PulseFunc cg_PulseFuncs[] = {
34 {"Rect. BW=0.89/T", &FFT::windowFuncRect}, {"Hanning BW=1.44/T", &FFT::windowFuncHanning},
35 {"Hamming BW=1.30/T", &FFT::windowFuncHamming}, {"Flat-Top BW=3.2/T", &FFT::windowFuncFlatTop},
36 {"Flat-Top BW=5.3/T", &FFT::windowFuncFlatTopLong}, {"Flat-Top BW=6.8/T", &FFT::windowFuncFlatTopLongLong},
37 {"Blackman BW=1.7/T", &FFT::windowFuncBlackman}, {"Blackman-Harris BW=1.9/T", &FFT::windowFuncBlackmanHarris},
38 {"Kaiser(3) BW=1.6/T", &FFT::windowFuncKaiser1}, {"Kaiser(7.2) BW=2.6/T", &FFT::windowFuncKaiser2},
39 {"Kaiser(15) BW=3.8/T", &FFT::windowFuncKaiser3}, {"Half-sin BW=1.2/T", &FFT::windowFuncHalfSin},
40 {"", 0}
41 };
42 #define PULSE_NO_HAMMING 2
43 #define PULSE_NO_FLATTOP_LONG_LONG 5
44 
45 XPulser::tpulsefunc
46 XPulser::pulseFunc(int no) const {
47  int idx = 0;
48  for(const __PulseFunc *f = cg_PulseFuncs; f->fp; ++f) {
49  if(idx == no)
50  return f->fp;
51  ++idx;
52  }
53  return &FFT::windowFuncRect;
54 }
55 int
56 XPulser::pulseFuncNo(const XString &str) const {
57  int idx = 0;
58  for(const __PulseFunc *f = cg_PulseFuncs; f->fp; ++f) {
59  if(f->name == str)
60  return idx;
61  ++idx;
62  }
63  return 0;
64 }
65 
66 #define NUM_PHASE_CYCLE_1 "1"
67 #define NUM_PHASE_CYCLE_2 "2"
68 #define NUM_PHASE_CYCLE_4 "4"
69 #define NUM_PHASE_CYCLE_8 "8"
70 #define NUM_PHASE_CYCLE_16 "16"
71 
72 #define COMB_MODE_OFF "Comb Off"
73 #define COMB_MODE_ON "Comb On"
74 #define COMB_MODE_P1_ALT "P1 ALT"
75 #define COMB_MODE_COMB_ALT "Comb ALT"
76 
77 #define RT_MODE_FIXREP "Fix Rep. Time"
78 #define RT_MODE_FIXREST "Fix Rest Time"
79 
80 XPulser::XPulser(const char *name, bool runtime,
81  Transaction &tr_meas, const shared_ptr<XMeasure> &meas) :
82  XPrimaryDriver(name, runtime, ref(tr_meas), meas),
83  m_output(create<XBoolNode>("Output", true)),
84  m_combMode(create<XComboNode>("CombMode", false, true)),
85  m_rtMode(create<XComboNode>("RTMode", false, true)),
86  m_rt(create<XDoubleNode>("RT", false, "%.7g")),
87  m_tau(create<XDoubleNode>("Tau", false, "%.7g")),
88  m_combPW(create<XDoubleNode>("CombPW", false)),
89  m_pw1(create<XDoubleNode>("PW1", false)),
90  m_pw2(create<XDoubleNode>("PW2", false)),
91  m_combNum(create<XUIntNode>("CombNum", false)),
92  m_combPT(create<XDoubleNode>("CombPT", false)),
93  m_combP1(create<XDoubleNode>("CombP1", false, "%.7g")),
94  m_combP1Alt(create<XDoubleNode>("CombP1Alt", false, "%.7g")),
95  m_aswSetup(create<XDoubleNode>("ASWSetup", false)),
96  m_aswHold(create<XDoubleNode>("ASWHold", false)),
97  m_altSep(create<XDoubleNode>("ALTSep", false)),
98  m_g2Setup(create<XDoubleNode>("Gate2Setup", false)),
99  m_echoNum(create<XUIntNode>("EchoNum", false)),
100  m_combOffRes(create<XDoubleNode>("CombOffRes", false)),
101  m_drivenEquilibrium(create<XBoolNode>("DrivenEquilibrium", false)),
102  m_numPhaseCycle(create<XComboNode>("NumPhaseCycle", false, true)),
103  m_p1Func(create<XComboNode>("P1Func", false, true)),
104  m_p2Func(create<XComboNode>("P2Func", false, true)),
105  m_combFunc(create<XComboNode>("CombFunc", false, true)),
106  m_p1Level(create<XDoubleNode>("P1Level", false)),
107  m_p2Level(create<XDoubleNode>("P2Level", false)),
108  m_combLevel(create<XDoubleNode>("CombLevel", false)),
109  m_masterLevel(create<XDoubleNode>("MasterLevel", false)),
110  m_qamOffset1(create<XDoubleNode>("QAMOffset1", false)),
111  m_qamOffset2(create<XDoubleNode>("QAMOffset2", false)),
112  m_qamLevel1(create<XDoubleNode>("QAMLevel1", false)),
113  m_qamLevel2(create<XDoubleNode>("QAMLevel2", false)),
114  m_qamDelay1(create<XDoubleNode>("QAMDelay1", false)),
115  m_qamDelay2(create<XDoubleNode>("QAMDelay2", false)),
116  m_difFreq(create<XDoubleNode>("DIFFreq", false)),
117  m_induceEmission(create<XBoolNode>("InduceEmission", false)),
118  m_induceEmissionPhase(create<XDoubleNode>("InduceEmissionPhase", false)),
119  m_qswDelay(create<XDoubleNode>("QSWDelay", false)),
120  m_qswWidth(create<XDoubleNode>("QSWWidth", false)),
121  m_qswSoftSWOff(create<XDoubleNode>("QSWSoftSWOff", false)),
122  m_invertPhase(create<XBoolNode>("InvertPhase", false)),
123  m_conserveStEPhase(create<XBoolNode>("ConserveStEPhase", false)),
124  m_qswPiPulseOnly(create<XBoolNode>("QSWPiPulseOnly", false)),
125  m_pulseAnalyzerMode(create<XBoolNode>("PulseAnalyzerMode", true)),
126  m_paPulseRept(create<XDoubleNode>("PAPulseRept", false)),
127  m_paPulseBW(create<XDoubleNode>("PAPulseBW", false)),
128  m_firstPhase(create<XUIntNode>("FirstPhase", true)),
129  m_moreConfigShow(create<XTouchableNode>("MoreConfigShow", true)),
130  m_form(new FrmPulser),
131  m_formMore(new FrmPulserMore(m_form.get())) {
132 
133  m_form->setWindowTitle(i18n("Pulser Control") + " - " + getLabel() );
134  m_formMore->setWindowTitle(i18n("Pulser Control More Config.") + " - " + getLabel() );
135  m_form->statusBar()->hide();
136  m_formMore->statusBar()->hide();
137 
138  m_form->m_btnMoreConfig->setIcon(QApplication::style()->standardIcon(QStyle::SP_FileDialogContentsView));
139 
140  Snapshot shot = iterate_commit([=](Transaction &tr){
141  const Snapshot &shot(tr);
142  {
143  for(unsigned int i = 0; i < NUM_DO_PORTS; i++) {
144  m_portSel[i] = create<XComboNode>(tr, formatString("PortSel%u", i).c_str(), false);
145  tr[ *m_portSel[i]].add({
146  "Gate", "PreGate", "Gate3", "Trig1", "Trig2", "ASW",
147  "QSW", "Pulse1", "Pulse2", "Comb", "CombFM",
148  "QPSK-A", "QPSK-B", "QPSK-NonInv", "QPSK-Inv",
149  "QPSK-PS-Gate", "PAnaGate"
150  });
151  // m_portSel[i]->setUIEnabled(false);
152  }
153  tr[ *portSel(0)] = PORTSEL_GATE;
154  tr[ *portSel(1)] = PORTSEL_PREGATE;
155  tr[ *portSel(3)] = PORTSEL_QPSK_A;
156  tr[ *portSel(4)] = PORTSEL_QPSK_B;
157  tr[ *portSel(6)] = PORTSEL_TRIG1;
158  tr[ *portSel(9)] = PORTSEL_ASW;
159  }
160 
161  tr[ *rtime()] = 100.0;
162  tr[ *tau()] = 100.0;
163  tr[ *combPW()] = 5.0;
164  tr[ *pw1()] = 5.0;
165  tr[ *pw2()] = 10.0;
166  tr[ *combNum()] = 1;
167  tr[ *combPT()] = 20.0;
168  tr[ *combP1()] = 0.2;
169  tr[ *combP1Alt()] = 50.0;
170  tr[ *aswSetup()] = 0.02;
171  tr[ *aswHold()] = 0.23;
172  tr[ *altSep()] = 0.25;
173  tr[ *g2Setup()] = 5.0;
174  tr[ *echoNum()] = 1;
175  tr[ *combOffRes()] = 0.0;
176  tr[ *drivenEquilibrium()] = false;
177  tr[ *numPhaseCycle()].add({NUM_PHASE_CYCLE_1, NUM_PHASE_CYCLE_2, NUM_PHASE_CYCLE_4, NUM_PHASE_CYCLE_8, NUM_PHASE_CYCLE_16});
178  tr[ *numPhaseCycle()] = NUM_PHASE_CYCLE_16;
179  tr[ *p1Level()] = -5.0;
180  tr[ *p2Level()] = -0.5;
181  tr[ *combLevel()] = -5.0;
182  tr[ *masterLevel()] = -10.0;
183  tr[ *qamLevel1()] = 1.0;
184  tr[ *qamLevel2()] = 1.0;
185  tr[ *qswDelay()] = 5.0;
186  tr[ *qswWidth()] = 10.0;
187  tr[ *qswSoftSWOff()] = 1.0;
188 
189  tr[ *combMode()].add({COMB_MODE_OFF ,COMB_MODE_ON, COMB_MODE_P1_ALT, COMB_MODE_COMB_ALT});
190  tr[ *combMode()] = N_COMB_MODE_OFF;
191  tr[ *rtMode()].add({RT_MODE_FIXREP, RT_MODE_FIXREST});
192  tr[ *rtMode()] = 1;
193 
194  for(const __PulseFunc *f = cg_PulseFuncs; f->fp; ++f) {
195  tr[ *p1Func()].add(f->name);
196  tr[ *p2Func()].add(f->name);
197  tr[ *combFunc()].add(f->name);
198  }
199  tr[ *p1Func()] = PULSE_NO_HAMMING; //Hamming
200  tr[ *p2Func()] = PULSE_NO_HAMMING; //Hamming
201  tr[ *combFunc()] = PULSE_NO_HAMMING; //Hamming
202 
203  tr[ *paPulseRept()] = 1; //ms
204  tr[ *paPulseBW()] = 1000.0; //kHz
205 
206  tr[ *firstPhase()] = 0;
207 
208  m_lsnOnMoreConfigShow = tr[ *m_moreConfigShow].onTouch().connectWeakly(
209  shared_from_this(), &XPulser::onMoreConfigShow,
210  XListener::FLAG_MAIN_THREAD_CALL | XListener::FLAG_AVOID_DUP);
211  });
212 
213  m_conUIs = {
214  xqcon_create<XQButtonConnector>(m_moreConfigShow, m_form->m_btnMoreConfig),
215  xqcon_create<XQToggleButtonConnector>(m_output, m_form->m_ckbOutput),
216  xqcon_create<XQComboBoxConnector>(m_combMode, m_form->m_cmbCombMode, Snapshot( *m_combMode)),
217  xqcon_create<XQComboBoxConnector>(m_rtMode, m_form->m_cmbRTMode, Snapshot( *m_rtMode)),
218  xqcon_create<XQLineEditConnector>(m_rt, m_form->m_edRT),
219  xqcon_create<XQLineEditConnector>(m_tau, m_form->m_edTau),
220  xqcon_create<XQLineEditConnector>(m_combPW, m_form->m_edCombPW),
221  xqcon_create<XQLineEditConnector>(m_pw1, m_form->m_edPW1),
222  xqcon_create<XQLineEditConnector>(m_pw2, m_form->m_edPW2),
223  xqcon_create<XQSpinBoxUnsignedConnector>(m_combNum, m_form->m_numCombNum),
224  xqcon_create<XQLineEditConnector>(m_combPT, m_form->m_edCombPT),
225  xqcon_create<XQLineEditConnector>(m_combP1, m_form->m_edCombP1),
226  xqcon_create<XQLineEditConnector>(m_combP1Alt, m_form->m_edCombP1Alt),
227  xqcon_create<XQLineEditConnector>(m_aswSetup, m_formMore->m_edASWSetup),
228  xqcon_create<XQLineEditConnector>(m_aswHold, m_formMore->m_edASWHold),
229  xqcon_create<XQLineEditConnector>(m_altSep, m_formMore->m_edALTSep),
230  xqcon_create<XQLineEditConnector>(m_g2Setup, m_formMore->m_edG2Setup),
231  xqcon_create<XQSpinBoxUnsignedConnector>(m_echoNum, m_formMore->m_numEcho),
232  xqcon_create<XQToggleButtonConnector>(m_drivenEquilibrium, m_formMore->m_ckbDrivenEquilibrium),
233  xqcon_create<XQComboBoxConnector>(m_numPhaseCycle, m_formMore->m_cmbPhaseCycle, Snapshot( *m_numPhaseCycle)),
234  xqcon_create<XQLineEditConnector>(m_combOffRes, m_form->m_edCombOffRes),
235  xqcon_create<XQToggleButtonConnector>(m_invertPhase, m_formMore->m_ckbInvertPhase),
236  xqcon_create<XQToggleButtonConnector>(m_conserveStEPhase, m_formMore->m_ckbStEPhase),
237  xqcon_create<XQComboBoxConnector>(m_p1Func, m_form->m_cmbP1Func, Snapshot( *m_p1Func)),
238  xqcon_create<XQComboBoxConnector>(m_p2Func, m_form->m_cmbP2Func, Snapshot( *m_p2Func)),
239  xqcon_create<XQComboBoxConnector>(m_combFunc, m_form->m_cmbCombFunc, Snapshot( *m_combFunc)),
240  xqcon_create<XQDoubleSpinBoxConnector>(m_p1Level, m_form->m_dblP1Level),
241  xqcon_create<XQDoubleSpinBoxConnector>(m_p2Level, m_form->m_dblP2Level),
242  xqcon_create<XQDoubleSpinBoxConnector>(m_combLevel, m_form->m_dblCombLevel),
243  xqcon_create<XQDoubleSpinBoxConnector>(m_masterLevel, m_form->m_dblMasterLevel, m_form->m_slMasterLevel),
244  xqcon_create<XQLineEditConnector>(m_qamOffset1, m_formMore->m_edQAMOffset1),
245  xqcon_create<XQLineEditConnector>(m_qamOffset2, m_formMore->m_edQAMOffset2),
246  xqcon_create<XQLineEditConnector>(m_qamLevel1, m_formMore->m_edQAMLevel1),
247  xqcon_create<XQLineEditConnector>(m_qamLevel2, m_formMore->m_edQAMLevel2),
248  xqcon_create<XQLineEditConnector>(m_qamDelay1, m_formMore->m_edQAMDelay1),
249  xqcon_create<XQLineEditConnector>(m_qamDelay2, m_formMore->m_edQAMDelay2),
250  xqcon_create<XQLineEditConnector>(m_difFreq, m_formMore->m_edDIFFreq),
251  xqcon_create<XQToggleButtonConnector>(m_induceEmission, m_formMore->m_ckbInduceEmission),
252  xqcon_create<XQDoubleSpinBoxConnector>(m_induceEmissionPhase, m_formMore->m_numInduceEmissionPhase),
253  xqcon_create<XQLineEditConnector>(m_qswDelay, m_formMore->m_edQSWDelay),
254  xqcon_create<XQLineEditConnector>(m_qswWidth, m_formMore->m_edQSWWidth),
255  xqcon_create<XQLineEditConnector>(m_qswSoftSWOff, m_formMore->m_edQSWSoftSWOff),
256  xqcon_create<XQToggleButtonConnector>(m_qswPiPulseOnly, m_formMore->m_ckbQSWPiPulseOnly),
257  xqcon_create<XQToggleButtonConnector>(m_pulseAnalyzerMode, m_formMore->m_ckbPulseAnalyzerMode),
258  xqcon_create<XQLineEditConnector>(m_paPulseRept, m_formMore->m_edPAPulseRept),
259  xqcon_create<XQLineEditConnector>(m_paPulseBW, m_formMore->m_edPAPulseBW),
260  xqcon_create<XQPulserDriverConnector>(
261  dynamic_pointer_cast<XPulser>(shared_from_this()), m_form->m_tblPulse, m_form->m_graph)
262  };
263  QComboBox*const combo[] = {
264  m_formMore->m_cmbPortSel0, m_formMore->m_cmbPortSel1, m_formMore->m_cmbPortSel2, m_formMore->m_cmbPortSel3,
265  m_formMore->m_cmbPortSel4, m_formMore->m_cmbPortSel5, m_formMore->m_cmbPortSel6, m_formMore->m_cmbPortSel7,
266  m_formMore->m_cmbPortSel8, m_formMore->m_cmbPortSel9, m_formMore->m_cmbPortSel10, m_formMore->m_cmbPortSel11,
267  m_formMore->m_cmbPortSel12, m_formMore->m_cmbPortSel13, m_formMore->m_cmbPortSel14, m_formMore->m_cmbPortSel15
268  };
269  for(unsigned int i = 0; i < NUM_DO_PORTS; i++) {
270  m_conUIs.push_back(xqcon_create<XQComboBoxConnector>(m_portSel[i], combo[i], shot));
271  }
272 
273  m_form->m_dblP1Level->setRange(-20.0, 3.0);
274  m_form->m_dblP1Level->setSingleStep(1.0);
275  m_form->m_dblP2Level->setRange(-20.0, 3.0);
276  m_form->m_dblP2Level->setSingleStep(1.0);
277  m_form->m_dblCombLevel->setRange(-20.0, 3.0);
278  m_form->m_dblCombLevel->setSingleStep(1.0);
279  m_form->m_dblMasterLevel->setRange(-30.0, 0.0);
280  m_form->m_dblMasterLevel->setSingleStep(1.0);
281 
282  changeUIStatus(true, false);
283 
284 }
285 
286 void
288  // impliment form->show() here
289  m_form->showNormal();
290  m_form->raise();
291 }
292 void
293 XPulser::onMoreConfigShow(const Snapshot &shot, XTouchableNode *) {
294  m_formMore->showNormal();
295  m_formMore->raise();
296 }
297 
298 void
300  changeUIStatus( !***pulseAnalyzerMode(), true);
301  pulseAnalyzerMode()->setUIEnabled(true);
302 
303  iterate_commit([=](Transaction &tr){
304  m_lsnOnPulseChanged = tr[ *combMode()].onValueChanged().connectWeakly(
305  shared_from_this(), &XPulser::onPulseChanged);
306  tr[ *rtime()].onValueChanged().connect(m_lsnOnPulseChanged);
307  tr[ *tau()].onValueChanged().connect(m_lsnOnPulseChanged);
308  tr[ *combPW()].onValueChanged().connect(m_lsnOnPulseChanged);
309  tr[ *pw1()].onValueChanged().connect(m_lsnOnPulseChanged);
310  tr[ *pw2()].onValueChanged().connect(m_lsnOnPulseChanged);
311  tr[ *combNum()].onValueChanged().connect(m_lsnOnPulseChanged);
312  tr[ *combPT()].onValueChanged().connect(m_lsnOnPulseChanged);
313  tr[ *combP1()].onValueChanged().connect(m_lsnOnPulseChanged);
314  tr[ *combP1Alt()].onValueChanged().connect(m_lsnOnPulseChanged);
315  tr[ *aswSetup()].onValueChanged().connect(m_lsnOnPulseChanged);
316  tr[ *aswHold()].onValueChanged().connect(m_lsnOnPulseChanged);
317  tr[ *altSep()].onValueChanged().connect(m_lsnOnPulseChanged);
318  tr[ *output()].onValueChanged().connect(m_lsnOnPulseChanged);
319  tr[ *g2Setup()].onValueChanged().connect(m_lsnOnPulseChanged);
320  tr[ *echoNum()].onValueChanged().connect(m_lsnOnPulseChanged);
321  tr[ *drivenEquilibrium()].onValueChanged().connect(m_lsnOnPulseChanged);
322  tr[ *numPhaseCycle()].onValueChanged().connect(m_lsnOnPulseChanged);
323  tr[ *combOffRes()].onValueChanged().connect(m_lsnOnPulseChanged);
324  tr[ *induceEmission()].onValueChanged().connect(m_lsnOnPulseChanged);
325  tr[ *induceEmissionPhase()].onValueChanged().connect(m_lsnOnPulseChanged);
326  tr[ *qswDelay()].onValueChanged().connect(m_lsnOnPulseChanged);
327  tr[ *qswWidth()].onValueChanged().connect(m_lsnOnPulseChanged);
328  tr[ *qswSoftSWOff()].onValueChanged().connect(m_lsnOnPulseChanged);
329  tr[ *qswPiPulseOnly()].onValueChanged().connect(m_lsnOnPulseChanged);
330  tr[ *invertPhase()].onValueChanged().connect(m_lsnOnPulseChanged);
331  tr[ *conserveStEPhase()].onValueChanged().connect(m_lsnOnPulseChanged);
332  for(unsigned int i = 0; i < NUM_DO_PORTS; i++) {
333  tr[ *portSel(i)].onValueChanged().connect(m_lsnOnPulseChanged);
334  }
335 
336  if(hasQAMPorts()) {
337  tr[ *p1Func()].onValueChanged().connect(m_lsnOnPulseChanged);
338  tr[ *p2Func()].onValueChanged().connect(m_lsnOnPulseChanged);
339  tr[ *combFunc()].onValueChanged().connect(m_lsnOnPulseChanged);
340  tr[ *p1Level()].onValueChanged().connect(m_lsnOnPulseChanged);
341  tr[ *p2Level()].onValueChanged().connect(m_lsnOnPulseChanged);
342  tr[ *combLevel()].onValueChanged().connect(m_lsnOnPulseChanged);
343  tr[ *masterLevel()].onValueChanged().connect(m_lsnOnPulseChanged);
344  tr[ *qamOffset1()].onValueChanged().connect(m_lsnOnPulseChanged);
345  tr[ *qamOffset2()].onValueChanged().connect(m_lsnOnPulseChanged);
346  tr[ *qamLevel1()].onValueChanged().connect(m_lsnOnPulseChanged);
347  tr[ *qamLevel2()].onValueChanged().connect(m_lsnOnPulseChanged);
348  tr[ *qamDelay1()].onValueChanged().connect(m_lsnOnPulseChanged);
349  tr[ *qamDelay2()].onValueChanged().connect(m_lsnOnPulseChanged);
350  tr[ *difFreq()].onValueChanged().connect(m_lsnOnPulseChanged);
351  }
352 
353  tr[ *pulseAnalyzerMode()].onValueChanged().connect(m_lsnOnPulseChanged);
354  tr[ *paPulseRept()].onValueChanged().connect(m_lsnOnPulseChanged);
355  tr[ *paPulseBW()].onValueChanged().connect(m_lsnOnPulseChanged);
356  });
357 }
358 void
360  m_lsnOnPulseChanged.reset();
361 
362  changeUIStatus(true, false);
363  pulseAnalyzerMode()->setUIEnabled(false);
364 
365  for(unsigned int i = 0; i < NUM_DO_PORTS; i++) {
366  m_portSel[i]->setUIEnabled(true);
367  }
368 
369  closeInterface();
370 }
371 
372 void
373 XPulser::changeUIStatus(bool nmrmode, bool state) {
374  iterate_commit([=](Transaction &tr){
375  //Features with QAM in NMR.
376  std::vector<shared_ptr<XNode>> runtime_ui{
377  p1Func(), p2Func(), combFunc(),
378  p1Level(), p2Level(), combLevel(),
379  masterLevel(), difFreq()
380  };
381  bool uienable = state && hasQAMPorts() && nmrmode;
382  for(auto &&x: runtime_ui)
383  tr[ *x].setUIEnabled(uienable);
384 
385  //Features with QAM.
386  runtime_ui = {
387  qamOffset1(), qamOffset2(),
388  qamLevel1(), qamLevel2(),
389  qamDelay1(), qamDelay2()
390  };
391  uienable = state && hasQAMPorts();
392  for(auto &&x: runtime_ui)
393  tr[ *x].setUIEnabled(uienable);
394 
395  runtime_ui = {
396  output(), paPulseRept(), paPulseBW()
397  };
398  for(auto &&x: runtime_ui)
399  tr[ *x].setUIEnabled(state);
400 
401  //Features in NMR.
402  runtime_ui = {
403  combMode(), rtMode(),
404  rtime(), tau(),
405  combPW(), pw1(), pw2(),
406  combNum(), combPT(), combP1(), combP1Alt(),
407  aswSetup(), aswHold(), altSep(),
408  g2Setup(), echoNum(),
411  induceEmission(), induceEmissionPhase(),
413  invertPhase(), conserveStEPhase()
414  };
415  uienable = state && nmrmode;
416  for(auto &&x: runtime_ui)
417  tr[ *x].setUIEnabled(uienable);
418  });
419 }
420 
421 void
423  tr[ *this].m_combMode = reader.pop<int16_t>();
424  int16_t pulser_mode = reader.pop<int16_t>();
425  tr[ *this].m_pulserMode = pulser_mode;
426  switch(pulser_mode) {
427  case N_MODE_NMR_PULSER:
428  default:
429  tr[ *this].m_rtime = reader.pop<double>();
430  tr[ *this].m_tau = reader.pop<double>();
431  tr[ *this].m_pw1 = reader.pop<double>();
432  tr[ *this].m_pw2 = reader.pop<double>();
433  tr[ *this].m_combP1 = reader.pop<double>();
434  tr[ *this].m_altSep = reader.pop<double>();
435  tr[ *this].m_combP1Alt = reader.pop<double>();
436  tr[ *this].m_aswSetup = reader.pop<double>();
437  tr[ *this].m_aswHold = reader.pop<double>();
438  try {
439  // ver 2 records
440  tr[ *this].m_difFreq = reader.pop<double>();
441  tr[ *this].m_combPW = reader.pop<double>();
442  tr[ *this].m_combPT = reader.pop<double>();
443  tr[ *this].m_echoNum = reader.pop<uint16_t>();
444  tr[ *this].m_combNum = reader.pop<uint16_t>();
445  tr[ *this].m_rtMode = reader.pop<int16_t>();
446  tr[ *this].m_numPhaseCycle = reader.pop<uint16_t>();
447  // ver 3 records
448  tr[ *this].m_invertPhase = reader.pop<uint16_t>();
449  // ver 4 records
450  tr[ *this].m_p1Func = reader.pop<int16_t>();
451  tr[ *this].m_p2Func = reader.pop<int16_t>();
452  tr[ *this].m_combFunc = reader.pop<int16_t>();
453  tr[ *this].m_p1Level = reader.pop<double>();
454  tr[ *this].m_p2Level = reader.pop<double>();
455  tr[ *this].m_combLevel = reader.pop<double>();
456  tr[ *this].m_masterLevel = reader.pop<double>();
457  tr[ *this].m_combOffRes= reader.pop<double>();
458  tr[ *this].m_conserveStEPhase = reader.pop<uint16_t>();
459  }
460  catch (XRecordError &) {
461  const Snapshot &shot(tr);
462  tr[ *this].m_difFreq = shot[ *difFreq()];
463  tr[ *this].m_combPW = shot[ *combPW()];
464  tr[ *this].m_combPT = shot[ *combPT()];
465  tr[ *this].m_echoNum = shot[ *echoNum()];
466  tr[ *this].m_combNum = shot[ *combNum()];
467  tr[ *this].m_rtMode = shot[ *rtMode()];
468  int npat = 16;
469  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_1) npat = 1;
470  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_2) npat = 2;
471  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_4) npat = 4;
472  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_8) npat = 8;
473  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_16) npat = 16;
474  tr[ *this].m_numPhaseCycle = npat;
475  tr[ *this].m_invertPhase = 0.0;
476  tr[ *this].m_p1Func = PULSE_NO_HAMMING;
477  tr[ *this].m_p2Func = PULSE_NO_HAMMING;
478  tr[ *this].m_combFunc = PULSE_NO_HAMMING;
479  tr[ *this].m_p1Level = 0;
480  tr[ *this].m_p2Level = -5;
481  tr[ *this].m_combLevel = 0;
482  tr[ *this].m_masterLevel = -10;
483  tr[ *this].m_combOffRes= 0;
484  tr[ *this].m_conserveStEPhase = 0;
485  }
486  tr[ *this].m_paPulseBW = -1;
487  tr[ *this].m_paPulseOrigin = 0;
488 
489  createRelPatListNMRPulser(tr);
490  break;
491  case N_MODE_PULSE_ANALYZER:
492  tr[ *this].m_rtime = tr[ *paPulseRept()];;
493  tr[ *this].m_tau = 0;
494  tr[ *this].m_pw1 = 6800.0 / tr[ *paPulseBW()]; //flattop_longlong
495  tr[ *this].m_pw2 = 0;
496  tr[ *this].m_combP1 = 0;
497  tr[ *this].m_altSep = 0;
498  tr[ *this].m_combP1Alt = 0;
499  tr[ *this].m_aswSetup = 0.1;
500  tr[ *this].m_aswHold = 0.1;
501  tr[ *this].m_difFreq = 0;
502  tr[ *this].m_combPW = 0;
503  tr[ *this].m_combPT = 0;
504  tr[ *this].m_echoNum = 1;
505  tr[ *this].m_combNum = 1;
506  tr[ *this].m_rtMode = N_COMB_MODE_OFF;
507  tr[ *this].m_numPhaseCycle = 2;
508  tr[ *this].m_invertPhase = 0.0;
509  tr[ *this].m_p1Func = PULSE_NO_FLATTOP_LONG_LONG;
510  tr[ *this].m_p2Func = PULSE_NO_FLATTOP_LONG_LONG;
511  tr[ *this].m_combFunc = PULSE_NO_FLATTOP_LONG_LONG;
512  tr[ *this].m_p1Level = 0;
513  tr[ *this].m_p2Level = -5;
514  tr[ *this].m_combLevel = 0;
515  tr[ *this].m_masterLevel = -10;
516  tr[ *this].m_combOffRes= 0;
517  tr[ *this].m_conserveStEPhase = 0;
518 
519  tr[ *this].m_paPulseBW = tr[ *paPulseBW()];
520  tr[ *this].m_paPulseOrigin = tr[ *this].m_pw1 / 2;
521  createRelPatListPulseAnalyzer(tr);
522  break;
523  }
524  try {
525  createNativePatterns(tr); //calling driver specific virtual funciton.
526  }
527  catch (XInterface::XInterfaceError &e) {
528  e.print();
529  }
530 }
531 
532 void
533 XPulser::onPulseChanged(const Snapshot &shot_node, XValueNodeBase *node) {
534  XTime time_awared = XTime::now();
535  Snapshot shot( *this);
536 
537  if(node == pulseAnalyzerMode().get()) {
538  changeUIStatus( !shot[ *pulseAnalyzerMode()], true);
539  }
540  if(shot[ *pulseAnalyzerMode()]) {
541  auto writer = std::make_shared<RawData>();
542 
543  // ver 1 records below
544  writer->push((int16_t)0);
545  writer->push((int16_t)N_MODE_PULSE_ANALYZER);
546 
547  finishWritingRaw(writer, time_awared, XTime::now());
548  return;
549  }
550 
551  const double tau__ = rintTermMicroSec(shot[ *tau()]);
552  const double asw_setup__ = rintTermMilliSec(shot[ *aswSetup()]);
553  const double asw_hold__ = rintTermMilliSec(shot[ *aswHold()]);
554  const double alt_sep__ = rintTermMilliSec(shot[ *altSep()]);
555  const int echo_num__ = shot[ *echoNum()];
556  if(asw_setup__ > 2.0 * tau__)
557  trans( *aswSetup()) = 2.0 * tau__;
558  if(node != altSep().get()) {
559  if(alt_sep__ != asw_setup__ + asw_hold__ + (echo_num__ - 1) * 2 * tau__/1000) {
560  trans( *altSep()) = asw_setup__ + asw_hold__ + (echo_num__ - 1) * 2 * tau__/1000;
561  return;
562  }
563  }
564 
565  auto writer = std::make_shared<RawData>();
566 
567  if( !shot[ *output()]) {
568  finishWritingRaw(writer, XTime(), XTime());
569  return;
570  }
571 
572 /* try {
573  changeOutput(false, blankpattern);
574  }
575  catch (XKameError &e) {
576  e.print(getLabel() + i18n("Pulser Turn-Off Failed, because"));
577  return;
578  }
579 */
580 // ver 1 records below
581  writer->push((int16_t)shot[ *combMode()]);
582  writer->push((int16_t)N_MODE_NMR_PULSER);
583  writer->push((double)rintTermMilliSec(shot[ *rtime()]));
584  writer->push((double)tau__);
585  writer->push((double)shot[ *pw1()]);
586  writer->push((double)shot[ *pw2()]);
587  writer->push((double)rintTermMilliSec(shot[ *combP1()]));
588  writer->push((double)alt_sep__);
589  writer->push((double)rintTermMilliSec(shot[ *combP1Alt()]));
590  writer->push((double)asw_setup__);
591  writer->push((double)asw_hold__);
592 // ver 2 records below
593  writer->push((double)shot[ *difFreq()]);
594  writer->push((double)shot[ *combPW()]);
595  writer->push((double)rintTermMicroSec(shot[ *combPT()]));
596  writer->push((uint16_t)shot[ *echoNum()]);
597  writer->push((uint16_t)shot[ *combNum()]);
598  writer->push((int16_t)shot[ *rtMode()]);
599  int npat = 16;
600  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_1) npat = 1;
601  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_2) npat = 2;
602  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_4) npat = 4;
603  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_8) npat = 8;
604  if(shot[ *numPhaseCycle()].to_str() == NUM_PHASE_CYCLE_16) npat = 16;
605  writer->push((uint16_t)npat);
606 // ver 3 records below
607  writer->push((uint16_t)shot[ *invertPhase()]);
608 // ver 4 records below
609  writer->push((uint16_t)shot[ *p1Func()]);
610  writer->push((uint16_t)shot[ *p2Func()]);
611  writer->push((uint16_t)shot[ *combFunc()]);
612  writer->push((double)shot[ *p1Level()]);
613  writer->push((double)shot[ *p2Level()]);
614  writer->push((double)shot[ *combLevel()]);
615  writer->push((double)shot[ *masterLevel()]);
616  writer->push((double)shot[ *combOffRes()]);
617  writer->push((uint16_t)shot[ *conserveStEPhase()]);
618 
619  finishWritingRaw(writer, time_awared, XTime::now());
620 }
621 
622 double
624  assert( !m_relPatList.empty());
625  return m_relPatList.back().time;
626 }
627 
628 unsigned int
629 XPulser::selectedPorts(const Snapshot &shot, int func) const {
630  unsigned int mask = 0;
631  for(unsigned int i = 0; i < NUM_DO_PORTS; i++) {
632  if(shot[ *portSel(i)] == func)
633  mask |= 1 << i;
634  }
635  return mask;
636 }
637 void
639  //A pettern at absolute time
640  class tpat {
641  public:
642  tpat(uint64_t npos, uint32_t newpat, uint32_t nmask) {
643  pos = npos; pat = newpat; mask = nmask;
644  }
645  tpat(const tpat &x) {
646  pos = x.pos; pat = x.pat; mask = x.mask;
647  }
648  uint64_t pos;
649  //this pattern bits will be outputted at 'pos'
650  uint32_t pat;
651  //mask bits
652  uint32_t mask;
653 
654  bool operator< (const tpat &y) const {
655  return pos < y.pos;
656  }
657  };
658 
659  const Snapshot &shot(tr);
660 
661  unsigned int g3mask = selectedPorts(shot, PORTSEL_GATE3);
662  unsigned int g2mask = selectedPorts(shot, PORTSEL_PREGATE);
663  unsigned int pagmask = selectedPorts(shot, PORTSEL_PULSE_ANALYZER_GATE);
664  unsigned int g1mask = (selectedPorts(shot, PORTSEL_GATE) | g3mask | pagmask);
665  unsigned int trig1mask = selectedPorts(shot, PORTSEL_TRIG1);
666  unsigned int trig2mask = selectedPorts(shot, PORTSEL_TRIG2);
667  unsigned int aswmask = selectedPorts(shot, PORTSEL_ASW);
668  unsigned int qswmask = selectedPorts(shot, PORTSEL_QSW);
669  unsigned int pulse1mask = selectedPorts(shot, PORTSEL_PULSE1);
670  unsigned int pulse2mask = selectedPorts(shot, PORTSEL_PULSE2);
671  unsigned int combmask = selectedPorts(shot, PORTSEL_COMB);
672  unsigned int combfmmask = selectedPorts(shot, PORTSEL_COMB_FM);
673 
674  bool invert_phase__ = shot[ *this].invertPhase();
675 
676  //QPSK patterns correspoinding to 0, pi/2, pi, -pi/2
677  unsigned int qpsk[4];
678  unsigned int qpskinv[4];
679  unsigned int qpskmask;
680  qpskmask = bitpatternsOfQPSK(shot, qpsk, qpskinv, invert_phase__);
681 
682  uint64_t rtime__ = rintSampsMilliSec(shot[ *this].rtime());
683  uint64_t tau__ = rintSampsMicroSec(shot[ *this].tau());
684  uint64_t asw_setup__ = rintSampsMilliSec(shot[ *this].aswSetup());
685  uint64_t asw_hold__ = rintSampsMilliSec(shot[ *this].aswHold());
686  uint64_t alt_sep__ = rintSampsMilliSec(shot[ *this].altSep());
687  uint64_t pw1__ = hasQAMPorts() ?
688  ceilSampsMicroSec(shot[ *this].pw1()/2)*2 : rintSampsMicroSec(shot[ *this].pw1()/2)*2;
689  uint64_t pw2__ = hasQAMPorts() ?
690  ceilSampsMicroSec(shot[ *this].pw2()/2)*2 : rintSampsMicroSec(shot[ *this].pw2()/2)*2;
691  uint64_t comb_pw__ = hasQAMPorts() ?
692  ceilSampsMicroSec(shot[ *this].combPW()/2)*2 : rintSampsMicroSec(shot[ *this].combPW()/2)*2;
693  uint64_t comb_pt__ = rintSampsMicroSec(shot[ *this].combPT());
694  uint64_t comb_p1__ = rintSampsMilliSec(shot[ *this].combP1());
695  uint64_t comb_p1_alt__ = rintSampsMilliSec(shot[ *this].combP1Alt());
696  uint64_t g2_setup__ = ceilSampsMicroSec(shot[ *g2Setup()]);
697  int echo_num__ = shot[ *this].echoNum();
698  int comb_num__ = shot[ *this].combNum();
699  int comb_mode__ = shot[ *this].combMode();
700  int rt_mode__ = shot[ *this].rtMode();
701  int num_phase_cycle__ = shot[ *this].numPhaseCycle();
702  int first_phase__ = shot[ *firstPhase()];
703 
704  bool comb_mode_alt = ((comb_mode__ == N_COMB_MODE_P1_ALT) ||
705  (comb_mode__ == N_COMB_MODE_COMB_ALT));
706  bool saturation_wo_comb = (comb_num__ == 0);
707  bool driven_equilibrium = shot[ *drivenEquilibrium()];
708  uint64_t qsw_delay__ = rintSampsMicroSec(shot[ *qswDelay()]);
709  uint64_t qsw_width__ = rintSampsMicroSec(shot[ *qswWidth()]);
710  uint64_t qsw_softswoff__ = std::min(qsw_width__, rintSampsMicroSec(shot[ *qswSoftSWOff()]));
711  bool qsw_pi_only__ = shot[ *qswPiPulseOnly()];
712  int comb_rot_num = lrint(shot[ *this].combOffRes() * (shot[ *this].combPW() / 1000.0 * 4));
713 
714  bool induce_emission__ = shot[ *induceEmission()];
715  uint64_t induce_emission___pw = comb_pw__;
716  if(comb_mode__ == N_COMB_MODE_OFF)
717  num_phase_cycle__ = std::min(num_phase_cycle__, 4);
718 
719  bool conserve_ste_phase__ = shot[ *this].conserveStEPhase();
720 
721  //comb phases
722  const uint32_t comb_ste_cancel[MAX_NUM_PHASE_CYCLE] = {
723  1, 3, 0, 2, 3, 1, 2, 0, 0, 2, 1, 3, 2, 0, 3, 1
724  };
725  //induced emission phases
726  const uint32_t pindem[MAX_NUM_PHASE_CYCLE] = {
727  0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2
728  };
729 
730  //pi/2 pulse phases
731  const uint32_t p1[MAX_NUM_PHASE_CYCLE] = {
732  0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2
733  };
734  //pi pulse phases
735  const uint32_t p2__[MAX_NUM_PHASE_CYCLE] = {
736  0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3
737  };
738  const uint32_t *p2 = conserve_ste_phase__ ? p1 : p2__;
739 
740  //subsequent pi pulse phases for multiple echoes or for st.e.
741  const uint32_t p2multi[MAX_NUM_PHASE_CYCLE] = {
742  1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3
743  };
744  //stimulated echo pulse phases
745  const uint32_t ste_p1[MAX_NUM_PHASE_CYCLE] = {
746  0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2
747  };
748  const uint32_t ste_p2[MAX_NUM_PHASE_CYCLE] = {
749  0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0
750  };
751 
752  typedef std::multiset<tpat, std::less<tpat> > tpatset;
753  tpatset patterns; // patterns
754  tpatset patterns_cheap; //Low priority patterns
755  typedef std::multiset<tpat, std::less<tpat> >::iterator tpatset_it;
756 
757  uint64_t pos = 0;
758 
759  int echonum = echo_num__;
760 
761  bool former_of_alt = !invert_phase__;
762  for(int i = 0; i < num_phase_cycle__ * (comb_mode_alt ? 2 : 1); i++) {
763  int j = (i / (comb_mode_alt ? 2 : 1) + first_phase__) % num_phase_cycle__; //index for phase cycling
764  if(invert_phase__)
765  j = num_phase_cycle__ - 1 - j;
766  former_of_alt = !former_of_alt;
767  bool comb_off_res = ((comb_mode__ != N_COMB_MODE_COMB_ALT) || former_of_alt) && (comb_rot_num != 0);
768 
769  uint64_t p1__ = 0; //0: Comb pulse is OFF.
770  if((comb_mode__ != N_COMB_MODE_OFF) &&
771  !((comb_mode__ == N_COMB_MODE_COMB_ALT) && former_of_alt && !(comb_rot_num != 0))) {
772  p1__ = ((former_of_alt || (comb_mode__ != N_COMB_MODE_P1_ALT)) ? comb_p1__ : comb_p1_alt__);
773  }
774 
775  uint64_t rest;
776  if(rt_mode__ == N_RT_MODE_FIXREST)
777  rest = rtime__;
778  else
779  rest = rtime__ - p1__;
780  if(rest <= 0)
781  throw XDriver::XRecordError("Inconsistent pattern of pulser setup.", __FILE__, __LINE__);
782 
783  if(saturation_wo_comb && (p1__ > 0)) rest = 0;
784 
785  pos += rest;
786 
787  //comb pulses
788  if((p1__ > 0) && !saturation_wo_comb) {
789  uint64_t combpt = std::max(comb_pt__, comb_pw__ + g2_setup__);
790  uint64_t cpos = pos - combpt * comb_num__;
791 
792  patterns_cheap.insert(tpat(cpos - comb_pw__/2 - g2_setup__, comb_off_res ? ~(uint32_t)0 : 0, combfmmask));
793  patterns_cheap.insert(tpat(cpos - comb_pw__/2 - g2_setup__, ~(uint32_t)0, combmask));
794  bool g2_each__ = (g2_setup__ * 2 + comb_pw__) < combpt;
795  for(int k = 0; k < comb_num__; k++) {
796  const uint32_t *comb = (conserve_ste_phase__) ?
797  ((k % 2 == 0) ? ste_p1 : ste_p2) : comb_ste_cancel;
798  patterns.insert(tpat(cpos + comb_pw__/2, qpsk[comb[j]], qpskmask));
799  cpos += combpt;
800  cpos -= comb_pw__/2;
801  if(g2_each__ || (k == 0))
802  patterns_cheap.insert(tpat(cpos - g2_setup__, g2mask, g2mask));
803  patterns.insert(tpat(cpos, ~(uint32_t)0, g1mask));
804  patterns.insert(tpat(cpos, PAT_QAM_PULSE_IDX_PCOMB, PAT_QAM_PULSE_IDX_MASK));
805  cpos += comb_pw__;
806  patterns.insert(tpat(cpos, 0 , g1mask));
807  patterns.insert(tpat(cpos, 0, PAT_QAM_PULSE_IDX_MASK));
808  if(g2_each__ || (k == comb_num__ - 1))
809  patterns.insert(tpat(cpos, 0, g2mask));
810  if( !qsw_pi_only__) {
811  patterns.insert(tpat(cpos + qsw_delay__, ~(uint32_t)0 , qswmask));
812  patterns.insert(tpat(cpos + (qsw_delay__ + qsw_width__/2 - qsw_softswoff__/2), 0 , qswmask));
813  patterns.insert(tpat(cpos + (qsw_delay__ + qsw_width__/2 + qsw_softswoff__/2), ~(uint32_t)0 , qswmask));
814  patterns.insert(tpat(cpos + (qsw_delay__ + qsw_width__), 0 , qswmask));
815  }
816 
817  cpos -= comb_pw__/2;
818  }
819  patterns.insert(tpat(cpos + comb_pw__/2, 0, combmask));
820  patterns.insert(tpat(cpos + comb_pw__/2, ~(uint32_t)0, combfmmask));
821  }
822  pos += p1__;
823 
824  //pi/2 pulse
825  bool g2_kept_p1p2 = false;
826  if(pw1__/2) {
827  //on
828  patterns_cheap.insert(tpat(pos - pw1__/2 - g2_setup__, qpsk[p1[j]], qpskmask));
829  patterns_cheap.insert(tpat(pos - pw1__/2 - g2_setup__, ~(uint32_t)0, g2mask));
830  patterns.insert(tpat(pos - pw1__/2, ~(uint32_t)0, trig2mask));
831  patterns_cheap.insert(tpat(pos - pw1__/2 - g2_setup__, ~(uint32_t)0, pulse1mask));
832  patterns.insert(tpat(pos - pw1__/2, PAT_QAM_PULSE_IDX_P1, PAT_QAM_PULSE_IDX_MASK));
833  patterns.insert(tpat(pos - pw1__/2, ~(uint32_t)0, g1mask));
834  //off
835  patterns.insert(tpat(pos + pw1__/2, 0, g1mask));
836  patterns.insert(tpat(pos + pw1__/2, 0, PAT_QAM_PULSE_IDX_MASK));
837  patterns.insert(tpat(pos + pw1__/2, 0, pulse1mask));
838  if( !pw2__/2 || (g2_setup__ * 2 + pw1__/2 + pw2__/2 < tau__)) {
839  patterns.insert(tpat(pos + pw1__/2, 0, g2mask));
840  }
841  else {
842  g2_kept_p1p2 = true;
843  }
844  if( ! qsw_pi_only__) {
845  patterns.insert(tpat(pos + pw1__/2 + qsw_delay__, ~(uint32_t)0 , qswmask));
846  patterns.insert(tpat(pos + pw1__/2 + (qsw_delay__ + qsw_width__/2 - qsw_softswoff__/2), 0 , qswmask));
847  patterns.insert(tpat(pos + pw1__/2 + (qsw_delay__ + qsw_width__/2 + qsw_softswoff__/2), ~(uint32_t)0 , qswmask));
848  patterns.insert(tpat(pos + pw1__/2 + (qsw_delay__ + qsw_width__), 0 , qswmask));
849  }
850  }
851  //for pi pulses
852  patterns.insert(tpat(pos + pw1__/2, qpsk[p2[j]], qpskmask));
853  patterns.insert(tpat(pos + pw1__/2, ~(uint32_t)0, pulse2mask));
854 
855  //2tau
856  pos += 2*tau__;
857  // patterns.insert(tpat(pos - asw_setup__, -1, aswmask | rfswmask, 0));
858  patterns.insert(tpat(pos - asw_setup__, ~(uint32_t)0, aswmask));
859  patterns.insert(tpat(pos -
860  (( !former_of_alt && comb_mode_alt) ? alt_sep__ : 0), ~(uint32_t)0, trig1mask));
861 
862  //induce emission
863  if(induce_emission__) {
864  patterns.insert(tpat(pos - induce_emission___pw/2, ~(uint32_t)0, g3mask));
865  patterns.insert(tpat(pos - induce_emission___pw/2, PAT_QAM_PULSE_IDX_INDUCE_EMISSION, PAT_QAM_PULSE_IDX_MASK));
866  patterns.insert(tpat(pos - induce_emission___pw/2, qpsk[pindem[j]], qpskmask));
867  patterns.insert(tpat(pos + induce_emission___pw/2, 0, PAT_QAM_PULSE_IDX_MASK));
868  patterns.insert(tpat(pos + induce_emission___pw/2, 0, g3mask));
869  }
870 
871  //pi pulses
872  pos -= 3*tau__;
873  for(int k = 0; k < echonum; k++) {
874  pos += 2*tau__;
875  if(pw2__/2) {
876  patterns.insert(tpat(pos - pw2__/2, 0, trig2mask));
877  //on
878  if( !g2_kept_p1p2) {
879  patterns_cheap.insert(tpat(pos - pw2__/2 - g2_setup__, qpsk[(k == 0) ? p2[j] : p2multi[j]], qpskmask));
880  patterns_cheap.insert(tpat(pos - pw2__/2 - g2_setup__, ~(uint32_t)0, g2mask));
881  }
882 
883  patterns.insert(tpat(pos - pw2__/2, PAT_QAM_PULSE_IDX_P2, PAT_QAM_PULSE_IDX_MASK));
884  patterns.insert(tpat(pos - pw2__/2, ~(uint32_t)0, g1mask));
885  //off
886  patterns.insert(tpat(pos + pw2__/2, 0, PAT_QAM_PULSE_IDX_MASK));
887  patterns.insert(tpat(pos + pw2__/2, 0, g1mask));
888  patterns.insert(tpat(pos + pw2__/2, 0, pulse2mask));
889  patterns.insert(tpat(pos + pw2__/2, 0, g2mask));
890  g2_kept_p1p2 = false;
891  //QSW
892  patterns.insert(tpat(pos + pw2__/2 + qsw_delay__, ~(uint32_t)0 , qswmask));
893  patterns.insert(tpat(pos + pw2__/2 + (qsw_delay__ + qsw_width__/2 - qsw_softswoff__/2), 0 , qswmask));
894  patterns.insert(tpat(pos + pw2__/2 + (qsw_delay__ + qsw_width__/2 + qsw_softswoff__/2), ~(uint32_t)0 , qswmask));
895  patterns.insert(tpat(pos + pw2__/2 + (qsw_delay__ + qsw_width__), 0 , qswmask));
896  }
897  }
898  if(g2_kept_p1p2)
899  throw XDriver::XRecordError("Inconsistent pattern of pulser setup.", __FILE__, __LINE__);
900 
901  patterns.insert(tpat(pos + tau__ + asw_hold__, 0, aswmask | trig1mask));
902  //induce emission
903  if(induce_emission__) {
904  patterns.insert(tpat(pos + tau__ + asw_hold__ - induce_emission___pw/2, ~(uint32_t)0, g3mask));
905  patterns.insert(tpat(pos + tau__ + asw_hold__ - induce_emission___pw/2, PAT_QAM_PULSE_IDX_INDUCE_EMISSION, PAT_QAM_PULSE_IDX_MASK));
906  patterns.insert(tpat(pos + tau__ + asw_hold__ - induce_emission___pw/2, qpsk[pindem[j]], qpskmask));
907  patterns.insert(tpat(pos + tau__ + asw_hold__ + induce_emission___pw/2, 0, PAT_QAM_PULSE_IDX_MASK));
908  patterns.insert(tpat(pos + tau__ + asw_hold__ + induce_emission___pw/2, 0, g3mask));
909  }
910 
911  if(driven_equilibrium) {
912  pos += 2*tau__;
913  //pi pulse
914  //on
915  patterns_cheap.insert(tpat(pos - pw2__/2 - g2_setup__, qpskinv[p2[j]], qpskmask));
916  patterns_cheap.insert(tpat(pos - pw2__/2 - g2_setup__, ~(uint32_t)0, g2mask));
917  patterns_cheap.insert(tpat(pos - pw2__/2 - g2_setup__, ~(uint32_t)0, pulse2mask));
918  patterns.insert(tpat(pos - pw2__/2, PAT_QAM_PULSE_IDX_P2, PAT_QAM_PULSE_IDX_MASK));
919  patterns.insert(tpat(pos - pw2__/2, ~(uint32_t)0, g1mask));
920  //off
921  patterns.insert(tpat(pos + pw2__/2, 0, pulse2mask));
922  patterns.insert(tpat(pos + pw2__/2, 0, PAT_QAM_PULSE_IDX_MASK));
923  patterns.insert(tpat(pos + pw2__/2, 0, g1mask | g2mask));
924  patterns.insert(tpat(pos + pw2__/2 + qsw_delay__, ~(uint32_t)0 , qswmask));
925  if(qsw_softswoff__) {
926  patterns.insert(tpat(pos + pw2__/2 + (qsw_delay__ + qsw_width__/2 - qsw_softswoff__/2), 0 , qswmask));
927  patterns.insert(tpat(pos + pw2__/2 + (qsw_delay__ + qsw_width__/2 + qsw_softswoff__/2), ~(uint32_t)0 , qswmask));
928  }
929  patterns.insert(tpat(pos + pw2__/2 + (qsw_delay__ + qsw_width__), 0 , qswmask));
930  pos += tau__;
931  //pi/2 pulse
932  //on
933  patterns_cheap.insert(tpat(pos - pw1__/2 - g2_setup__, qpskinv[p1[j]], qpskmask));
934  patterns_cheap.insert(tpat(pos - pw1__/2 - g2_setup__, ~(uint32_t)0, pulse1mask));
935  patterns_cheap.insert(tpat(pos - pw1__/2 - g2_setup__, ~(uint32_t)0, g2mask));
936  patterns.insert(tpat(pos - pw1__/2, PAT_QAM_PULSE_IDX_P1, PAT_QAM_PULSE_IDX_MASK));
937  patterns.insert(tpat(pos - pw1__/2, ~(uint32_t)0, g1mask));
938  //off
939  patterns.insert(tpat(pos + pw1__/2, 0, PAT_QAM_PULSE_IDX_MASK));
940  patterns.insert(tpat(pos + pw1__/2, 0, g1mask));
941  patterns.insert(tpat(pos + pw1__/2, 0, pulse1mask));
942  patterns.insert(tpat(pos + pw1__/2, qpsk[p1[j]], qpskmask));
943  patterns.insert(tpat(pos + pw1__/2, 0, g2mask));
944  if( !qsw_pi_only__) {
945  patterns.insert(tpat(pos + pw1__/2 + qsw_delay__, ~(uint32_t)0 , qswmask));
946  patterns.insert(tpat(pos + pw1__/2 + (qsw_delay__ + qsw_width__/2 - qsw_softswoff__/2), 0 , qswmask));
947  patterns.insert(tpat(pos + pw1__/2 + (qsw_delay__ + qsw_width__/2 + qsw_softswoff__/2), ~(uint32_t)0 , qswmask));
948  patterns.insert(tpat(pos + pw1__/2 + (qsw_delay__ + qsw_width__), 0 , qswmask));
949  }
950  }
951  }
952 
953  //insert low-priority (cheap) pulses into pattern set
954  for(tpatset_it it = patterns_cheap.begin(); it != patterns_cheap.end(); it++) {
955  uint64_t npos = it->pos;
956  for(tpatset_it kit = patterns.begin(); kit != patterns.end(); kit++) {
957  //Avoid overrapping within minPulseWidth(), which is typ. 1 us
958  uint64_t diff = llabs((int64_t)kit->pos - (int64_t)npos);
959  diff -= pos * (diff / pos);
960  if(diff < rintSampsMilliSec(minPulseWidth())) {
961  npos = kit->pos;
962  break;
963  }
964  }
965  patterns.insert(tpat(npos, it->pat, it->mask));
966  }
967 
968  //determine the first pattern and the length.
969  uint64_t lastpos = 0;
970  uint32_t pat = 0;
971  for(tpatset_it it = patterns.begin(); it != patterns.end(); it++) {
972  lastpos = it->pos - pos;
973  pat &= ~it->mask;
974  pat |= (it->pat & it->mask);
975  }
976 
977  tr[ *this].m_relPatList.clear();
978  uint64_t patpos = patterns.begin()->pos;
979  for(tpatset_it it = patterns.begin(); it != patterns.end();) {
980  pat &= ~it->mask;
981  pat |= (it->pat & it->mask);
982  it++;
983  if((it == patterns.end()) || (it->pos != patpos)) {
984  //skip duplicated patterns.
985  if((it != patterns.end()) &&
986  tr[ *this].m_relPatList.size() &&
987  (pat == tr[ *this].m_relPatList[tr[ *this].m_relPatList.size() - 1].pattern)) {
988  patpos = it->pos;
989  continue;
990  }
991  Payload::RelPat relpat(pat, patpos, patpos - lastpos);
992  tr[ *this].m_relPatList.push_back(relpat);
993  if(it == patterns.end()) break;
994  lastpos = patpos;
995  patpos = it->pos;
996  }
997  }
998 
999  //Prepares analog pulse waves for QAM
1000  if(hasQAMPorts()) {
1001  for(unsigned int i = 0; i < PAT_QAM_PULSE_IDX_MASK/PAT_QAM_PULSE_IDX; i++)
1002  tr[ *this].m_qamWaveForm[i].clear();
1003 
1004  double tau__ = shot[ *this].tau();
1005  double dif_freq__ = shot[ *this].difFreq();
1006 
1007  bool induce_emission__ = shot[ *induceEmission()];
1008  double induce_emission___phase = shot[ *induceEmissionPhase()] / 180.0 * M_PI;
1009 
1010  makeWaveForm(tr, PAT_QAM_PULSE_IDX_P1/PAT_QAM_PULSE_IDX - 1,
1011  shot[ *this].pw1()*1e-3,
1012  pw1__/2, pulseFunc(shot[ *this].p1Func()),
1013  shot[ *this].p1Level(), dif_freq__ * 1e3, -2 * M_PI * dif_freq__ * 2 * tau__);
1014  makeWaveForm(tr, PAT_QAM_PULSE_IDX_P2/PAT_QAM_PULSE_IDX - 1,
1015  shot[ *this].pw2()*1e-3,
1016  pw2__/2, pulseFunc(shot[ *this].p2Func()),
1017  shot[ *this].p2Level(), dif_freq__ * 1e3, -2 * M_PI * dif_freq__ * 2 * tau__);
1018  makeWaveForm(tr, PAT_QAM_PULSE_IDX_PCOMB/PAT_QAM_PULSE_IDX - 1,
1019  shot[ *this].combPW()*1e-3,
1020  comb_pw__/2, pulseFunc(shot[ *this].combFunc()),
1021  shot[ *this].combLevel(), shot[ *this].combOffRes() + dif_freq__ *1000.0);
1022  if(induce_emission__) {
1023  makeWaveForm(tr, PAT_QAM_PULSE_IDX_INDUCE_EMISSION/PAT_QAM_PULSE_IDX - 1,
1024  shot[ *this].combPW()*1e-3,
1025  induce_emission___pw/2, pulseFunc(shot[ *this].combFunc()),
1026  shot[ *this].combLevel(), shot[ *this].combOffRes() + dif_freq__ *1000.0, induce_emission___phase);
1027  }
1028  }
1029 }
1030 
1031 unsigned int
1032 XPulser::bitpatternsOfQPSK(const Snapshot &shot, unsigned int qpsk[4], unsigned int qpskinv[4], bool invert) {
1033  unsigned int qpskamask = selectedPorts(shot, PORTSEL_QPSK_A);
1034  unsigned int qpskbmask = selectedPorts(shot, PORTSEL_QPSK_B);
1035  unsigned int qpsknoninvmask = selectedPorts(shot, PORTSEL_QPSK_OLD_NONINV);
1036  unsigned int qpskinvmask = selectedPorts(shot, PORTSEL_QPSK_OLD_INV);
1037  unsigned int qpskpsgatemask = selectedPorts(shot, PORTSEL_QPSK_OLD_PSGATE);
1038  unsigned int qpskmask = qpskamask | qpskbmask |
1039  qpskinvmask | qpsknoninvmask | qpskpsgatemask | PAT_QAM_PHASE_MASK;
1040 
1041  auto qpsk__ = [=](unsigned int phase) -> unsigned int {
1042  //unit of phase is pi/2
1043  auto qpsk_ph__ = [invert](unsigned int phase) -> unsigned int {
1044  return (phase + (invert ? 2 : 0)) % 4;
1045  };
1046  //patterns correspoinding to 0, pi/2, pi, -pi/2
1047  const unsigned int qpskIQ[4] = {0, 1, 3, 2};
1048  const unsigned int qpskOLD[4] = {2, 3, 4, 5};
1049  return
1050  ((qpskIQ[qpsk_ph__(phase)] & 1) ? qpskamask : 0) |
1051  ((qpskIQ[qpsk_ph__(phase)] & 2) ? qpskbmask : 0) |
1052  ((qpskOLD[qpsk_ph__(phase)] & 1) ? qpskpsgatemask : 0) |
1053  ((qpskOLD[qpsk_ph__(phase)] & 2) ? qpsknoninvmask : 0) |
1054  ((qpskOLD[qpsk_ph__(phase)] & 4) ? qpskinvmask : 0) |
1055  (qpsk_ph__(phase) * PAT_QAM_PHASE);
1056  };
1057 
1058  for(int ph = 0; ph < 4; ++ph) {
1059  qpsk[ph] = qpsk__(ph);
1060  qpskinv[ph] = qpsk__((ph + 2) % 4);
1061  }
1062  return qpskmask;
1063 }
1064 
1065 void
1066 XPulser::createRelPatListPulseAnalyzer(Transaction &tr) throw (XRecordError&) {
1067  const Snapshot &shot(tr);
1068 
1069  unsigned int trig1mask = selectedPorts(shot, PORTSEL_TRIG1);
1070  unsigned int trig2mask = selectedPorts(shot, PORTSEL_TRIG2);
1071  unsigned int aswmask = selectedPorts(shot, PORTSEL_ASW);
1072  unsigned int pulse1mask = selectedPorts(shot, PORTSEL_PULSE1);
1073  unsigned int pulse2mask = selectedPorts(shot, PORTSEL_PULSE2);
1074 
1075  unsigned int basebits = aswmask | selectedPorts(shot, PORTSEL_PULSE_ANALYZER_GATE);
1076  unsigned int trigbits = trig1mask | trig2mask | pulse1mask | pulse2mask;
1077  unsigned int onbits = 0, onmask = 0;
1078  if(hasQAMPorts()) {
1079  onbits = PAT_QAM_PULSE_IDX_P1;
1080  onmask = PAT_QAM_PULSE_IDX_MASK;
1081  }
1082 
1083  //QPSK patterns correspoinding to 0, pi/2, pi, -pi/2
1084  unsigned int qpsk[4];
1085  unsigned int qpskinv[4];
1086  unsigned int qpskmask;
1087  qpskmask = bitpatternsOfQPSK(shot, qpsk, qpskinv, false);
1088 
1089  uint64_t rtime__ = rintSampsMilliSec(shot[ *this].rtime());
1090  uint64_t pw1__ = hasQAMPorts() ?
1091  ceilSampsMicroSec(shot[ *this].pw1()/2)*2 : rintSampsMicroSec(shot[ *this].pw1()/2)*2;
1092 
1093  if((rtime__ <= pw1__) || (rtime__ <= pw1__) || (rtime__ == 0))
1094  throw XDriver::XRecordError("Inconsistent pattern of pulser setup.", __FILE__, __LINE__);
1095 
1096  tr[ *this].m_relPatList.clear();
1097  uint32_t pat = basebits | qpsk[0] | trigbits | onbits;
1098  tr[ *this].m_relPatList.push_back(Payload::RelPat(pat, rtime__ - pw1__, rtime__ - pw1__));
1099  pat &= ~onmask;
1100  pat &= ~trigbits;
1101  pat = (pat & ~qpskmask) | qpsk[2];
1102  tr[ *this].m_relPatList.push_back(Payload::RelPat(pat, rtime__, pw1__));
1103  pat |= onbits;
1104  tr[ *this].m_relPatList.push_back(Payload::RelPat(pat, 2 * rtime__ - pw1__, rtime__ - pw1__));
1105  pat &= ~onmask;
1106  pat &= ~trigbits;
1107  pat = (pat & ~qpskmask) | qpsk[0];
1108  tr[ *this].m_relPatList.push_back(Payload::RelPat(pat, 2 * rtime__, pw1__));
1109 
1110  if(hasQAMPorts()) {
1111  for(unsigned int i = 0; i < PAT_QAM_PULSE_IDX_MASK/PAT_QAM_PULSE_IDX; i++)
1112  tr[ *this].m_qamWaveForm[i].clear();
1113 
1114  makeWaveForm(tr, PAT_QAM_PULSE_IDX_P1/PAT_QAM_PULSE_IDX - 1,
1115  shot[ *this].pw1()*1e-3,
1116  pw1__/2, pulseFunc(shot[ *this].p1Func()),
1117  shot[ *this].p1Level(), 0, 0);
1118  }
1119 }
1120 
1121 void
1122 XPulser::makeWaveForm(Transaction &tr, unsigned int pnum_minus_1,
1123  double pw, unsigned int to_center,
1124  tpulsefunc func, double dB, double freq, double phase) {
1125  const Snapshot &shot(tr);
1126  std::vector<std::complex<double> > &p = tr[ *this].m_qamWaveForm[pnum_minus_1];
1127  double dma_ao_period = resolutionQAM();
1128  to_center *= lrint(resolution() / dma_ao_period);
1129  double delay1 = shot[ *qamDelay1()] * 1e-3 / dma_ao_period;
1130  double delay2 = shot[ *qamDelay2()] * 1e-3 / dma_ao_period;
1131  double dx = dma_ao_period / pw;
1132  double dp = 2*M_PI*freq*dma_ao_period;
1133  double z = pow(10.0, dB/20.0);
1134  const int FAC_ANTIALIAS = 3;
1135  p.resize(to_center * 2);
1136  std::fill(p.begin(), p.end(), std::complex<double>(0.0));
1137  std::vector<std::complex<double> > wave(p.size() * FAC_ANTIALIAS, 0.0);
1138  for(int i = 0; i < (int)wave.size(); ++i) {
1139  double i1 = (double)(i - (int)wave.size() / 2 - FAC_ANTIALIAS / 2) / FAC_ANTIALIAS - delay1;
1140  double i2 = i1 + delay1 - delay2;
1141  double x = z * func(i1 * dx) * cos(i1 * dp + M_PI/4 + phase);
1142  double y = z * func(i2 * dx) * sin(i2 * dp + M_PI/4 + phase);
1143  wave[i] = std::complex<double>(x, y) / (double)FAC_ANTIALIAS;
1144  }
1145  //Moving average for antialiasing.
1146  for(int i = 0; i < (int)wave.size(); ++i) {
1147  int j = i / FAC_ANTIALIAS;
1148  p[j] += wave[i];
1149  }
1150 }
1151 
1152 void
1154  const unsigned int blankpattern = selectedPorts(shot, PORTSEL_COMB_FM);
1155  try {
1156  changeOutput(shot, shot[ *output()], blankpattern);
1157  }
1158  catch (XKameError &e) {
1159  e.print(getLabel() + i18n("Pulser Turn-On/Off Failed, because"));
1160  }
1161 }

Generated for KAME4 by  doxygen 1.8.3