16 #include "ui_nmrpulseform.h"
17 #include "freqestleastsquare.h"
21 #include "graphwidget.h"
22 #include "ui_graphnurlform.h"
24 #include "xnodeconnector.h"
26 REGISTER_TYPE(
XDriverList, NMRPulseAnalyzer,
"NMR FID/echo analyzer");
29 XNMRPulseAnalyzer::XNMRPulseAnalyzer(
const char *name,
bool runtime,
30 Transaction &tr_meas,
const shared_ptr<XMeasure> &meas) :
33 dynamic_pointer_cast<
XDriver>(shared_from_this()))),
35 dynamic_pointer_cast<
XDriver>(shared_from_this()))),
40 m_usePNR(create<
XBoolNode>(
"UsePNR", false)),
41 m_pnrSolverList(create<
XComboNode>(
"PNRSpectrumSolver", false, true)),
42 m_solverList(create<
XComboNode>(
"SpectrumSolver", false, true)),
46 m_fftLen(create<
XUIntNode>(
"FFTLen", false)),
47 m_windowFunc(create<
XComboNode>(
"WindowFunc", false, true)),
48 m_windowWidth(create<
XDoubleNode>(
"WindowLength", false)),
50 m_exAvgIncr(create<
XBoolNode>(
"ExAvgIncr", false)),
51 m_extraAvg(create<
XUIntNode>(
"ExtraAvg", false)),
52 m_numEcho(create<
XUIntNode>(
"NumEcho", false)),
53 m_echoPeriod(create<
XDoubleNode>(
"EchoPeriod", false)),
56 m_picEnabled(create<
XBoolNode>(
"PICEnabled", false)),
61 m_form->m_graph, m_form->m_edDump, m_form->m_tbDump, m_form->m_btnDump)),
62 m_ftWaveGraph(create<
XWaveNGraph>(
"Spectrum", true, m_spectrumForm.get())),
63 m_solver(create<
SpectrumSolverWrapper>(
"SpectrumSolverWrapper", true, m_solverList, m_windowFunc, m_windowWidth)),
65 m_form->m_btnAvgClear->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogResetButton));
66 m_form->m_btnSpectrum->setIcon( *g_pIconGraph);
71 meas->scalarEntries()->insert(tr_meas, entryPeakAbs());
72 meas->scalarEntries()->insert(tr_meas, entryPeakFreq());
75 tr[ *m_pnrSolverList].str(
XString(SpectrumSolverWrapper::SPECTRUM_SOLVER_LS_MDL));
76 tr[ *fromTrig()] = -0.005;
79 tr[ *bgWidth()] = 0.03;
80 tr[ *fftPos()] = 0.004;
81 tr[ *fftLen()] = 16384;
87 m_form->setWindowTitle(i18n(
"NMR Pulse - ") + getLabel() );
89 m_spectrumForm->setWindowTitle(i18n(
"NMR-Spectrum - ") + getLabel() );
91 m_form->m_dblWindowWidth->setRange(3.0, 200.0);
92 m_form->m_dblWindowWidth->setSingleStep(1.0);
93 m_form->m_numExtraAvg->setRange(0, 100000);
94 m_form->m_dblPhaseAdv->setRange(-180.0, 180.0);
95 m_form->m_dblPhaseAdv->setSingleStep(10.0);
98 xqcon_create<XQButtonConnector>(m_avgClear, m_form->m_btnAvgClear),
99 xqcon_create<XQButtonConnector>(m_spectrumShow, m_form->m_btnSpectrum),
100 xqcon_create<XQLineEditConnector>(fromTrig(), m_form->m_edPos),
101 xqcon_create<XQLineEditConnector>(width(), m_form->m_edWidth),
102 xqcon_create<XQDoubleSpinBoxConnector>(phaseAdv(), m_form->m_dblPhaseAdv, m_form->m_slPhaseAdv),
103 xqcon_create<XQToggleButtonConnector>(usePNR(), m_form->m_ckbPNR),
104 xqcon_create<XQComboBoxConnector>(pnrSolverList(), m_form->m_cmbPNRSolver,
Snapshot( *pnrSolverList())),
106 xqcon_create<XQLineEditConnector>(bgPos(), m_form->m_edBGPos),
107 xqcon_create<XQLineEditConnector>(bgWidth(), m_form->m_edBGWidth),
108 xqcon_create<XQLineEditConnector>(fftPos(), m_form->m_edFFTPos),
109 xqcon_create<XQLineEditConnector>(fftLen(), m_form->m_edFFTLen),
110 xqcon_create<XQSpinBoxUnsignedConnector>(extraAvg(), m_form->m_numExtraAvg),
111 xqcon_create<XQToggleButtonConnector>(exAvgIncr(), m_form->m_ckbIncrAvg),
112 xqcon_create<XQSpinBoxUnsignedConnector>(numEcho(), m_form->m_numEcho),
113 xqcon_create<XQLineEditConnector>(echoPeriod(), m_form->m_edEchoPeriod),
115 xqcon_create<XQDoubleSpinBoxConnector>(
windowWidth(), m_form->m_dblWindowWidth, m_form->m_slWindowWIdth),
116 xqcon_create<XQLineEditConnector>(difFreq(), m_form->m_edDIFFreq),
117 xqcon_create<XQToggleButtonConnector>(m_picEnabled, m_form->m_ckbPICEnabled),
118 xqcon_create<XQComboBoxConnector>(m_pulser, m_form->m_cmbPulser, ref(tr_meas)),
119 xqcon_create<XQComboBoxConnector>(dso(), m_form->m_cmbDSO, ref(tr_meas))
123 const char *labels[] = {
"Time [ms]",
"IFFT Re [V]",
"IFFT Im [V]",
"DSO CH1[V]",
"DSO CH2[V]"};
124 tr[ *waveGraph()].setColCount(5, labels);
125 tr[ *waveGraph()].insertPlot(labels[1], 0, 1);
126 tr[ *waveGraph()].insertPlot(labels[2], 0, 2);
127 tr[ *waveGraph()].insertPlot(labels[3], 0, 3);
128 tr[ *waveGraph()].insertPlot(labels[4], 0, 4);
129 tr[ *tr[ *waveGraph()].axisy()->label()] = i18n(
"Intens. [V]");
130 tr[ *tr[ *waveGraph()].plot(0)->label()] = i18n(
"IFFT Re.");
131 tr[ *tr[ *waveGraph()].plot(0)->drawPoints()] =
false;
132 tr[ *tr[ *waveGraph()].plot(0)->lineColor()] = QColor(0xcc, 0x00, 0x80).rgb();
133 tr[ *tr[ *waveGraph()].plot(0)->intensity()] = 2.0;
134 tr[ *tr[ *waveGraph()].plot(1)->label()] = i18n(
"IFFT Im.");
135 tr[ *tr[ *waveGraph()].plot(1)->drawPoints()] =
false;
136 tr[ *tr[ *waveGraph()].plot(1)->intensity()] = 2.0;
137 tr[ *tr[ *waveGraph()].plot(1)->lineColor()] = QColor(0x00, 170, 0x00).rgb();
138 tr[ *tr[ *waveGraph()].plot(2)->label()] = i18n(
"DSO CH1");
139 tr[ *tr[ *waveGraph()].plot(2)->drawPoints()] =
false;
140 tr[ *tr[ *waveGraph()].plot(2)->lineColor()] = QColor(0xff, 0xa0, 0x00).rgb();
141 tr[ *tr[ *waveGraph()].plot(2)->intensity()] = 0.3;
142 tr[ *tr[ *waveGraph()].plot(3)->label()] = i18n(
"DSO CH2");
143 tr[ *tr[ *waveGraph()].plot(3)->drawPoints()] =
false;
144 tr[ *tr[ *waveGraph()].plot(3)->lineColor()] = QColor(0x00, 0xa0, 0xff).rgb();
145 tr[ *tr[ *waveGraph()].plot(3)->intensity()] = 0.3;
146 tr[ *waveGraph()].clearPoints();
148 ftWaveGraph()->iterate_commit([=](
Transaction &tr){
149 const char *labels[] = {
"Freq. [kHz]",
"Re. [V]",
"Im. [V]",
150 "Abs. [V]",
"Phase [deg]",
"Dark. [V]" };
151 tr[ *ftWaveGraph()].setColCount(6, labels);
152 tr[ *ftWaveGraph()].insertPlot(labels[3], 0, 3);
153 tr[ *ftWaveGraph()].insertPlot(labels[4], 0, -1, 4);
154 tr[ *ftWaveGraph()].insertPlot(labels[5], 0, 5);
155 tr[ *tr[ *ftWaveGraph()].axisy()->label()] = i18n(
"Intens. [V]");
156 tr[ *tr[ *ftWaveGraph()].plot(0)->label()] = i18n(
"abs.");
157 tr[ *tr[ *ftWaveGraph()].plot(0)->drawBars()] =
true;
158 tr[ *tr[ *ftWaveGraph()].plot(0)->drawLines()] =
true;
159 tr[ *tr[ *ftWaveGraph()].plot(0)->drawPoints()] =
false;
160 tr[ *tr[ *ftWaveGraph()].plot(0)->intensity()] = 0.5;
161 tr[ *tr[ *ftWaveGraph()].plot(1)->label()] = i18n(
"phase");
162 tr[ *tr[ *ftWaveGraph()].plot(1)->drawPoints()] =
false;
163 tr[ *tr[ *ftWaveGraph()].plot(1)->intensity()] = 0.3;
164 tr[ *tr[ *ftWaveGraph()].plot(2)->label()] = i18n(
"dark");
165 tr[ *tr[ *ftWaveGraph()].plot(2)->drawBars()] =
false;
166 tr[ *tr[ *ftWaveGraph()].plot(2)->drawLines()] =
true;
167 tr[ *tr[ *ftWaveGraph()].plot(2)->lineColor()] = QColor(0xa0, 0xa0, 0x00).rgb();
168 tr[ *tr[ *ftWaveGraph()].plot(2)->drawPoints()] =
false;
169 tr[ *tr[ *ftWaveGraph()].plot(2)->intensity()] = 0.5;
171 shared_ptr<XXYPlot> plot = ftWaveGraph()->graph()->plots()->create<
XXYPlot>(
172 tr,
"Peaks",
true, ref(tr), ftWaveGraph()->graph());
174 tr[ *plot->label()] = i18n(
"Peaks");
175 tr[ *plot->axisX()] = tr[ *ftWaveGraph()].axisx();
176 tr[ *plot->axisY()] = tr[ *ftWaveGraph()].axisy();
177 tr[ *plot->drawPoints()] =
false;
178 tr[ *plot->drawLines()] =
false;
179 tr[ *plot->drawBars()] =
true;
180 tr[ *plot->intensity()] = 0.5;
181 tr[ *plot->displayMajorGrid()] =
false;
182 tr[ *plot->pointColor()] = QColor(0x40, 0x40, 0xa0).rgb();
183 tr[ *plot->barColor()] = QColor(0x40, 0x40, 0xa0).rgb();
187 tr[ *ftWaveGraph()].clearPoints();
191 m_lsnOnAvgClear = tr[ *m_avgClear].onTouch().connectWeakly(
192 shared_from_this(), &XNMRPulseAnalyzer::onAvgClear);
193 m_lsnOnSpectrumShow = tr[ *m_spectrumShow].onTouch().connectWeakly(
194 shared_from_this(), &XNMRPulseAnalyzer::onSpectrumShow,
195 XListener::FLAG_MAIN_THREAD_CALL | XListener::FLAG_AVOID_DUP);
197 m_lsnOnCondChanged = tr[ *fromTrig()].onValueChanged().connectWeakly(
198 shared_from_this(), &XNMRPulseAnalyzer::onCondChanged);
199 tr[ *width()].onValueChanged().connect(m_lsnOnCondChanged);
200 tr[ *phaseAdv()].onValueChanged().connect(m_lsnOnCondChanged);
201 tr[ *usePNR()].onValueChanged().connect(m_lsnOnCondChanged);
202 tr[ *pnrSolverList()].onValueChanged().connect(m_lsnOnCondChanged);
203 tr[ *
solverList()].onValueChanged().connect(m_lsnOnCondChanged);
204 tr[ *bgPos()].onValueChanged().connect(m_lsnOnCondChanged);
205 tr[ *bgWidth()].onValueChanged().connect(m_lsnOnCondChanged);
206 tr[ *fftPos()].onValueChanged().connect(m_lsnOnCondChanged);
207 tr[ *fftLen()].onValueChanged().connect(m_lsnOnCondChanged);
209 tr[ *exAvgIncr()].onValueChanged().connect(m_lsnOnCondChanged);
210 tr[ *numEcho()].onValueChanged().connect(m_lsnOnCondChanged);
211 tr[ *echoPeriod()].onValueChanged().connect(m_lsnOnCondChanged);
212 tr[ *
windowFunc()].onValueChanged().connect(m_lsnOnCondChanged);
213 tr[ *
windowWidth()].onValueChanged().connect(m_lsnOnCondChanged);
214 tr[ *difFreq()].onValueChanged().connect(m_lsnOnCondChanged);
217 XNMRPulseAnalyzer::~XNMRPulseAnalyzer() {
220 m_spectrumForm->showNormal();
221 m_spectrumForm->raise();
224 m_form->showNormal();
228 void XNMRPulseAnalyzer::backgroundSub(
Transaction &tr,
229 std::vector<std::complex<double> > &wave,
230 int pos,
int length,
int bgpos,
int bglength) {
233 std::complex<double> bg = 0;
235 double normalize = 0.0;
236 for(
int i = 0; i < bglength; i++) {
238 if( !shot[ *usePNR()])
239 z = FFT::windowFuncHamming( (
double)i / bglength - 0.5);
240 bg += z * wave[pos + i + bgpos];
246 for(
int i = 0; i < wave.size(); i++) {
252 if(shot[ *usePNR()]) {
254 std::vector<std::complex<double> > memin(bglength), memout(dnrlength);
255 for(
unsigned int i = 0; i < bglength; i++) {
256 memin[i] = wave[pos + i + bgpos];
259 solverPNR.exec(memin, memout, bgpos, 0.5e-2, &FFT::windowFuncRect, 1.0);
260 int imax = std::min((
int)wave.size() - pos, (int)memout.size());
261 for(
unsigned int i = 0; i < imax; i++) {
262 wave[i + pos] -= solverPNR.ifft()[i];
272 void XNMRPulseAnalyzer::rotNFFT(
Transaction &tr,
int ftpos,
double ph,
273 std::vector<std::complex<double> > &wave,
274 std::vector<std::complex<double> > &ftwave) {
277 int length = wave.size();
279 std::complex<double> cph(std::polar(1.0, ph));
280 for(
int i = 0; i < length; i++) {
284 int fftlen = ftwave.size();
286 std::vector<std::complex<double> > fftout(fftlen);
288 FFT::twindowfunc wndfunc = m_solver->windowFunc(shot);
291 solver.exec(wave, fftout, -ftpos, 0.3e-2, wndfunc, wndwidth);
294 throw XSkippedRecordError(e.msg(), __FILE__, __LINE__);
297 std::copy(fftout.begin(), fftout.end(), ftwave.begin());
300 std::vector<double> weight;
303 for(
int i = 0; i < length; i++)
304 w += weight[i] * weight[i];
305 tr[ *
this].m_ftWavePSDCoeff = w/(double)length;
308 tr[ *
this].m_ftWavePSDCoeff = 1.0;
312 trans( *this).m_timeClearRequested = XTime::now();
317 const shared_ptr<XDSO> dso__ = shot_this[ *dso()];
319 trans( *dso__->restart()).touch();
322 if(node == exAvgIncr().
get())
323 trans( *extraAvg()) = 0;
324 if((node == numEcho().
get()) || (node == difFreq().
get()) || (node == exAvgIncr().
get()))
325 onAvgClear(shot, avgClear().
get());
332 const shared_ptr<XPulser> pulse__ = shot_this[ *pulser()];
333 if (emitter == pulse__.get())
335 const shared_ptr<XDSO> dso__ = shot_this[ *dso()];
345 XDriver *emitter)
throw (XRecordError&) {
347 const shared_ptr<XDSO> dso__ = shot_this[ *dso()];
350 const Snapshot &shot_dso((emitter == dso__.get()) ? shot_emitter : shot_others);
351 assert(shot_dso[ *dso__].time() );
353 if(shot_dso[ *dso__].numChannels() < 1) {
354 throw XSkippedRecordError(i18n(
"No record in DSO"), __FILE__, __LINE__);
356 if(shot_dso[ *dso__].numChannels() < 2) {
357 throw XSkippedRecordError(i18n(
"Two channels needed in DSO"), __FILE__, __LINE__);
359 if( !shot_dso[ *dso__->singleSequence()]) {
360 m_statusPrinter->printWarning(i18n(
"Use sequential average in DSO."));
362 int dso_len = shot_dso[ *dso__].length();
364 double interval = shot_dso[ *dso__].timeInterval();
366 throw XSkippedRecordError(i18n(
"Invalid time interval in waveforms."), __FILE__, __LINE__);
368 int pos = lrint(shot_this[ *fromTrig()] *1e-3 / interval + shot_dso[ *dso__].trigPos());
369 double starttime = (pos - shot_dso[ *dso__].trigPos()) * interval;
371 throw XSkippedRecordError(i18n(
"Position beyond waveforms."), __FILE__, __LINE__);
374 throw XSkippedRecordError(i18n(
"Position beyond waveforms."), __FILE__, __LINE__);
376 int length = lrint( shot_this[ *width()] / 1000 / interval);
377 if(pos + length >= dso_len) {
378 throw XSkippedRecordError(i18n(
"Invalid length."), __FILE__, __LINE__);
381 throw XSkippedRecordError(i18n(
"Invalid length."), __FILE__, __LINE__);
384 int bgpos = lrint((shot_this[ *bgPos()] - shot_this[ *fromTrig()]) / 1000 / interval);
385 if(pos + bgpos >= dso_len) {
386 throw XSkippedRecordError(i18n(
"Position for BG. sub. beyond waveforms."), __FILE__, __LINE__);
389 throw XSkippedRecordError(i18n(
"Position for BG. sub. beyond waveforms."), __FILE__, __LINE__);
391 int bglength = lrint(shot_this[ *bgWidth()] / 1000 / interval);
392 if(pos + bgpos + bglength >= dso_len) {
393 throw XSkippedRecordError(i18n(
"Invalid Length for BG. sub."), __FILE__, __LINE__);
396 throw XSkippedRecordError(i18n(
"Invalid Length for BG. sub."), __FILE__, __LINE__);
399 shared_ptr<XPulser> pulse__(shot_this[ *pulser()]);
401 int echoperiod = lrint(shot_this[ *echoPeriod()] / 1000 /interval);
402 int numechoes = shot_this[ *numEcho()];
403 numechoes = std::max(1, numechoes);
404 bool bg_after_last_echo = (echoperiod < bgpos + bglength);
406 if(bglength && (bglength < length * (bg_after_last_echo ? numechoes : 1) * 3))
407 m_statusPrinter->printWarning(i18n(
"Maybe, length for BG. sub. is too short."));
409 if((bgpos < length + (bg_after_last_echo ? (echoperiod * (numechoes - 1)) : 0))
410 && (bgpos + bglength > 0))
411 m_statusPrinter->printWarning(i18n(
"Maybe, position for BG. sub. is overrapped against echoes"),
true);
414 if(pos + echoperiod * (numechoes - 1) + length >= dso_len) {
415 throw XSkippedRecordError(i18n(
"Invalid Multiecho settings."), __FILE__, __LINE__);
417 if(echoperiod < length) {
418 throw XSkippedRecordError(i18n(
"Invalid Multiecho settings."), __FILE__, __LINE__);
420 if( !bg_after_last_echo) {
421 if(bgpos + bglength > echoperiod) {
422 throw XSkippedRecordError(i18n(
"Invalid Multiecho settings."), __FILE__, __LINE__);
424 if(pos + echoperiod * (numechoes - 1) + bgpos + bglength >= dso_len) {
425 throw XSkippedRecordError(i18n(
"Invalid Multiecho settings."), __FILE__, __LINE__);
429 if((numechoes > shot_others[ *pulse__].echoNum()) ||
430 (fabs(shot_this[ *echoPeriod()] * 1e3 / (shot_others[ *pulse__].tau() * 2.0) - 1.0) > 1e-4)) {
431 m_statusPrinter->printWarning(i18n(
"Invalid Multiecho settings."),
true);
436 if(shot_others[ *pulse__].isPulseAnalyzerMode()) {
437 m_statusPrinter->printWarning(i18n(
"Built-In Network Analyzer Mode."),
false);
438 throw XSkippedRecordError(__FILE__, __LINE__);
442 if((shot_this[ *
this].m_startTime != starttime) || (length != shot_this[ *
this].m_waveWidth)) {
443 double t = length * interval * 1e3;
444 tr[ *tr[ *waveGraph()].axisx()->autoScale()] =
false;
445 tr[ *tr[ *waveGraph()].axisx()->minValue()] = starttime * 1e3 - t * 0.3;
446 tr[ *tr[ *waveGraph()].axisx()->maxValue()] = starttime * 1e3 + t * 1.3;
448 tr[ *
this].m_waveWidth = length;
449 bool skip = (shot_this[ *
this].m_timeClearRequested > shot_dso[ *dso__].timeAwared());
450 bool avgclear = skip;
452 if(interval != shot_this[ *
this].m_interval) {
454 tr[ *
this].m_interval = interval;
457 if(shot_this[ *
this].m_startTime != starttime) {
459 tr[ *
this].m_startTime = starttime;
463 if(length > (
int)shot_this[ *
this].m_waveSum.size()) {
466 tr[ *
this].m_wave.resize(length);
467 tr[ *
this].m_waveSum.resize(length);
469 if(fftlen != shot_this[ *
this].m_darkPSD.size()) {
472 if(length > fftlen) {
473 throw XSkippedRecordError(i18n(
"FFT length is too short."), __FILE__, __LINE__);
475 tr[ *
this].m_darkPSD.resize(fftlen);
476 tr[ *
this].m_darkPSDSum.resize(fftlen);
477 std::fill(tr[ *
this].m_wave.begin(), tr[ *
this].m_wave.end(), std::complex<double>(0.0));
480 bool picenabled = shot_this[ *m_picEnabled];
481 bool inverted =
false;
482 if(picenabled && ( !pulse__ || !shot_others[ *pulse__].time())) {
484 gErrPrint(getLabel() +
": " + i18n(
"No active pulser!"));
487 inverted = shot_others[ *pulse__].invertPhase();
490 int avgnum = std::max((
unsigned int)shot_this[ *extraAvg()], 1u) * (picenabled ? 2 : 1);
492 if( !shot_this[ *exAvgIncr()] && (avgnum <= shot_this[ *
this].m_avcount)) {
496 std::fill(tr[ *
this].m_waveSum.begin(), tr[ *
this].m_waveSum.end(), std::complex<double>(0.0));
497 std::fill(tr[ *
this].m_darkPSDSum.begin(), tr[ *
this].m_darkPSDSum.end(), 0.0);
498 tr[ *
this].m_avcount = 0;
499 if(shot_this[ *exAvgIncr()]) {
500 tr[ *extraAvg()] = 0;
505 throw XSkippedRecordError(__FILE__, __LINE__);
508 tr[ *
this].m_dsoWave.resize(dso_len);
509 std::complex<double> *dsowave( &tr[ *
this].m_dsoWave[0]);
511 const double *rawwavecos, *rawwavesin = NULL;
512 assert(shot_dso[ *dso__].numChannels() );
513 rawwavecos = shot_dso[ *dso__].wave(0);
514 rawwavesin = shot_dso[ *dso__].wave(1);
515 for(
unsigned int i = 0; i < dso_len; i++) {
516 dsowave[i] = std::complex<double>(rawwavecos[i], rawwavesin[i]) * (inverted ? -1.0 : 1.0);
519 tr[ *
this].m_dsoWaveStartPos = pos;
522 if(bg_after_last_echo)
523 backgroundSub(tr, tr[ *
this].m_dsoWave, pos, length, bgpos, bglength);
524 for(
int i = 1; i < numechoes; i++) {
525 int rpos = pos + i * echoperiod;
527 j < ( !bg_after_last_echo ? std::max(bgpos + bglength, length) : length); j++) {
531 dsowave[pos + j] /= (double)numechoes;
532 dsowave[pos + j] += dsowave[k] / (double)numechoes;
536 if( !bg_after_last_echo)
537 backgroundSub(tr, tr[ *
this].m_dsoWave, pos, length, bgpos, bglength);
539 std::complex<double> *wavesum( &tr[ *
this].m_waveSum[0]);
540 double *darkpsdsum( &tr[ *
this].m_darkPSDSum[0]);
542 if((emitter == dso__.get()) || ( !shot_this[ *
this].m_avcount)) {
543 for(
int i = 0; i < length; i++) {
544 wavesum[i] += dsowave[pos + i];
548 if( !shot_this[ *
this].m_ftDark ||
549 (shot_this[ *
this].m_ftDark->length() != shot_this[ *
this].m_darkPSD.size())) {
550 tr[ *
this].m_ftDark.reset(
new FFT(-1, shot_this[ *fftLen()]));
552 std::vector<std::complex<double> > darkin(fftlen, 0.0), darkout(fftlen);
553 int bginplen = std::min(bglength, fftlen);
554 double normalize = 0.0;
556 for(
int i = 0; i < bginplen; i++) {
557 double tw = sin(2.0*M_PI*i/(
double)bginplen);
558 darkin[i] = dsowave[pos + i + bgpos] * tw;
559 normalize += tw * tw;
561 normalize = 1.0 / normalize * interval;
562 tr[ *
this].m_ftDark->exec(darkin, darkout);
564 for(
int i = 0; i < fftlen; i++) {
565 darkin[i] = std::norm(darkout[i]) * normalize;
567 tr[ *
this].m_ftDark->exec(darkin, darkout);
568 std::vector<std::complex<double> > sigma2(darkout);
569 std::fill(darkin.begin(), darkin.end(), std::complex<double>(0.0));
570 double x = sqrt(1.0 / length / fftlen);
571 for(
int i = 0; i < length; i++) {
574 tr[ *
this].m_ftDark->exec(darkin, darkout);
575 for(
int i = 0; i < fftlen; i++) {
576 darkin[i] = std::norm(darkout[i]);
578 tr[ *
this].m_ftDark->exec(darkin, darkout);
579 for(
int i = 0; i < fftlen; i++) {
580 darkin[i] = std::conj(darkout[i] * sigma2[i]);
582 tr[ *
this].m_ftDark->exec(darkin, darkout);
583 normalize = 1.0 / fftlen;
584 for(
int i = 0; i < fftlen; i++) {
585 darkpsdsum[i] += std::real(darkout[i]) * normalize;
588 tr[ *
this].m_avcount++;
589 if( shot_this[ *exAvgIncr()]) {
590 tr[ *extraAvg()] = shot_this[ *
this].m_avcount;
593 std::complex<double> *wave( &tr[ *
this].m_wave[0]);
594 double normalize = 1.0 / shot_this[ *
this].m_avcount;
595 for(
int i = 0; i < length; i++) {
596 wave[i] = wavesum[i] * normalize;
598 double darknormalize = normalize * normalize;
599 if(bg_after_last_echo)
600 darknormalize /= (double)numechoes;
601 double *darkpsd( &tr[ *
this].m_darkPSD[0]);
602 for(
int i = 0; i < fftlen; i++) {
603 darkpsd[i] = darkpsdsum[i] * darknormalize;
605 int ftpos = lrint( shot_this[ *fftPos()] * 1e-3 / interval + shot_dso[ *dso__].trigPos() - pos);
607 if(shot_this[ *difFreq()] != 0.0) {
609 double omega = -2.0 * M_PI * shot_this[ *difFreq()] * 1e3 * interval;
610 for(
int i = 0; i < length; i++) {
611 wave[i] *= std::polar(1.0, omega * (i - ftpos));
617 double ph = shot_this[ *phaseAdv()] * M_PI / 180;
618 tr[ *
this].m_waveFTPos = ftpos;
620 tr[ *
this].m_dFreq = 1.0 / fftlen / interval;
621 tr[ *
this].m_ftWave.resize(fftlen);
623 rotNFFT(tr, ftpos, ph, tr[ *
this].m_wave, tr[ *
this].m_ftWave);
625 if(solver.
peaks().size()) {
626 entryPeakAbs()->value(tr,
627 solver.
peaks()[0].first / (double)shot_this[ *
this].m_wave.size());
628 double x = solver.
peaks()[0].second;
629 x = (x > fftlen / 2) ? (x - fftlen) : x;
630 entryPeakFreq()->value(tr,
631 0.001 * x * shot_this[ *
this].m_dFreq);
634 m_isPulseInversionRequested = picenabled && (shot_this[ *
this].m_avcount % 2 == 1) && (emitter == dso__.get());
636 if( !shot_this[ *exAvgIncr()] && (avgnum != shot_this[ *
this].m_avcount))
637 throw XSkippedRecordError(__FILE__, __LINE__);
642 if(shot[ *
this].time() && shot[ *
this].m_avcount)
645 tr[ *ftWaveGraph()].clearPoints();
646 tr[ *waveGraph()].clearPoints();
647 tr[ *m_peakPlot->maxCount()] = 0;
651 if(m_isPulseInversionRequested.compare_set_strong((
int)
true, (
int)
false)) {
652 shared_ptr<XPulser> pulse__ = shot[ *pulser()];
655 if(tr[ *pulse__].time()) {
656 tr[ *pulse__->invertPhase()] = !tr[ *pulse__->invertPhase()];
666 int ftsize = shot[ *
this].m_ftWave.size();
668 tr[ *ftWaveGraph()].setRowCount(ftsize);
669 double normalize = 1.0 / shot[ *
this].m_wave.size();
670 double darknormalize =
671 shot[ *
this].m_ftWavePSDCoeff / (shot[ *
this].m_wave.size() * shot[ *
this].interval());
672 double dfreq = shot[ *
this].m_dFreq;
673 const double *darkpsd( &shot[ *
this].m_darkPSD[0]);
674 const std::complex<double> *ftwave( &shot[ *
this].m_ftWave[0]);
675 double *colf(tr[ *ftWaveGraph()].cols(0));
676 double *colr(tr[ *ftWaveGraph()].cols(1));
677 double *coli(tr[ *ftWaveGraph()].cols(2));
678 double *colabs(tr[ *ftWaveGraph()].cols(3));
679 double *colarg(tr[ *ftWaveGraph()].cols(4));
680 double *coldark(tr[ *ftWaveGraph()].cols(5));
681 for (
int i = 0; i < ftsize; i++) {
682 int j = (i - ftsize/2 + ftsize) % ftsize;
683 colf[i] = 0.001 * (i - ftsize/2) * dfreq;
684 std::complex<double> z = ftwave[j] * normalize;
685 colr[i] = std::real(z);
686 coli[i] = std::imag(z);
687 colabs[i] = std::abs(z);
688 colarg[i] = std::arg(z) / M_PI * 180;
689 coldark[i] = sqrt(darkpsd[j] * darknormalize);
691 const std::vector<std::pair<double, double> > &peaks(solver.
peaks());
692 int peaks_size = peaks.size();
693 tr[ *m_peakPlot->maxCount()] = peaks_size;
694 auto &points(tr[ *m_peakPlot].points());
695 points.resize(peaks_size);
696 for(
int i = 0; i < peaks_size; i++) {
697 double x = peaks[i].second;
698 x = (x > ftsize / 2) ? (x - ftsize) : x;
699 points[i] =
XGraph::ValPoint(0.001 * x * dfreq, peaks[i].first * normalize);
701 ftWaveGraph()->drawGraph(tr);
703 int length = shot[ *
this].m_dsoWave.size();
704 const std::complex<double> *dsowave( &shot[ *
this].m_dsoWave[0]);
705 if(solver.ifft().size() < ftsize)
707 const std::complex<double> *ifft( &solver.ifft()[0]);
708 int dsowavestartpos = shot[ *
this].m_dsoWaveStartPos;
709 double interval = shot[ *
this].m_interval;
710 double starttime = shot[ *
this].startTime();
711 int waveftpos = shot[ *
this].m_waveFTPos;
712 tr[ *waveGraph()].setRowCount(length);
713 double *colt(tr[ *waveGraph()].cols(0));
714 double *colfr(tr[ *waveGraph()].cols(1));
715 double *colfi(tr[ *waveGraph()].cols(2));
716 double *colrr(tr[ *waveGraph()].cols(3));
717 double *colri(tr[ *waveGraph()].cols(4));
718 for (
int i = 0; i < length; i++) {
719 int j = i - dsowavestartpos;
720 colt[i] = (starttime + j * interval) * 1e3;
721 if(abs(j) < ftsize / 2) {
722 j = (j - waveftpos + ftsize) % ftsize;
723 colfr[i] = std::real(ifft[j]);
724 colfi[i] = std::imag(ifft[j]);
730 colrr[i] = dsowave[i].real();
731 colri[i] = dsowave[i].imag();
733 waveGraph()->drawGraph(tr);