nmrfspectrum.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 "ui_nmrfspectrumform.h"
16 #include "nmrfspectrum.h"
17 #include "signalgenerator.h"
18 #include "nmrspectrumbase_impl.h"
19 #include "autolctuner.h"
20 #include "pulserdriver.h"
21 
22 REGISTER_TYPE(XDriverList, NMRFSpectrum, "NMR frequency-swept spectrum measurement");
23 
24 //---------------------------------------------------------------------------
25 XNMRFSpectrum::XNMRFSpectrum(const char *name, bool runtime,
26  Transaction &tr_meas, const shared_ptr<XMeasure> &meas)
27  : XNMRSpectrumBase<FrmNMRFSpectrum>(name, runtime, ref(tr_meas), meas),
28  m_sg1(create<XItemNode<XDriverList, XSG> >(
29  "SG1", false, ref(tr_meas), meas->drivers(), true)),
30  m_autoTuner(create<XItemNode<XDriverList, XAutoLCTuner> >(
31  "AutoTuner", false, ref(tr_meas), meas->drivers(), true)),
32  m_pulser(create<XItemNode<XDriverList, XPulser> >(
33  "Pulser", false, ref(tr_meas), meas->drivers(), true)),
34  m_sg1FreqOffset(create<XDoubleNode>("SG1FreqOffset", false)),
35  m_centerFreq(create<XDoubleNode>("CenterFreq", false)),
36  m_freqSpan(create<XDoubleNode>("FreqSpan", false)),
37  m_freqStep(create<XDoubleNode>("FreqStep", false)),
38  m_active(create<XBoolNode>("Active", true)),
39  m_tuneCycleStep(create<XDoubleNode>("TuneCycleStep", false)),
40  m_tuneCycleStrategy(create<XComboNode>("TuneCycleStrategy", false, true)) {
41 
42  connect(sg1());
43 // connect(autoTuner());
44 // connect(pulser());
45 
46  m_form->setWindowTitle(i18n("NMR Spectrum (Freq. Sweep) - ") + getLabel() );
47 
48  iterate_commit([=](Transaction &tr){
49  tr[ *m_spectrum].setLabel(0, "Freq [MHz]");
50  tr[ *tr[ *m_spectrum].axisx()->label()] = i18n("Freq [MHz]");
51 
52  tr[ *centerFreq()] = 20;
53  tr[ *sg1FreqOffset()] = 0;
54  tr[ *freqSpan()] = 200;
55  tr[ *freqStep()] = 1;
56 
57  for(auto &&x: {"As is", "Await Manual Tune", "Auto Tune", "Cyclic Avg. BPSK", "Cyclic Avg. QPSK", "Cyclic Avg. QPSKxP.I"})
58  tr[ *tuneCycleStrategy()].add(x);
59  tr[ *tuneCycleStrategy()] = STRATEGY_ASIS;
60  });
61 
62  m_conUIs = {
63  xqcon_create<XQLineEditConnector>(m_sg1FreqOffset, m_form->m_edSG1FreqOffset),
64  xqcon_create<XQLineEditConnector>(m_centerFreq, m_form->m_edCenterFreq),
65  xqcon_create<XQLineEditConnector>(m_freqSpan, m_form->m_edFreqSpan),
66  xqcon_create<XQLineEditConnector>(m_freqStep, m_form->m_edFreqStep),
67  xqcon_create<XQComboBoxConnector>(m_sg1, m_form->m_cmbSG1, ref(tr_meas)),
68  xqcon_create<XQComboBoxConnector>(m_autoTuner, m_form->m_cmbAutoTuner, ref(tr_meas)),
69  xqcon_create<XQComboBoxConnector>(m_pulser, m_form->m_cmbPulser, ref(tr_meas)),
70  xqcon_create<XQToggleButtonConnector>(m_active, m_form->m_ckbActive),
71  xqcon_create<XQLineEditConnector>(m_tuneCycleStep, m_form->m_edTuneCycleStep),
72  xqcon_create<XQComboBoxConnector>(m_tuneCycleStrategy, m_form->m_cmbTuneCycleStrategy, Snapshot( *m_tuneCycleStrategy))
73  };
74 
75  iterate_commit([=](Transaction &tr){
76  m_lsnOnActiveChanged = tr[ *active()].onValueChanged().connectWeakly(
77  shared_from_this(), &XNMRFSpectrum::onActiveChanged);
78  tr[ *centerFreq()].onValueChanged().connect(m_lsnOnCondChanged);
79  tr[ *freqSpan()].onValueChanged().connect(m_lsnOnCondChanged);
80  tr[ *freqStep()].onValueChanged().connect(m_lsnOnCondChanged);
81  });
82 }
83 
84 void
85 XNMRFSpectrum::onActiveChanged(const Snapshot &shot, XValueNodeBase *) {
86  Snapshot shot_this( *this);
87  if(shot_this[ *active()]) {
88  switch(shot_this[ *tuneCycleStrategy()]) {
89  case STRATEGY_ASIS:
90  break;
91  case STRATEGY_CYCLE_DBL:
92  case STRATEGY_CYCLE_QUAD:
93  case STRATEGY_CYCLE_OCT:
94  {
95  double x = shot_this[ *tuneCycleStep()] / shot_this[ *freqStep()];
96  if((x < 0.9) || (fabs(x - lrint(x)) > 0.003 * x))
97  gErrPrint(i18n("Invalid cyclic step."));
98  }
99  case STRATEGY_TUNE_AWAIT:
100  case STRATEGY_AUTOTUNE:
101  {
102  shared_ptr<XPulser> pulser__ = shot_this[ *pulser()];
103  if( !pulser__)
104  gErrPrint(i18n("Pulser should be selected."));
105  pulser__->iterate_commit([=](Transaction &tr){
106  tr[ *pulser__->firstPhase()] = 0;
107  tr[ *pulser__->invertPhase()] = false;
108  });
109  }
110  if(shot_this[ *tuneCycleStep()] <= 0.0)
111  gErrPrint(i18n("Invalid tuning/cyclic step."));
112  break;
113  }
114 
115  onClear(shot_this, clear().get());
116  m_lastFreqAcquired = -1000.0;
117  m_tunedFreq = -1000.0;
118  m_lastCycle = 0;
119  double newf = getMinFreq(shot_this) * 1e-6; //MHz
120  performTuning(shot_this, newf);
121  newf += shot_this[ *sg1FreqOffset()];
122  shared_ptr<XSG> sg1__ = shot_this[ *sg1()];
123  if(sg1__)
124  trans( *sg1__->freq()) = newf;
125  }
126  else
127  m_lsnOnTuningChanged.reset();
128 }
129 bool
131  return false;
132 }
133 bool
134 XNMRFSpectrum::checkDependencyImpl(const Snapshot &shot_this,
135  const Snapshot &shot_emitter, const Snapshot &shot_others,
136  XDriver *emitter) const {
137  shared_ptr<XSG> sg1__ = shot_this[ *sg1()];
138  if( !sg1__) return false;
139  shared_ptr<XNMRPulseAnalyzer> pulse__ = shot_this[ *pulse()];
140  if(emitter != pulse__.get()) return false;
141  if(shot_emitter[ *pulse__].timeAwared() < shot_others[ *sg1__].time()) return false;
142  double freq = getCurrentCenterFreq(shot_this, shot_others);
143  if(m_lastFreqAcquired == freq) {
144  return false; //skips for the same freq.
145  }
146  m_lastFreqAcquired = freq;
147  return true;
148 }
149 double
150 XNMRFSpectrum::getMinFreq(const Snapshot &shot_this) const{
151  double cfreq = shot_this[ *centerFreq()]; //MHz
152  double freq_span = shot_this[ *freqSpan()] * 1e-3; //MHz
153  return (cfreq - freq_span/2) * 1e6;
154 }
155 double
156 XNMRFSpectrum::getMaxFreq(const Snapshot &shot_this) const{
157  double cfreq = shot_this[ *centerFreq()]; //MHz
158  double freq_span = shot_this[ *freqSpan()] * 1e-3; //MHz
159  return (cfreq + freq_span/2) * 1e6;
160 }
161 double
162 XNMRFSpectrum::getFreqResHint(const Snapshot &shot_this) const {
163  return 1e-6;
164 }
165 double
166 XNMRFSpectrum::getCurrentCenterFreq(const Snapshot &shot_this, const Snapshot &shot_others) const {
167  shared_ptr<XSG> sg1__ = shot_this[ *sg1()];
168  assert( sg1__ );
169  assert(shot_others[ *sg1__].time() );
170  double freq = shot_others[ *sg1__].freq() - shot_this[ *sg1FreqOffset()]; //MHz
171  return freq * 1e6;
172 }
173 void
174 XNMRFSpectrum::performTuning(const Snapshot &shot_this, double newf) {
175  if((shot_this[ *tuneCycleStrategy()] != STRATEGY_AUTOTUNE) ||
176  (shot_this[ *tuneCycleStrategy()] != STRATEGY_TUNE_AWAIT))
177  return; //tuning is declined by user.
178 
179  if(fabs(m_tunedFreq - newf) <= shot_this[ *tuneCycleStep()] / 2 * 1e-3)
180  return; //not needed yet
181 
182  newf += shot_this[ *tuneCycleStep()] / 2 * 1e-3; //to be tuned to
183 
184  shared_ptr<XPulser> pulser__ = shot_this[ *pulser()];
185  if( !pulser__) {
186  gWarnPrint(i18n("Pulser should be selected."));
187  return;
188  }
189  //Tunes Capacitors.
190  trans( *pulser__->output()) = false; // Pulse off.
191  shared_ptr<XNMRPulseAnalyzer> pulse__ = shot_this[ *pulse()];
192  if(pulse__)
193  trans( *pulse__->avgClear()).touch();
194 
195  if((shot_this[ *tuneCycleStrategy()] == STRATEGY_TUNE_AWAIT)) {
196  g_statusPrinter->printMessage(getLabel() + " " + i18n("Tune it by yourself to") +
197  formatString(" %.3f~MHz", newf) + i18n(", and turn pulse on again."), true, __FILE__, __LINE__, true);
198  }
199  if((shot_this[ *tuneCycleStrategy()] == STRATEGY_AUTOTUNE)) {
200  shared_ptr<XAutoLCTuner> autotuner = shot_this[ *autoTuner()];
201  if( !autotuner) {
202  gWarnPrint(i18n("AutoTuner should be selected."));
203  return;
204  }
205  autotuner->iterate_commit([=](Transaction &tr){
206  m_lsnOnTuningChanged = tr[ *autotuner->tuning()].onValueChanged().connectWeakly(
207  shared_from_this(), &XNMRFSpectrum::onTuningChanged);
208  tr[ *autotuner->target()] = newf;
209  });
210  }
211  m_tunedFreq = newf;
212 }
213 void
214 XNMRFSpectrum::rearrangeInstrum(const Snapshot &shot_this) {
215  m_lsnOnTuningChanged.reset();
216  //set new freq
217  if(shot_this[ *active()]) {
218  shared_ptr<XSG> sg1__ = shot_this[ *sg1()];
219  if( ! sg1__)
220  return;
221  Snapshot shot_sg( *sg1__);
222  if( !shot_sg[ *sg1__].time())
223  return;
224 
225  double freq = getCurrentCenterFreq(shot_this, shot_sg) * 1e-6;
226 
227  double cfreq = shot_this[ *centerFreq()]; //MHz
228  double freq_span = shot_this[ *freqSpan()] * 1e-3; //MHz
229  if(cfreq <= freq_span / 2) {
230  throw XRecordError(i18n("Invalid center freq."), __FILE__, __LINE__);
231  }
232 
233  double freq_step = shot_this[ *tuneCycleStep()] * 1e-3; //MHz
234  int num_psk_cycles = 0;
235  switch(shot_this[ *tuneCycleStrategy()]) {
236  default:
237  freq_step = shot_this[ *freqStep()] * 1e-3; //MHz
238  break;
239  case STRATEGY_CYCLE_DBL:
240  num_psk_cycles = 2; break;
241  case STRATEGY_CYCLE_QUAD:
242  num_psk_cycles = 4; break;
243  case STRATEGY_CYCLE_OCT:
244  num_psk_cycles = 8; break;
245  }
246  if(freq_span < freq_step * 1.5) {
247  throw XRecordError(i18n("Too large freq. step."), __FILE__, __LINE__);
248  }
249 
250  double newf = freq; //MHz
251  newf += freq_step;
252 
253  if(newf >= getMaxFreq(shot_this) * 1e-6) {
254  double x = (newf - getMinFreq(shot_this) * 1e-6) / freq_step;
255  newf -= floor(x + 0.01) * freq_step; //the first freq of this cycle.
256  ++m_lastCycle;
257  if(m_lastCycle >= num_psk_cycles) {
258  m_lastCycle = 0;
259  newf += shot_this[ *freqStep()] * 1e-3; //shifted.
260  if((newf - getMinFreq(shot_this) * 1e-6) / freq_step > 0.99) {
261  trans( *active()) = false; //finish
262  return;
263  }
264  }
265  shared_ptr<XPulser> pulser__ = shot_this[ *pulser()];
266  if( !pulser__)
267  throw XRecordError(i18n("Pulser should be selected."), __FILE__, __LINE__);
268  if( ***pulser__->rtime() < 1000)
269  throw XRecordError(i18n("Too short repetition period."), __FILE__, __LINE__);
270  pulser__->iterate_commit([=](Transaction &tr){
271  tr[ *pulser__->firstPhase()] = m_lastCycle % 4;
272  tr[ *pulser__->invertPhase()] = (m_lastCycle / 4) ? true : false;
273  });
274  }
275 
276  newf = round(newf * 1e8) / 1e8; //rounds
277 
278  performTuning(shot_this, newf); //tunes a circuit if needed.
279 
280  newf += shot_this[ *sg1FreqOffset()]; //modifies SG freq.
281  if(sg1__)
282  trans( *sg1__->freq()) = newf;
283  }
284 }
285 void
287  Snapshot shot_this( *this);
288  shared_ptr<XPulser> pulser__ = shot_this[ *pulser()];
289  if( !pulser__) return;
290 // if(shot_this[ *tuneStrategy()] != TUNESTRATEGY_AUTOTUNER) return;
291  {
292  shared_ptr<XAutoLCTuner> autotuner = shot_this[ *autoTuner()];
293  if(autotuner) {
294  Snapshot shot_tuner( *autotuner);
295  if(shot_tuner[ *autotuner->tuning()])
296  return; //still tuner is running.
297  if( !shot_tuner[ *autotuner->succeeded()])
298  return; //awaiting manual tuning.
299  }
300  }
301  m_lsnOnTuningChanged.reset();
302  if(shot_this[ *active()]) {
303  //Tuning has succeeded, go on.
304  trans( *pulser__->output()) = true; // Pulse on.
305  }
306 }
307 void
308 XNMRFSpectrum::getValues(const Snapshot &shot_this, std::vector<double> &values) const {
309  int wave_size = shot_this[ *this].wave().size();
310  double min__ = shot_this[ *this].min();
311  double res = shot_this[ *this].res();
312  values.resize(wave_size);
313  for(unsigned int i = 0; i < wave_size; i++) {
314  double freq = min__ + i * res;
315  values[i] = freq * 1e-6;
316  }
317 }

Generated for KAME4 by  doxygen 1.8.3