pulseanalyzer.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 "pulseanalyzer.h"
16 #include "analyzer.h"
17 
18 REGISTER_TYPE(XDriverList, NMRBuiltInNetworkAnalyzer, "NMR Built-In Network Analyzer");
19 
20 XNMRBuiltInNetworkAnalyzer::XNMRBuiltInNetworkAnalyzer(const char *name, bool runtime,
21  Transaction &tr_meas, const shared_ptr<XMeasure> &meas) :
22  XSecondaryDriverInterface<XNetworkAnalyzer>(name, runtime, ref(tr_meas), meas),
23  m_pulser(create<XItemNode<XDriverList, XPulser> >("Pulser", false, ref(tr_meas), meas->drivers(), true)),
24  m_dso(create<XItemNode<XDriverList, XDSO> >("DSO", false, ref(tr_meas), meas->drivers(), true)),
25  m_sg(create<XItemNode<XDriverList, XSG> >("SG", false, ref(tr_meas), meas->drivers(), true)) {
26  connect(m_dso);
27  connect(m_pulser);
28  connect(m_sg);
29 
30  iterate_commit([=](Transaction &tr){
31  const char *cand[] = {"OFF", "11", "21", "51", "101", "201", "401", "801", "1601", "3201", ""};
32  for(const char **it = cand; strlen( *it); it++) {
33  tr[ *points()].add( *it);
34  }
35  tr[ *this].m_sweeping = false;
36  });
38 }
39 void
40 XNMRBuiltInNetworkAnalyzer::clear() {
41  restart(CAL_NONE, true);
42 }
43 void
44 XNMRBuiltInNetworkAnalyzer::onCalOpenTouched(const Snapshot &shot, XTouchableNode *) {
45  restart(CAL_OPEN);
46 }
47 void
48 XNMRBuiltInNetworkAnalyzer::onCalShortTouched(const Snapshot &shot, XTouchableNode *) {
49  restart(CAL_SHORT);
50 }
51 void
52 XNMRBuiltInNetworkAnalyzer::onCalTermTouched(const Snapshot &shot, XTouchableNode *) {
53  restart(CAL_TERM);
54 }
55 void
56 XNMRBuiltInNetworkAnalyzer::onCalThruTouched(const Snapshot &shot, XTouchableNode *) {
57  restart(CAL_THRU);
58 }
59 void
60 XNMRBuiltInNetworkAnalyzer::onStartFreqChanged(const Snapshot &shot, XValueNodeBase *) {
61  clear();
62 }
63 void
64 XNMRBuiltInNetworkAnalyzer::onStopFreqChanged(const Snapshot &shot, XValueNodeBase *) {
65  clear();
66 }
67 void
68 XNMRBuiltInNetworkAnalyzer::onAverageChanged(const Snapshot &shot, XValueNodeBase *) {
69  clear();
70 }
71 void
72 XNMRBuiltInNetworkAnalyzer::onPointsChanged(const Snapshot &shot, XValueNodeBase *) {
73  clear();
74  int pts = atoi(Snapshot( *this)[ *points()].to_str().c_str());
75  if( !pts){
76  try {
77  startContSweep();
78  }
79  catch (XInterface::XInterfaceError &e) {
80  gErrPrint(e.msg());
81  }
82 // stop();
83  }
84 }
85 void
86 XNMRBuiltInNetworkAnalyzer::getMarkerPos(unsigned int num, double &x, double &y) {
87  Snapshot shot( *this);
88  switch(num) {
89  case 0:
90  x = shot[ *this].m_marker_min.first;
91  y = shot[ *this].m_marker_min.second;
92  break;
93  case 1:
94  x = shot[ *this].m_marker_max.first;
95  y = shot[ *this].m_marker_max.second;
96  break;
97  default:
98  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
99  }
100 }
101 void
102 XNMRBuiltInNetworkAnalyzer::oneSweep() {
103  bool ret = restart(CAL_NONE);
104  if( !ret)
105  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
106  while(Snapshot( *this)[ *this].m_sweeping) {
107  msecsleep(30);
108  }
109 }
110 bool
111 XNMRBuiltInNetworkAnalyzer::restart(int calmode, bool clear) {
112  bool ret = false;
113  iterate_commit([=, &ret](Transaction &tr){
114  try {
115  ret = false;
116  restart(tr, calmode, clear);
117  ret = true;
118  }
119  catch (XDriver::XSkippedRecordError &) {
120  }
121  catch (XInterface::XInterfaceError &e) {
122  gErrPrint(e.msg());
123  }
124  });
125  return ret;
126 }
127 void
128 XNMRBuiltInNetworkAnalyzer::restart(Transaction &tr, int calmode, bool clear) {
129  Snapshot &shot_this(tr);
130 
131  int pts = atoi(shot_this[ *points()].to_str().c_str());
132  tr[ *this].m_sweepPoints = pts;
133  if( !pts)
134  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
135 
136  tr[ *this].m_ftsum.clear();
137  tr[ *this].m_ftsum_weight.clear();
138  tr[ *this].m_calMode = calmode;
139  if(clear || tr[ *this].m_raw_open.empty()) {
140  tr[ *this].m_raw_open.clear();
141  tr[ *this].m_raw_short.clear();
142  tr[ *this].m_raw_term.clear();
143  tr[ *this].m_raw_thru.clear();
144  tr[ *this].m_raw_open.resize(pts, 1.0);
145  tr[ *this].m_raw_short.resize(pts, -1.0);
146  tr[ *this].m_raw_term.resize(pts, 0.0);
147  tr[ *this].m_raw_thru.resize(pts, 1.0);
148  }
149 
150  shared_ptr<XPulser> pulse = shot_this[ *m_pulser];
151  if( !pulse)
152  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
153  shared_ptr<XSG> sg = shot_this[ *m_sg];
154  if( !sg)
155  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
156  shared_ptr<XDSO> dso = shot_this[ *m_dso];
157  if( !dso)
158  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
159 
160  Snapshot shot_dso( *dso);
161  double interval;
162  int dso_len;
163  if( !shot_dso[ *dso].time() || !shot_dso[ *dso].numChannels()) {
164  interval = 1e-6; //temporary
165  dso_len = 10000; //temporary
166  }
167  else {
168  interval = shot_dso[ *dso].timeInterval();
169  dso_len = shot_dso[ *dso].length();
170  }
171 
172  double fmax = shot_this[ *stopFreq()];
173  tr[ *this].m_sweepStop = fmax;
174  double fmin = shot_this[ *startFreq()];
175  tr[ *this].m_sweepStart = fmin;
176  if((fmax <= fmin) || (fmin <= 0.1))
177  throw XDriver::XSkippedRecordError(i18n("Invalid frequency settings"), __FILE__, __LINE__);
178 
179  pulse->iterate_commit([=, &tr](Transaction &trp){
180  double plsbw = trp[ *pulse].paPulseBW() * 1e-3; //[MHz]
181  double fstep = plsbw *1.0;
182  fstep = std::max(fstep, (fmax - fmin) / (pts - 1));
183  if(fstep < 0.001)
184  throw XDriver::XSkippedRecordError(i18n("Invalid frequency settings"), __FILE__, __LINE__);
185  tr[ *this].m_sweepStep = fstep;
186  trp[ *pulse->pulseAnalyzerMode()] = true;
187  double rept_ms = std::max(2.0 / ((fmax - fmin) / (pts - 1)) * 1e-3 * 2, 0.2);
188  rept_ms = interval * 1e3 * lrint(rept_ms / (interval * 1e3)); //round to DSO interval.
189  trp[ *pulse->paPulseRept()] = rept_ms;
190  trp[ *pulse->output()] = true;
191  });
192 
193  trans( *sg->freq()) = fmin;
194 
195  dso->iterate_commit([=](Transaction &trd){
196  int avg = std::max(1L, lrint(0.03 / (interval * dso_len)));
197  avg *= std::max(1u, (unsigned int)shot_this[ *average()]);
198  trd[ *dso->average()] = (avg + 3) / 4 * 4; //round to phase cycling for NMR.
199  trd[ *dso->firEnabled()] = false;
200  trd[ *dso->restart()].touch(); //Restart averaging in DSO.
201  });
202 
203  tr[ *this].m_sweeping = true;
204 }
205 void
206 XNMRBuiltInNetworkAnalyzer::startContSweep() {
207  Snapshot shot_this( *this);
208  shared_ptr<XPulser> pulse = shot_this[ *m_pulser];
209  if(pulse) {
210  pulse->iterate_commit([=](Transaction &tr){
211  tr[ *pulse->pulseAnalyzerMode()] = false;
212  tr[ *pulse->output()] = false;
213  });
214  }
215  shared_ptr<XSG> sg = shot_this[ *m_sg];
216  if(sg) {
217  trans( *sg->freq()) = (double)shot_this[ *this].m_marker_min.first;
218  }
219 }
220 void
221 XNMRBuiltInNetworkAnalyzer::acquireTrace(shared_ptr<RawData> &, unsigned int ch) {
222 
223 }
224 void
226 }
227 void
228 XNMRBuiltInNetworkAnalyzer::writeTraceAndMarkers(Transaction &tr) {
229  Snapshot &shot_this(tr);
230  double fmin = shot_this[ *this].m_sweepStart;
231  double fmax = shot_this[ *this].m_sweepStop;
232  int pts = shot_this[ *this].m_sweepPoints;
233 // if( !pts)
234 // throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
235 
236  tr[ *this].m_startFreq = fmin;
237  double df = (fmax - fmin) / (pts - 1);
238  tr[ *this].m_freqInterval = df;
239  tr[ *this].trace_().resize(pts);
240 
241  auto ftsum = &tr[ *this].m_ftsum[0];
242  auto ftsum_weight = &tr[ *this].m_ftsum_weight[0];
243  for(unsigned int i = 0; i < pts; i++) {
244  ftsum[i] /= ftsum_weight[i];
245  }
246 
247  //Stores calibration curves.
248  switch(tr[ *this].m_calMode) {
249  case CAL_NONE:
250  break;
251  case CAL_OPEN:
252  tr[ *this].m_raw_open.resize(pts);
253  std::copy(tr[ *this].m_ftsum.begin(), tr[ *this].m_ftsum.end(), tr[ *this].m_raw_open.begin());
254  break;
255  case CAL_SHORT:
256  tr[ *this].m_raw_short.resize(pts);
257  std::copy(tr[ *this].m_ftsum.begin(), tr[ *this].m_ftsum.end(), tr[ *this].m_raw_short.begin());
258  break;
259  case CAL_TERM:
260  tr[ *this].m_raw_term.resize(pts);
261  std::copy(tr[ *this].m_ftsum.begin(), tr[ *this].m_ftsum.end(), tr[ *this].m_raw_term.begin());
262  break;
263  case CAL_THRU:
264  tr[ *this].m_raw_thru.resize(pts);
265  std::copy(tr[ *this].m_ftsum.begin(), tr[ *this].m_ftsum.end(), tr[ *this].m_raw_thru.begin());
266  break;
267  }
268 
269  auto rawopen = &tr[ *this].m_raw_open[0];
270  auto rawshort = &tr[ *this].m_raw_short[0];
271  auto rawterm = &tr[ *this].m_raw_term[0];
272  auto trace = &tr[ *this].trace_()[0];
273  for(unsigned int i = 0; i < pts; i++) {
274  auto zport_in = - rawopen[i] / rawshort[i]; //Impedance of the port connected to LNA.
275  auto s11_dut = 1.0 - 2.0 / ((1.0 + zport_in) / (1.0 - (ftsum[i] - rawterm[i]) / rawopen[i]) + 1.0 - zport_in);
276  trace[i] = s11_dut;
277  }
278 
279  //Tracking markers.
280  auto &mkmin = tr[ *this].m_marker_min;
281  mkmin.second = 1000;
282  auto &mkmax = tr[ *this].m_marker_max;
283  mkmax.second = -1000;
284  auto z = tr[ *this].trace();
285  for(unsigned int i = 0; i < pts; i++) {
286  double r = 20.0 * log10(std::abs( *z++));
287  if(r < mkmin.second)
288  mkmin = std::pair<double, double>(i * df + fmin, r);
289  if(r > mkmax.second)
290  mkmax = std::pair<double, double>(i * df + fmin, r);
291  }
292 }
293 void
295 
296 }
297 bool
299  const Snapshot &shot_emitter, const Snapshot &shot_others,
300  XDriver *emitter) const {
301  if( !shot_this[ *this].m_sweeping)
302  return false;
303  shared_ptr<XPulser> pulse = shot_this[ *m_pulser];
304  if( !pulse) return false;
305  shared_ptr<XDSO> dso = shot_this[ *m_dso];
306  if( !dso) return false;
307  shared_ptr<XSG> sg = shot_this[ *m_sg];
308  if( !sg) return false;
309  if(emitter != dso.get())
310  return false;
311  if(shot_emitter[ *dso].timeAwared() < shot_others[ *sg].time()) return false;
312  return true;
313 }
314 void
315 XNMRBuiltInNetworkAnalyzer::analyze(Transaction &tr, const Snapshot &shot_emitter, const Snapshot &shot_others,
316  XDriver *emitter) throw (XRecordError&) {
317  const Snapshot &shot_this(tr);
318  int pts = shot_this[ *this].m_sweepPoints;
319  if( !pts) {
320  tr[ *this].m_sweeping = false;
321  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
322  }
323 
324  const Snapshot &shot_dso(shot_emitter);
325  const Snapshot &shot_sg(shot_others);
326  const Snapshot &shot_pulse(shot_others);
327  shared_ptr<XPulser> pulse = shot_this[ *m_pulser];
328  shared_ptr<XDSO> dso = shot_this[ *m_dso];
329  shared_ptr<XSG> sg = shot_this[ *m_sg];
330 
331  assert(shot_dso[ *dso].time() );
332 
333  if(shot_dso[ *dso].numChannels() < 1) {
334  throw XSkippedRecordError(i18n("No record in DSO"), __FILE__, __LINE__);
335  }
336  if(shot_dso[ *dso].numChannels() < 2) {
337  throw XSkippedRecordError(i18n("Two channels needed in DSO"), __FILE__, __LINE__);
338  }
339  if( !shot_dso[ *dso->singleSequence()]) {
340  g_statusPrinter->printWarning(i18n("Use sequential average in DSO."));
341  }
342  int dso_len = shot_dso[ *dso].length();
343 
344  double interval = shot_dso[ *dso].timeInterval();
345  if (interval <= 0) {
346  throw XSkippedRecordError(i18n("Invalid time interval in waveforms."), __FILE__, __LINE__);
347  }
348  int pos = lrint(shot_dso[ *dso].trigPos());
349  if(pos >= dso_len) {
350  throw XSkippedRecordError(i18n("Position beyond waveforms."), __FILE__, __LINE__);
351  }
352  if(pos < 0) {
353  throw XSkippedRecordError(i18n("Position beyond waveforms."), __FILE__, __LINE__);
354  }
355 
356  if(pulse) {
357  if( !shot_pulse[ *pulse].isPulseAnalyzerMode())
358  throw XSkippedRecordError(i18n("Pulser configured not in Built-In Network Analyzer Mode."), __FILE__, __LINE__);
359  }
360  double rept = shot_pulse[ *pulse].rtime() * 1e-3; //[s]
361  double plsorg = shot_pulse[ *pulse].paPulseOrigin() * 1e-6; //[s]
362 
363  double fmin = shot_this[ *this].m_sweepStart;
364  double fmax = shot_this[ *this].m_sweepStop;
365 
366  unsigned int fftlen = (unsigned int)floor(std::max(plsorg / interval, 1e-6 / ((fmax - fmin) / (pts - 1)) / interval * 2));
367  fftlen = FFT::fitLength(std::min(fftlen, (unsigned int)floor(rept / interval)));
368  if( !m_fft || m_fft->length() != fftlen) {
369  m_fft.reset(new FFT(-1, fftlen));
370  m_fftin.resize(fftlen);
371  m_fftout.resize(fftlen);
372  }
373  std::fill(m_fftin.begin(), m_fftin.end(), 0.0);
374  unsigned int avg_in_wave = floor((dso_len - pos) / (rept / interval));
375  if(avg_in_wave < 2)
376  throw XSkippedRecordError(i18n("Too short waveforms."), __FILE__, __LINE__);
377  avg_in_wave = avg_in_wave / 2 * 2;
378 
379  for(unsigned int av = 0; av < avg_in_wave; ++av) {
380  int lpos = lrint(pos + (rept * av) / interval);
381  int org = lrint(pos + (plsorg + rept * av) / interval);
382  bool inverted = (av % 2 == 1);
383  const double *wavecos = &shot_dso[ *dso].wave(0)[lpos];
384  const double *wavesin = &shot_dso[ *dso].wave(1)[lpos];
385  for(unsigned int i = fftlen - (org - lpos); i < fftlen; ++i) {
386  m_fftin[i] += std::complex<double>( *wavecos++, *wavesin++) * (inverted ? -1.0 : 1.0);
387  }
388  for(unsigned int i = 0; i < fftlen - (org - lpos); ++i) {
389  m_fftin[i] += std::complex<double>( *wavecos++, *wavesin++) * (inverted ? -1.0 : 1.0);
390  }
391  }
392  double fft_df = 1.0 / (interval * fftlen) * 1e-6; //[MHz]
393  m_fft->exec(m_fftin, m_fftout);
394 
395  double plsbw = shot_pulse[ *pulse].paPulseBW() * 1e-3; //[MHz]
396 
397  if(tr[ *this].m_ftsum.size() != pts) {
398  tr[ *this].m_ftsum.resize(pts);
399  tr[ *this].m_ftsum_weight.resize(pts);
400  std::fill(tr[ *this].m_ftsum.begin(), tr[ *this].m_ftsum.end(), 0.0);
401  std::fill(tr[ *this].m_ftsum_weight.begin(), tr[ *this].m_ftsum_weight.end(), 0);
402  }
403  double freq = shot_sg[ *sg].freq();
404  tr[ *this].m_lastCenterFreq = freq;
405  if(freq < fmin - plsbw/2) {
406  restart(tr, shot_this[ *this].m_calMode);
407  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
408  }
409  double normalize = 1.0 / avg_in_wave / fftlen;
410  auto ftsum = &tr[ *this].m_ftsum[0];
411  auto ftsum_weight = &tr[ *this].m_ftsum_weight[0];
412  for(int i = 0; i < fftlen; ++i) {
413  double f = fft_df * ((i >= fftlen / 2) ? i - (int)fftlen : i);
414  if(abs(f) > plsbw / 2)
415  continue;
416  f += freq;
417  int j = lrint((f - fmin) / (fmax - fmin) * (pts - 1));
418  if((j < 0) || (j >= pts))
419  continue;
420  ftsum[j] += m_fftout[i] * normalize;
421  ++ftsum_weight[j];
422  }
423  if( !shot_this[ *this].m_ftsum.size()) {
424  restart(tr, shot_this[ *this].m_calMode);
425  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
426  }
427  double fstep = shot_this[ *this].m_sweepStep;
428  if(freq + fstep / 2 > fmax) {
429  writeTraceAndMarkers(tr);
430  tr[ *this].m_sweeping = false;
431  }
432  throw XDriver::XSkippedRecordError(__FILE__, __LINE__);
433 }
434 void
436  if(shot[ *this].m_sweeping) {
437  double freq = shot[ *this].m_lastCenterFreq;
438  double fstep = shot[ *this].m_sweepStep;
439 
440  freq += fstep;
441  shared_ptr<XSG> sg = shot[ *m_sg];
442  assert(sg);
443  trans( *sg->freq()) = freq; //setting new freq.
444  }
445  else
447 }
448 

Generated for KAME4 by  doxygen 1.8.3