DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
ODMR.cpp
Go to the documentation of this file.
1// This file is part of DynExp.
2
3#include "stdafx.h"
4#include "ui_ODMR.h"
5#include "ODMR.h"
6
8{
13
14 unsigned long long ODMRData::GetSweepNumberSteps() const noexcept
15 {
17 return 0;
18
19 return std::floor(std::abs(SweepSeriesStop - SweepSeriesStart) / SweepSeriesStep) + 1;
20 }
21
22 std::stringstream ODMRData::AssembleCSVHeader(double RFPower, double RFModulationDepth, double AuxAnalogOutValue, bool IsRFOffResonance)
23 {
24 std::stringstream CSVData;
25
26 CSVData << std::setprecision(6);
27 CSVData << "RFPower = " << RFPower << " " << GetRFGenerator()->GetValueUnitStr() << "\n";
28 CSVData << "RFCenterFreq = " << RFCenterFreq << " Hz\n";
29 CSVData << "RFFreqSpan = " << RFFreqSpan << " Hz\n";
30 CSVData << "RFFreqSpacing = " << RFFreqSpacing << " Hz\n";
31 CSVData << "RFDwellTime = " << RFDwellTime << " s\n";
32
33 CSVData << "RFModulation = ";
34 switch (RFModulation)
35 {
36 case RFModulationType::None: CSVData << "none\n"; break;
37 case RFModulationType::Sine: CSVData << "sine\n"; break;
38 case RFModulationType::Pulse: CSVData << "pulse\n"; break;
39 default: CSVData << "\n";
40 }
41 CSVData << "RFModulationFreq = " << RFModulationFreq << " Hz\n";
42 CSVData << "RFModulationDepth = " << RFModulationDepth << " Hz\n";
43
44 CSVData << "ODMRSamplingRate = " << ODMRSamplingRate << " samples/s\n";
45 CSVData << "CurrentSaveIndex = " << CurrentSaveIndex << "\n";
46
47 CSVData << "IsRFOffResonance = " << (IsRFOffResonance ? "yes" : "no") << "\n";
48 CSVData << "SensitivityEnabled = " << (SensitivityEnabled ? "yes" : "no") << "\n";
49 CSVData << "SensitivityOncePerSweep = " << (SensitivityOncePerSweep ? "yes" : "no") << "\n";
50 CSVData << "SensitivityOffResonanceEnabled = " << (SensitivityOffResonanceEnabled ? "yes" : "no") << "\n";
51 CSVData << "SensitivityResonanceFreq = " << SensitivityResonanceFreq << " Hz\n";
52 CSVData << "SensitivityOffResonanceFreq = " << SensitivityOffResonanceFreq << " Hz\n";
53 CSVData << "SensitivityResonanceSpan = " << SensitivityResonanceSpan << " Hz\n";
54 CSVData << "SensitivitySamplingRate = " << SensitivitySamplingRate << " samples/s\n";
55 CSVData << "SensitivityDuration = " << SensitivityDuration << " s\n";
56
57 CSVData << "SensitivityAnalysisEnabled = " << (SensitivityAnalysisEnabled ? "yes" : "no") << "\n";
58 CSVData << "GyromagneticRatio = " << GyromagneticRatio << " Hz/T\n";
59
60 CSVData << "SweepSeriesEnabled = " << (SweepSeriesEnabled ? "yes" : "no") << "\n";
61 CSVData << "SweepSeries = ";
62 switch (SweepSeries)
63 {
64 case SweepSeriesType::RFModulationDepth: CSVData << "RFModulationDepth\n"; break;
65 case SweepSeriesType::RFPower: CSVData << "RFPower\n"; break;
66 case SweepSeriesType::AnalogOut: CSVData << "AnalogOut\n"; break;
67 default: CSVData << "\n";
68 }
69 CSVData << "SweepSeriesStart = " << SweepSeriesStart << "\n";
70 CSVData << "SweepSeriesStop = " << SweepSeriesStop << "\n";
71 CSVData << "SweepSeriesStep = " << SweepSeriesStep << "\n";
72 CSVData << "SweepSeriesRetrace = " << (SweepSeriesRetrace ? "yes" : "no") << "\n";
73 CSVData << "SweepSeriesAdvanceLastValue = " << (SweepSeriesAdvanceLastValue ? "yes" : "no") << "\n";
74 CSVData << "CurrentSweepIndex = " << CurrentSweepIndex << "\n";
75 CSVData << "AuxAnalogOutValue = " << AuxAnalogOutValue << "\n";
76
78 {
79 auto& LockinInstr = dynamic_cast<const DynExpInstr::LockinAmplifier&>(*GetSignalDetector());
80 auto LockinData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::LockinAmplifier>(GetSignalDetector()->GetInstrumentData());
81
82 auto Sensitivity = LockinData->GetSensitivity();
83 auto TimeConstant = LockinData->GetTimeConstant();
84 unsigned int FilterOrder = LockinData->GetFilterOrder();
85
86 CSVData << "LockinSensitivity = " << Sensitivity << " " << LockinInstr.GetSensitivityUnitString() << "\n";
87 CSVData << "LockinTimeConstant = " << TimeConstant << " s\n";
88 CSVData << "LockinFilterOrder = " << FilterOrder << "\n";
89 }
90
91 CSVData << "HEADER_END\n";
92
93 return CSVData;
94 }
95
152
153 ODMR::ODMR::ODMR(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType&& Params)
154 : QModuleBase(OwnerThreadID, std::move(Params)),
155 StateMachine(InitializingState, ReadyState,
156 MeasurementSeriesStepState, MeasurementSeriesInitState,
157 ODMRTraceInitState, ODMRTraceWaitState, ODMRTraceFinishState,
158 SensitivityInitState, SensitivityWaitState, SensitivityFinishState)
159 {
160 }
161
162 std::chrono::milliseconds ODMR::ODMR::GetMainLoopDelay() const
163 {
164 auto CurrentState = StateMachine.GetCurrentState()->GetState();
165
166 // If doing some measurement, run much faster.
167 if (CurrentState == StateType::Ready)
168 return std::chrono::milliseconds(30);
169 else
170 return std::chrono::milliseconds(2);
171 }
172
174 {
175 try
176 {
177 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
178
180 {
181 auto LockinData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::LockinAmplifier>(ModuleData->GetSignalDetector()->GetInstrumentData());
182
183 ModuleData->AcquisitionTime = LockinData->GetAcquisitionTime();
184 } // LockinData unlocked here.
185
186 StateMachine.Invoke(*this, Instance);
187
189 }
190 catch (const Util::TimeoutException& e)
191 {
192 if (NumFailedUpdateAttempts++ >= 3)
193 Instance.GetOwner().SetWarning(e);
194 }
195
197 }
198
209
210 std::unique_ptr<DynExp::QModuleWidget> ODMR::MakeUIWidget()
211 {
212 auto Widget = std::make_unique<ODMRWidget>(*this);
213
214 Connect(Widget->GetUI()->SBRFPower, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnRFPowerChanged);
215 Connect(Widget->GetUI()->CBRFAutoEnable, &QCheckBox::checkStateChanged, this, &ODMR::OnRFAutoEnableClicked);
216 Connect(Widget->GetUI()->SBRFCenter, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnRFCenterFreqChanged);
217 Connect(Widget->GetUI()->SBRFSpan, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnRFFreqSpanChanged);
218 Connect(Widget->GetUI()->SBRFFreqSpacing, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnRFFreqSpacingChanged);
219 Connect(Widget->GetUI()->SBRFDwellTime, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnRFDwellTimeChanged);
220
221 Connect(Widget->GetUI()->RBRFModulationTypeNone, &QRadioButton::clicked, this, &ODMR::OnRFModNoneClicked);
222 Connect(Widget->GetUI()->RBRFModulationTypeSine, &QRadioButton::clicked, this, &ODMR::OnRFModSineClicked);
223 Connect(Widget->GetUI()->RBRFModulationTypePulse, &QRadioButton::clicked, this, &ODMR::OnRFModPulseClicked);
224 Connect(Widget->GetUI()->SBRFModulationFreq, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnRFModFreqChanged);
225 Connect(Widget->GetUI()->SBRFModulationDepth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnRFModDepthChanged);
226
227 Connect(Widget->GetUI()->SBDataAcquisitionODMRSamplingRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnODMRSamplingRateChanged);
228
229 Connect(Widget->GetUI()->LESaveDataPath, &QLineEdit::textChanged, this, &ODMR::OnSavePathChanged);
230 Connect(Widget->GetUI()->SBSaveDataCurrentIndex, QOverload<int>::of(&QSpinBox::valueChanged), this, &ODMR::OnSaveIndexChanged);
231 Connect(Widget->GetUI()->CBSaveDataEnable, &QCheckBox::checkStateChanged, this, &ODMR::OnAutosaveClicked);
232
233 Connect(Widget->GetUI()->CBSensitivityEnable, &QCheckBox::checkStateChanged, this, &ODMR::OnRecordSensitivityClicked);
234 Connect(Widget->GetUI()->CBSensitivityOncePerSweep, &QCheckBox::checkStateChanged, this, &ODMR::OnRecordSensitivityOncePerSweepClicked);
235 Connect(Widget->GetUI()->CBSensitivityOffResEnable, &QCheckBox::checkStateChanged, this, &ODMR::OnRecordSensitivityOffResonanceClicked);
236 Connect(Widget->GetUI()->SBSensitivityFreq, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSensitivityResonanceFreqChanged);
237 Connect(Widget->GetUI()->SBSensitivityOffResFreq, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSensitivityOffResonanceFreqChanged);
238 Connect(Widget->GetUI()->SBSensitivitySpan, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSensitivityResonanceSpanChanged);
239 Connect(Widget->GetUI()->SBSensitivitySamplingRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSensitivitySamplingRateChanged);
240 Connect(Widget->GetUI()->SBSensitivityDuration, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSensitivityDurationChanged);
241
242 Connect(Widget->GetUI()->GBSensitivityAnalysis, &QGroupBox::toggled, this, &ODMR::OnEnableSensitivityAnalysisClicked);
243 Connect(Widget->GetUI()->SBGyromagneticRatio, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnGyromagneticRatioChanged);
244
245 Connect(Widget->GetUI()->CBParamSweepEnable, &QCheckBox::checkStateChanged, this, &ODMR::OnEnableSweepSeriesClicked);
246 Connect(Widget->GetUI()->CBParamSweepType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ODMR::OnSweepSeriesParamChanged);
247 Connect(Widget->GetUI()->SBParamSweepStart, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSweepSeriesStartChanged);
248 Connect(Widget->GetUI()->SBParamSweepStop, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSweepSeriesStopChanged);
249 Connect(Widget->GetUI()->SBParamSweepStep, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ODMR::OnSweepSeriesStepChanged);
250 Connect(Widget->GetUI()->CBParamSweepRetrace, &QCheckBox::checkStateChanged, this, &ODMR::OnSweepSeriesRetraceClicked);
251 Connect(Widget->GetUI()->CBParamSweepAdvanceLastValue, &QCheckBox::checkStateChanged, this, &ODMR::OnSweepSeriesAdvanceLastValueClicked);
252
253 Connect(Widget->GetUI()->BStart, &QPushButton::clicked, this, &ODMR::OnStartClicked);
254 Connect(Widget->GetUI()->BStartSensitivity, &QPushButton::clicked, this, &ODMR::OnStartSensitivityClicked);
255 Connect(Widget->GetUI()->BStop, &QPushButton::clicked, this, &ODMR::OnStopClicked);
256 Connect(Widget->GetUI()->BRFOn, &QPushButton::clicked, this, &ODMR::OnRFOnClicked);
257 Connect(Widget->GetUI()->BRFOff, &QPushButton::clicked, this, &ODMR::OnRFOffClicked);
258
259 return Widget;
260 }
261
262 void ODMR::UpdateUIChild(const ModuleBase::ModuleDataGetterType& ModuleDataGetter)
263 {
264 auto Widget = GetWidget<ODMRWidget>();
265 ODMRPlotType ODMRPlot;
266 SensitivityPlotType SensitivityPlot;
267
268 {
269 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(ModuleDataGetter());
270
271 if (StateMachine.GetCurrentState()->GetState() == StateType::Initializing)
272 return;
273
274 Widget->InitializeUI(ModuleData);
275 Widget->SetUIState(StateMachine.GetCurrentState(), ModuleData);
276 Widget->UpdateUIData(ModuleData);
277
278 if (ModuleData->ODMRPlot.HasChanged)
279 {
280 ODMRPlot = ModuleData->ODMRPlot;
281 ModuleData->ODMRPlot.HasChanged = false;
282 }
283 if (ModuleData->SensitivityPlot.HasChanged)
284 {
285 SensitivityPlot = ModuleData->SensitivityPlot;
286 ModuleData->SensitivityPlot.HasChanged = false;
287 }
288 } // ModuleData unlocked here (heavy plot operations follow).
289
290 if (ODMRPlot.HasChanged)
291 {
292 Widget->UpdateODMRPlot(ODMRPlot);
293 ConnectChartWidgets(Widget->GetODMRDataSeries());
294 }
295 if (SensitivityPlot.HasChanged)
296 Widget->UpdateSensitivityPlot(SensitivityPlot);
297 }
298
300 {
301 NextRFPower = ModuleData->RFPower;
302 NextRFModulationDepth = ModuleData->RFModulationDepth;
303 NextAuxAnalogOutValue = (ModuleData->AuxAnalogOutMinValue <= 0 && ModuleData->AuxAnalogOutMaxValue >= 0) ? 0 : ModuleData->AuxAnalogOutMinValue;
304
305 if (!ModuleData->SweepSeriesEnabled || !ModuleData->GetSweepNumberSteps())
306 return;
307
308 decltype(ModuleData->CurrentSweepIndex) SweepIndex = ModuleData->CurrentSweepIndex;
309 if (ModuleData->SweepSeriesAdvanceLastValue && SweepIndex == 1)
310 SweepIndex = ModuleData->GetSweepNumberSteps() - 1;
311 else if (ModuleData->SweepSeriesAdvanceLastValue && SweepIndex > 1)
312 --SweepIndex;
313
314 switch (ModuleData->SweepSeries)
315 {
317 NextRFModulationDepth = (ModuleData->SweepSeriesStart + SweepIndex * std::abs(ModuleData->SweepSeriesStep)) * 1e3;
318 break;
320 NextRFPower = ModuleData->SweepSeriesStart + SweepIndex * std::abs(ModuleData->SweepSeriesStep);
321 break;
323 NextAuxAnalogOutValue = ModuleData->SweepSeriesStart + SweepIndex * std::abs(ModuleData->SweepSeriesStep);
324 break;
325 }
326 }
327
342
344 {
346 ModuleData->GetAuxAnalogOut()->SetSync(NextAuxAnalogOutValue);
347 }
348
350 {
351 // Trigger on rising edge, so set to 0 now.
352 ModuleData->GetTrigger()->SetSync(0);
353
354 // Wait to ensure that trigger signal does not come too fast
355 std::this_thread::sleep_for(std::chrono::milliseconds(200));
356
357 // Prepare acquisition.
358 ModuleData->GetSignalDetector()->Stop();
359 ModuleData->GetSignalDetector()->Clear();
360 ModuleData->GetSignalDetector()->Start();
361
362 // Wait until every involved instrument is ready.
363 DynExp::WaitForInstruments(*ModuleData->GetRFGenerator(), *ModuleData->GetSignalDetector(), *ModuleData->GetTrigger());
364
365 // Trigger RF sweep and data acquisition now.
366 ModuleData->GetTrigger()->SetSync(1);
367 }
368
369 void ODMR::ConnectChartWidgets(QLineSeries* ODMRLineSeries)
370 {
371 if (!ODMRLineSeries)
372 return;
373
374 Connect(ODMRLineSeries, &QXYSeries::hovered, this, &ODMR::OnODMRChartHovered);
375 Connect(ODMRLineSeries, &QXYSeries::clicked, this, &ODMR::OnODMRChartClicked);
376 }
377
379 {
380 auto ModuleParams = DynExp::dynamic_Params_cast<ODMR>(Instance->ParamsGetter());
381 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
382
383 Instance->LockObject(ModuleParams->RFGenerator, ModuleData->GetRFGenerator());
384 Instance->LockObject(ModuleParams->SignalDetector, ModuleData->GetSignalDetector());
385 Instance->LockObject(ModuleParams->TriggerOut, ModuleData->GetTrigger());
386
387 ModuleData->RFGeneratorMinFuncDesc = ModuleData->GetRFGenerator()->GetMinCaps();
388 ModuleData->RFGeneratorMaxFuncDesc = ModuleData->GetRFGenerator()->GetMaxCaps();
389 ModuleData->RFGeneratorDefaultFuncDesc = ModuleData->GetRFGenerator()->GetParamDefaults();
390
391 if (dynamic_cast<const DynExpInstr::LockinAmplifier*>(ModuleData->GetSignalDetector().get()))
393 else if (dynamic_cast<const DynExpInstr::AnalogIn*>(ModuleData->GetSignalDetector().get()))
395 ModuleData->GetSignalDetector()->Stop();
396
397 if (ModuleParams->AuxAnalogOut.ContainsID())
398 {
399 Instance->LockObject(ModuleParams->AuxAnalogOut, ModuleData->GetAuxAnalogOut());
401
402 ModuleData->AuxAnalogOutValueUnit = ModuleData->GetAuxAnalogOut()->GetValueUnit();
403 ModuleData->AuxAnalogOutMinValue = ModuleData->GetAuxAnalogOut()->GetUserMinValue();
404 ModuleData->AuxAnalogOutMaxValue = ModuleData->GetAuxAnalogOut()->GetUserMaxValue();
405 }
406 }
407
409 {
410 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
411
412 Instance->UnlockObject(ModuleData->GetRFGenerator());
413 Instance->UnlockObject(ModuleData->GetSignalDetector());
414 Instance->UnlockObject(ModuleData->GetTrigger());
415 Instance->UnlockObject(ModuleData->GetAuxAnalogOut());
416 }
417
418 void ODMR::OnRFPowerChanged(DynExp::ModuleInstance* Instance, double Value) const
419 {
420 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
421 ModuleData->RFPower = Value;
422 }
423
424 void ODMR::OnRFAutoEnableClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
425 {
426 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
427 ModuleData->RFAutoEnabled = Checked == Qt::CheckState::Checked;
428 }
429
430 void ODMR::OnRFCenterFreqChanged(DynExp::ModuleInstance* Instance, double Value) const
431 {
432 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
433 ModuleData->RFCenterFreq = Value * 1e6;
434 }
435
436 void ODMR::OnRFFreqSpanChanged(DynExp::ModuleInstance* Instance, double Value) const
437 {
438 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
439 ModuleData->RFFreqSpan = Value * 1e6;
440 }
441
442 void ODMR::OnRFFreqSpacingChanged(DynExp::ModuleInstance* Instance, double Value) const
443 {
444 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
445 ModuleData->RFFreqSpacing = Value * 1e3;
446 }
447
448 void ODMR::OnRFDwellTimeChanged(DynExp::ModuleInstance* Instance, double Value) const
449 {
450 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
451 ModuleData->RFDwellTime = Value * 1e-3;
452 }
453
454 void ODMR::OnRFModNoneClicked(DynExp::ModuleInstance* Instance, bool Checked) const
455 {
456 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
457
458 if (Checked)
460 }
461
462 void ODMR::OnRFModSineClicked(DynExp::ModuleInstance* Instance, bool Checked) const
463 {
464 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
465
466 if (Checked)
468 }
469
470 void ODMR::OnRFModPulseClicked(DynExp::ModuleInstance* Instance, bool Checked) const
471 {
472 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
473
474 if (Checked)
476 }
477
478 void ODMR::OnRFModFreqChanged(DynExp::ModuleInstance* Instance, double Value) const
479 {
480 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
481 ModuleData->RFModulationFreq = Value * 1e3;
482 }
483
484 void ODMR::OnRFModDepthChanged(DynExp::ModuleInstance* Instance, double Value) const
485 {
486 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
487 ModuleData->RFModulationDepth = Value * 1e3;
488 }
489
490 void ODMR::OnODMRSamplingRateChanged(DynExp::ModuleInstance* Instance, double Value) const
491 {
492 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
493 ModuleData->ODMRSamplingRate = Value;
494 }
495
496 void ODMR::OnSavePathChanged(DynExp::ModuleInstance* Instance, QString Path) const
497 {
498 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
499 ModuleData->SaveDataPath = Path.toStdString();
500 }
501
502 void ODMR::OnSaveIndexChanged(DynExp::ModuleInstance* Instance, int Index) const
503 {
504 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
505 ModuleData->CurrentSaveIndex = Index;
506 }
507
508 void ODMR::OnAutosaveClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
509 {
510 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
511 ModuleData->AutosaveEnabled = Checked == Qt::CheckState::Checked;
512 }
513
514 void ODMR::OnRecordSensitivityClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
515 {
516 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
517 ModuleData->SensitivityEnabled = Checked == Qt::CheckState::Checked;
518 }
519
520 void ODMR::OnRecordSensitivityOncePerSweepClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
521 {
522 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
523 ModuleData->SensitivityOncePerSweep = Checked == Qt::CheckState::Checked;
524 }
525
526 void ODMR::OnRecordSensitivityOffResonanceClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
527 {
528 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
529 ModuleData->SensitivityOffResonanceEnabled = Checked == Qt::CheckState::Checked;
530 }
531
533 {
534 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
535 ModuleData->SensitivityResonanceFreq = Value * 1e6;
536 }
537
539 {
540 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
541 ModuleData->SensitivityOffResonanceFreq = Value * 1e6;
542 }
543
545 {
546 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
547 ModuleData->SensitivityResonanceSpan = Value * 1e6;
548 }
549
551 {
552 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
553 ModuleData->SensitivitySamplingRate = Value;
554 }
555
557 {
558 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
559 ModuleData->SensitivityDuration = Value;
560 }
561
563 {
564 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
565 ModuleData->SensitivityAnalysisEnabled = Checked;
566 }
567
569 {
570 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
571 ModuleData->GyromagneticRatio = Value * 1e6;
572 }
573
574 void ODMR::OnEnableSweepSeriesClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
575 {
576 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
577 ModuleData->SweepSeriesEnabled = Checked == Qt::CheckState::Checked;
578 }
579
581 {
582 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
583
584 switch (Index)
585 {
586 case 0: ModuleData->SweepSeries = ODMRData::SweepSeriesType::RFModulationDepth; break;
587 case 1: ModuleData->SweepSeries = ODMRData::SweepSeriesType::RFPower; break;
588 case 2:
591 break;
592 }
593 }
594
595 void ODMR::OnSweepSeriesStartChanged(DynExp::ModuleInstance* Instance, double Value) const
596 {
597 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
598 ModuleData->SweepSeriesStart = Value;
599 }
600
601 void ODMR::OnSweepSeriesStopChanged(DynExp::ModuleInstance* Instance, double Value) const
602 {
603 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
604 ModuleData->SweepSeriesStop = Value;
605 }
606
607 void ODMR::OnSweepSeriesStepChanged(DynExp::ModuleInstance* Instance, double Value) const
608 {
609 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
610 ModuleData->SweepSeriesStep = Value;
611 }
612
613 void ODMR::OnSweepSeriesRetraceClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
614 {
615 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
616 ModuleData->SweepSeriesRetrace = Checked == Qt::CheckState::Checked;
617 }
618
619 void ODMR::OnSweepSeriesAdvanceLastValueClicked(DynExp::ModuleInstance* Instance, Qt::CheckState Checked) const
620 {
621 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
622 ModuleData->SweepSeriesAdvanceLastValue = Checked == Qt::CheckState::Checked;
623 }
624
626 {
627 if (!IsReadyState())
628 return;
629
631
632 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
634 }
635
637 {
638 if (!IsReadyState())
639 return;
640
642
643 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
645 }
646
647 void ODMR::OnStopClicked(DynExp::ModuleInstance* Instance, bool) const
648 {
649 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
650
651 if (ModuleData->RFAutoEnabled)
652 ModuleData->GetRFGenerator()->Stop();
653 ModuleData->GetSignalDetector()->Stop();
654
655 StateMachine.ResetContext();
656 StateMachine.SetCurrentState(StateType::Ready);
657 }
658
659 void ODMR::OnRFOnClicked(DynExp::ModuleInstance* Instance, bool) const
660 {
661 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
662 ModuleData->GetRFGenerator()->Start();
663 }
664
666 {
667 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
668 ModuleData->GetRFGenerator()->Stop();
669 }
670
671 void ODMR::OnODMRChartHovered(DynExp::ModuleInstance* Instance, QPointF Point, bool State) const
672 {
673 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
674 ModuleData->ODMRPlot.SelectedPoint = State ? Point : QPointF();
675 }
676
677 void ODMR::OnODMRChartClicked(DynExp::ModuleInstance* Instance, QPointF Point) const
678 {
679 if (Point.isNull())
680 return;
681
682 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance->ModuleDataGetter());
683 ModuleData->GetRFGenerator()->SetSineFunction({ Point.x() * 1e9 , ModuleData->RFPower, 0, 0});
684 }
685
690
695
697 {
698 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
699
700 ModuleData->CurrentSweepIndex = 0;
702
704 {
705 auto LockinAmplifier = ModuleData->GetLockinAmplifier();
707 LockinAmplifier->SetTriggerEdge(DynExpInstr::LockinAmplifierDefs::TriggerEdgeType::Rise);
708 LockinAmplifier->SetEnable(true);
709 }
710
712 }
713
715 {
716 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
717
718 if (!ModuleData->SweepSeriesEnabled || ++ModuleData->CurrentSweepIndex >= ModuleData->GetSweepNumberSteps())
719 {
720 ++ModuleData->CurrentSaveIndex;
721
722 if (ModuleData->SweepSeriesEnabled && ModuleData->SweepSeriesRetrace)
723 {
724 ModuleData->CurrentSweepIndex = 0;
726
728 InitRFGenerator(ModuleData->GetRFStartFreq(), false, ModuleData);
729 }
730 if (ModuleData->RFAutoEnabled)
731 ModuleData->GetRFGenerator()->Stop();
732
733 return StateType::Ready;
734 }
735
737
739 }
740
742 {
743 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
744
746 InitRFGenerator(ModuleData->GetRFStartFreq(), ModuleData->RFAutoEnabled, ModuleData);
747 ModuleData->GetRFGenerator()->SetSweep({
749 ModuleData->GetRFStartFreq(),
750 ModuleData->GetRFStopFreq(),
751 ModuleData->RFFreqSpacing,
752 ModuleData->RFDwellTime * 1000,
753 true
754 });
755 ModuleData->GetRFGenerator()->SetTrigger({
758 });
759
761 {
762 auto LockinAmplifier = ModuleData->GetLockinAmplifier();
763 LockinAmplifier->SetStreamSize(ModuleData->RFDwellTime * ModuleData->GetNumSamples() * ModuleData->ODMRSamplingRate);
764 LockinAmplifier->SetSamplingRate(ModuleData->ODMRSamplingRate);
765 }
766
768
770 }
771
773 {
774 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
775
776 return ModuleData->GetSignalDetector()->HasFinished() ? StateType::ODMRTraceFinish : StateType::ODMRTraceWait;
777 }
778
780 {
781 std::vector<std::tuple<double, double, double>> SaveSamples;
782 bool Save = false;
783 bool PerformSensitivityMeasurement = false;
784 double RFStartFreq{};
785 decltype(ODMRData::RFDwellTime) RFDwellTime{};
786 decltype(ODMRData::RFFreqSpacing) RFFreqSpacing{};
787 bool IsBasicSampleTimeUsed{};
788 double SamplingRate{ .0 };
790 decltype(ODMRPlotType::DataPoints) ODMRDataPoints;
791 decltype(ODMRPlotType::DataPointsMinValues) ODMRDataPointsMinValues = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
792 decltype(ODMRPlotType::DataPointsMaxValues) ODMRDataPointsMaxValues = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
793 decltype(ODMRData::SensitivityResonanceFreq) SensitivityResonanceFreq{};
794 decltype(ODMRData::SensitivityResonanceSpan) SensitivityResonanceSpan{};
795 decltype(ODMRPlotType::FitParams) ODMRFitParams{};
796 decltype(ODMRPlotType::FitPoints) ODMRFitPoints{};
797 std::vector<double> FitXData;
798 std::vector<double> FitYData;
799 std::string Filename;
800 std::string ValueUnitStr;
801 std::stringstream CSVData;
802
803 {
804 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
805
806 if (!ModuleData->GetSignalDetector()->CanRead())
808
809 Save = ModuleData->AutosaveEnabled;
810 PerformSensitivityMeasurement = ModuleData->SensitivityEnabled && (!ModuleData->SensitivityOncePerSweep || !ModuleData->CurrentSweepIndex);
811 RFStartFreq = ModuleData->GetRFStartFreq();
812 RFDwellTime = ModuleData->RFDwellTime;
813 RFFreqSpacing = ModuleData->RFFreqSpacing;
814 SensitivityResonanceFreq = ModuleData->SensitivityResonanceFreq;
815 SensitivityResonanceSpan = ModuleData->SensitivityResonanceSpan;
816
817 auto SignalDetectorData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::DataStreamInstrument>(ModuleData->GetSignalDetector()->GetInstrumentData());
818 SignalDetectorData->GetSampleStream()->SeekBeg(std::ios_base::in);
819 ODMRSamples = SignalDetectorData->GetSampleStream()->ReadBasicSamples(SignalDetectorData->GetSampleStream()->GetStreamSizeRead());
820
821 IsBasicSampleTimeUsed = SignalDetectorData->GetSampleStream()->IsBasicSampleTimeUsed();
822 if (!IsBasicSampleTimeUsed && ModuleData->TestFeature(ODMRData::FeatureType::AnalogInDetection))
823 {
824 SamplingRate = ModuleData->GetAnalogIn()->GetNumericSampleStreamParams().SamplingRate;
825
826 if (SamplingRate == .0)
827 throw Util::InvalidDataException("The analog input channel's sampling rate must not be 0.");
828 }
829
830 } // ModuleData unlocked here (heavy calculation follows).
831
832 for (size_t i = 0; i < ODMRSamples.size(); ++i)
833 {
834 const auto& Sample = ODMRSamples[i];
835
836 auto Frequency = RFStartFreq + (IsBasicSampleTimeUsed ? Sample.Time : (static_cast<double>(i) / SamplingRate)) / RFDwellTime * RFFreqSpacing;
837 ODMRDataPoints.push_back({ Frequency / 1e9, Sample.Value });
838 ODMRDataPointsMinValues = { std::min(ODMRDataPointsMinValues.x(), Frequency / 1e9), std::min(ODMRDataPointsMinValues.y(), Sample.Value) };
839 ODMRDataPointsMaxValues = { std::max(ODMRDataPointsMaxValues.x(), Frequency / 1e9), std::max(ODMRDataPointsMaxValues.y(), Sample.Value) };
840 if (Save)
841 SaveSamples.emplace_back(std::make_tuple(Frequency, Sample.Time, Sample.Value));
842
843 if (PerformSensitivityMeasurement &&
844 Frequency >= SensitivityResonanceFreq - SensitivityResonanceSpan / 2 &&
845 Frequency <= SensitivityResonanceFreq + SensitivityResonanceSpan / 2)
846 {
847 FitXData.push_back(Frequency - SensitivityResonanceFreq);
848 FitYData.push_back(Sample.Value);
849 }
850 }
851
852 if (PerformSensitivityMeasurement)
853 {
854 double c0{0}, c1{0}, cov00{0}, cov01{0}, cov11{0}, chisq{0};
855 gsl_fit_linear(FitXData.data(), 1, FitYData.data(), 1, FitXData.size(), &c0, &c1, &cov00, &cov01, &cov11, &chisq);
856 ODMRFitParams = { c0, c1 };
857
858 for (const auto& f : FitXData)
859 ODMRFitPoints.push_back({ (f + SensitivityResonanceFreq) / 1e9, c0 + c1 * f });
860 }
861
862 {
863 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
864
865 ModuleData->ODMRPlot.DataPoints = std::move(ODMRDataPoints);
866 ModuleData->ODMRPlot.DataPointsMinValues = ODMRDataPointsMinValues;
867 ModuleData->ODMRPlot.DataPointsMaxValues = ODMRDataPointsMaxValues;
868 ModuleData->ODMRPlot.FitParams = ODMRFitParams;
869 ModuleData->ODMRPlot.FitPoints = ODMRFitPoints;
870 ModuleData->ODMRPlot.HasChanged = true;
871
872 Filename = Util::RemoveExtFromPath(ModuleData->SaveDataPath) + "_ODMR" + Util::ToStr(ModuleData->CurrentSaveIndex) + "_Sweep" + Util::ToStr(ModuleData->CurrentSweepIndex) + ".csv";
873 ValueUnitStr = ModuleData->GetSignalDetector()->GetValueUnitStr();
874
875 if (Save)
876 CSVData = ModuleData->AssembleCSVHeader(NextRFPower, NextRFModulationDepth, NextAuxAnalogOutValue, false);
877 } // ModuleData unlocked here.
878
879 if (Save)
880 {
881 CSVData << "f(Hz);t(s);Value(" << ValueUnitStr << ")\n";
882 for (const auto& Sample : SaveSamples)
883 CSVData << std::get<0>(Sample) << ";" << std::get<1>(Sample) << ";" << std::get<2>(Sample) << "\n";
884
885 Util::SaveToFile(QString::fromStdString(Filename), CSVData.str());
886 }
887
888 return PerformSensitivityMeasurement ? StateType::SensitivityInit : StateType::MeasurementSeriesStep;
889 }
890
891 StateType ODMR::SensitivityInitFunc(DynExp::ModuleInstance& Instance)
892 {
893 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
894
895 // No sensitivity calculation if detection is not performed with a lock-in amplifer since in this case it is not possible
896 // to measure the ODMR signal's derivative directly.
897 if (!ModuleData->TestFeature(ODMRData::FeatureType::LockinDetection))
898 {
899 StateMachine.ResetContext();
900 return StateType::MeasurementSeriesStep;
901 }
902
903 SetAuxAnalogOutValue(ModuleData);
904 ModuleData->GetRFGenerator()->SetSweep({}); // Disable sweep.
905 ModuleData->GetRFGenerator()->SetTrigger({}); // Disable trigger.
906 auto RFFreq = StateMachine.GetContext() == &SensitivityOffResonanceContext ? ModuleData->SensitivityOffResonanceFreq : ModuleData->SensitivityResonanceFreq;
907 InitRFGenerator(RFFreq, ModuleData->RFAutoEnabled, ModuleData);
908
909 auto LockinAmplifier = ModuleData->GetLockinAmplifier();
910 LockinAmplifier->SetStreamSize(ModuleData->SensitivityDuration * ModuleData->SensitivitySamplingRate);
911 LockinAmplifier->SetSamplingRate(ModuleData->SensitivitySamplingRate);
912
913 WaitUntilReadyAndTrigger(ModuleData);
914
915 return StateType::SensitivityWait;
916 }
917
918 StateType ODMR::SensitivityWaitFunc(DynExp::ModuleInstance& Instance)
919 {
920 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
921
922 return ModuleData->GetSignalDetector()->HasFinished() ? StateType::SensitivityFinish : StateType::SensitivityWait;
923 }
924
925 StateType ODMR::SensitivityFinishFunc(DynExp::ModuleInstance& Instance)
926 {
927 std::vector<std::tuple<double, double>> SaveSamples;
928 ODMRData::MeasurementModeType MeasurementMode = ODMRData::MeasurementModeType::All;
929 bool Save = false;
930 bool SensitivityOffResonanceEnabled = false;
931 bool SensitivityAnalysisEnabled = false;
932 decltype(ODMRPlotType::FitParams) ODMRFitParams{};
933 decltype(ODMRData::GyromagneticRatio) GyromagneticRatio{};
935 std::vector<std::complex<double>> SensitivityASD;
936 decltype(SensitivityPlotType::DataPoints) SensitivityDataPoints;
937 decltype(SensitivityPlotType::DataPointsMinValues) SensitivityDataPointsMinValues = { std::numeric_limits<double>::max(), std::numeric_limits<double>::max() };
938 decltype(SensitivityPlotType::DataPointsMaxValues) SensitivityDataPointsMaxValues = { std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest() };
939 std::string Filename;
940 std::string FilenamePrefix;
941 std::string ValueUnitStr;
942 std::stringstream CSVData;
943
944 {
945 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
946
947 if (!ModuleData->GetSignalDetector()->CanRead())
948 return StateType::SensitivityFinish;
949
950 MeasurementMode = ModuleData->MeasurementMode;
951 Save = ModuleData->AutosaveEnabled;
952 SensitivityOffResonanceEnabled = ModuleData->SensitivityOffResonanceEnabled;
953 SensitivityAnalysisEnabled = ModuleData->SensitivityAnalysisEnabled;
954 ODMRFitParams = ModuleData->ODMRPlot.FitParams;
955 GyromagneticRatio = ModuleData->GyromagneticRatio;
956
957 auto SignalDetectorData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::DataStreamInstrument>(ModuleData->GetSignalDetector()->GetInstrumentData());
958 SignalDetectorData->GetSampleStream()->SeekBeg(std::ios_base::in);
959 SensitivitySamples = SignalDetectorData->GetSampleStream()->ReadBasicSamples(SignalDetectorData->GetSampleStream()->GetStreamSizeRead());
960 } // ModuleData unlocked here (heavy calculation follows).
961
962 for (const auto& Sample : SensitivitySamples)
963 {
964 SaveSamples.emplace_back(std::make_tuple(Sample.Time, Sample.Value));
965
966 if (MeasurementMode == ODMRData::MeasurementModeType::All && StateMachine.GetContext() != &SensitivityOffResonanceContext)
967 SensitivityASD.emplace_back(Sample.Value / std::get<1>(ODMRFitParams) / GyromagneticRatio, 0);
968 }
969
970 if (SensitivityASD.size() > 2 && SensitivityAnalysisEnabled && StateMachine.GetContext() != &SensitivityOffResonanceContext)
971 {
972 const auto Length = static_cast<double>(SensitivityASD.size());
973
974 SensitivityASD = Util::FFT(SensitivityASD);
975 std::transform(SensitivityASD.cbegin(), SensitivityASD.cend(), SensitivityASD.begin(), [Length](auto x) { return std::abs(x / Length); });
976
977 // Make single-sided spectrum
978 SensitivityASD.erase(SensitivityASD.cbegin() + SensitivityASD.size() / 2 + 1, SensitivityASD.cend());
979 std::transform(SensitivityASD.cbegin() + 1, SensitivityASD.cend(), SensitivityASD.begin() + 1, [Length](auto x) { return 2.0 * x; });
980
981 // Assume SensitivitySamples sorted by Time. Assume samples equally spaced in time.
982 double TimeSamplingRate = 1 / (std::abs(SensitivitySamples.back().Time - SensitivitySamples.front().Time) / (SensitivitySamples.size() - 1));
983 std::vector<double> Frequencies(Length / 2 + 1, 0);
984 std::iota(Frequencies.begin(), Frequencies.end(), 0);
985 std::transform(Frequencies.cbegin(), Frequencies.cend(), Frequencies.begin(), [TimeSamplingRate, Length](auto x) { return TimeSamplingRate * x / Length; });
986
987 double FrequencySamplingRate = std::abs(Frequencies.back() - Frequencies.front()) / (Frequencies.size() - 1);
988 std::transform(SensitivityASD.cbegin(), SensitivityASD.cend(), SensitivityASD.begin(), [FrequencySamplingRate](auto x) { return x / std::sqrt(FrequencySamplingRate); });
989
990 if (SensitivityASD.size() == Frequencies.size())
991 for (size_t i = 1; i < SensitivityASD.size(); ++i) // Ignore 0 Hz frequency component
992 {
993 SensitivityDataPoints.push_back({ Frequencies[i], SensitivityASD[i].real() });
994 SensitivityDataPointsMinValues = { std::min(SensitivityDataPointsMinValues.x(), SensitivityDataPoints.back().x()),
995 std::min(SensitivityDataPointsMinValues.y(), SensitivityDataPoints.back().y()) };
996 SensitivityDataPointsMaxValues = { std::max(SensitivityDataPointsMaxValues.x(), SensitivityDataPoints.back().x()),
997 std::max(SensitivityDataPointsMaxValues.y(), SensitivityDataPoints.back().y()) };
998 }
999 }
1000
1001 {
1002 auto ModuleData = DynExp::dynamic_ModuleData_cast<ODMR>(Instance.ModuleDataGetter());
1003
1004 if (StateMachine.GetContext() != &SensitivityOffResonanceContext)
1005 {
1006 ModuleData->SensitivityPlot.DataPoints = std::move(SensitivityDataPoints);
1007 ModuleData->SensitivityPlot.DataPointsMinValues = SensitivityDataPointsMinValues;
1008 ModuleData->SensitivityPlot.DataPointsMaxValues = SensitivityDataPointsMaxValues;
1009 ModuleData->SensitivityPlot.HasChanged = true;
1010
1011 FilenamePrefix = "Sensitivity";
1012 }
1013 else
1014 FilenamePrefix = "OffResSensitivity";
1015
1016 Filename = Util::RemoveExtFromPath(ModuleData->SaveDataPath) + "_" + FilenamePrefix + Util::ToStr(ModuleData->CurrentSaveIndex) + "_Sweep" + Util::ToStr(ModuleData->CurrentSweepIndex) + ".csv";
1017 ValueUnitStr = ModuleData->GetSignalDetector()->GetValueUnitStr();
1018
1019 if (Save)
1020 CSVData = ModuleData->AssembleCSVHeader(NextRFPower, NextRFModulationDepth, NextAuxAnalogOutValue, StateMachine.GetContext() == &SensitivityOffResonanceContext);
1021 } // ModuleData unlocked here.
1022
1023 if (Save)
1024 {
1025 CSVData << "t(s);Value(" << ValueUnitStr << ")\n";
1026 CSVData << std::setprecision(12);
1027 for (const auto& Sample : SaveSamples)
1028 CSVData << std::get<0>(Sample) << ";" << std::get<1>(Sample) << "\n";
1029
1030 Util::SaveToFile(QString::fromStdString(Filename), CSVData.str());
1031 }
1032
1033 if (SensitivityOffResonanceEnabled)
1034 {
1035 if (StateMachine.GetContext() == &SensitivityOffResonanceContext)
1036 StateMachine.ResetContext();
1037 else
1038 {
1039 StateMachine.SetContext(&SensitivityOffResonanceContext);
1040 return StateType::SensitivityInit;
1041 }
1042 }
1043
1044 return StateType::MeasurementSeriesStep;
1045 }
1046}
Implementation of a module to perform optically detected magnetic resonance (ODMR) measurements.
Meta instrument for a single analog input port based on the data stream and generic input port meta i...
Definition AnalogIn.h:136
std::vector< BasicSample > BasicSampleListType
Type of a list containing data stream samples of type BasicSample.
Meta instrument for a lock-in amplifier based on the data stream meta instrument.
DynExpInstr::DataStreamInstrumentData::ValueType AuxAnalogOutMinValue
Definition ODMR.h:97
double SensitivityResonanceFreq
Definition ODMR.h:74
std::stringstream AssembleCSVHeader(double RFPower, double RFModulationDepth, double AuxAnalogOutValue, bool IsRFOffResonance)
Definition ODMR.cpp:22
bool TestFeature(const std::array< FeatureType, N > &Flags) const
Definition ODMR.h:35
DynExpInstr::DataStreamInstrumentData::UnitType AuxAnalogOutValueUnit
Definition ODMR.h:96
SweepSeriesType SweepSeries
Definition ODMR.h:84
auto & GetRFGenerator() noexcept
Definition ODMR.h:40
std::string SaveDataPath
Definition ODMR.h:67
unsigned long long CurrentSweepIndex
Definition ODMR.h:90
SensitivityPlotType SensitivityPlot
Definition ODMR.h:103
DynExpInstr::FunctionGeneratorDefs::FunctionDescType RFGeneratorMaxFuncDesc
Definition ODMR.h:93
double SensitivityResonanceSpan
Definition ODMR.h:76
Util::FeatureTester< FeatureType > Features
Definition ODMR.h:116
double SensitivityOffResonanceFreq
Definition ODMR.h:75
unsigned long long GetSweepNumberSteps() const noexcept
Definition ODMR.cpp:14
unsigned int CurrentSaveIndex
Definition ODMR.h:68
MeasurementModeType MeasurementMode
Definition ODMR.h:66
DynExpInstr::FunctionGeneratorDefs::FunctionDescType RFGeneratorDefaultFuncDesc
Definition ODMR.h:94
ODMRPlotType ODMRPlot
Definition ODMR.h:102
RFModulationType RFModulation
Definition ODMR.h:60
DynExpInstr::FunctionGeneratorDefs::FunctionDescType RFGeneratorMinFuncDesc
Definition ODMR.h:92
bool SensitivityOffResonanceEnabled
Definition ODMR.h:73
DynExpInstr::DataStreamInstrumentData::ValueType AuxAnalogOutMaxValue
Definition ODMR.h:98
auto & GetSignalDetector() noexcept
Definition ODMR.h:41
void ResetImpl(dispatch_tag< QModuleDataBase >) override final
Definition ODMR.cpp:9
std::unique_ptr< DynExp::QModuleWidget > MakeUIWidget() override final
Used by InitUI() as a factory function for the module's user interface widget. Create the widget here...
Definition ODMR.cpp:210
size_t NumFailedUpdateAttempts
Definition ODMR.h:284
void InitRFGenerator(double Frequency, bool EnableRF, Util::SynchronizedPointer< ModuleDataType > &ModuleData) const
Definition ODMR.cpp:328
void OnEnableSweepSeriesClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:574
void OnSweepSeriesStopChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:601
void OnRFModDepthChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:484
void ConnectChartWidgets(QLineSeries *ODMRLineSeries)
Definition ODMR.cpp:369
void UpdateUIChild(const ModuleBase::ModuleDataGetterType &ModuleDataGetter) override final
Definition ODMR.cpp:262
void OnExit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread terminates (not due to an exception,...
Definition ODMR.cpp:408
Util::StateMachine< StateMachineStateType > StateMachine
Definition ODMR.h:278
Util::DynExpErrorCodes::DynExpErrorCodes ModuleMainLoop(DynExp::ModuleInstance &Instance) override final
Module main loop. The function is executed periodically by the module thread. Also refer to GetMainLo...
Definition ODMR.cpp:173
void WaitUntilReadyAndTrigger(Util::SynchronizedPointer< ModuleDataType > &ModuleData) const
Definition ODMR.cpp:349
StateType MeasurementSeriesInitFunc(DynExp::ModuleInstance &Instance)
Definition ODMR.cpp:696
void OnSweepSeriesAdvanceLastValueClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:619
void OnStopClicked(DynExp::ModuleInstance *Instance, bool) const
Definition ODMR.cpp:647
void OnSweepSeriesRetraceClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:613
StateType ODMRTraceWaitFunc(DynExp::ModuleInstance &Instance)
Definition ODMR.cpp:772
void OnRFModNoneClicked(DynExp::ModuleInstance *Instance, bool Checked) const
Definition ODMR.cpp:454
void OnAutosaveClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:508
void OnRFFreqSpanChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:436
void OnGyromagneticRatioChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:568
std::chrono::milliseconds GetMainLoopDelay() const override final
Specifies in which time intervals the module's event queue runs to handle pending events.
Definition ODMR.cpp:162
bool IsReadyState() const noexcept
Definition ODMR.h:181
void OnODMRSamplingRateChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:490
void ResetImpl(dispatch_tag< QModuleBase >) override final
Definition ODMR.cpp:199
void OnRFOnClicked(DynExp::ModuleInstance *Instance, bool) const
Definition ODMR.cpp:659
double NextAuxAnalogOutValue
Definition ODMR.h:282
void OnRFModPulseClicked(DynExp::ModuleInstance *Instance, bool Checked) const
Definition ODMR.cpp:470
StateType ReadyStateFunc(DynExp::ModuleInstance &Instance)
Definition ODMR.cpp:691
void OnRecordSensitivityOffResonanceClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:526
ODMR(const std::thread::id OwnerThreadID, DynExp::ParamsBasePtrType &&Params)
Definition ODMR.cpp:153
void OnSavePathChanged(DynExp::ModuleInstance *Instance, QString Path) const
Definition ODMR.cpp:496
void OnSweepSeriesStepChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:607
void OnSensitivityResonanceSpanChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:544
void OnSensitivityOffResonanceFreqChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:538
StateType ODMRTraceInitFunc(DynExp::ModuleInstance &Instance)
Definition ODMR.cpp:741
StateType InitializingStateFunc(DynExp::ModuleInstance &Instance)
Definition ODMR.cpp:686
double NextRFModulationDepth
Definition ODMR.h:281
void SetAuxAnalogOutValue(Util::SynchronizedPointer< ModuleDataType > &ModuleData) const
Definition ODMR.cpp:343
void OnSaveIndexChanged(DynExp::ModuleInstance *Instance, int Index) const
Definition ODMR.cpp:502
void OnODMRChartHovered(DynExp::ModuleInstance *Instance, QPointF Point, bool State) const
Definition ODMR.cpp:671
StateType MeasurementSeriesStepFunc(DynExp::ModuleInstance &Instance)
Definition ODMR.cpp:714
void OnODMRChartClicked(DynExp::ModuleInstance *Instance, QPointF Point) const
Definition ODMR.cpp:677
void OnRFFreqSpacingChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:442
void OnRFModFreqChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:478
void OnRFDwellTimeChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:448
void OnStartClicked(DynExp::ModuleInstance *Instance, bool) const
Definition ODMR.cpp:625
void InitSweepValues(Util::SynchronizedPointer< ModuleDataType > &ModuleData)
Definition ODMR.cpp:299
void OnSensitivitySamplingRateChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:550
void OnSensitivityResonanceFreqChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:532
void OnRFModSineClicked(DynExp::ModuleInstance *Instance, bool Checked) const
Definition ODMR.cpp:462
void OnStartSensitivityClicked(DynExp::ModuleInstance *Instance, bool) const
Definition ODMR.cpp:636
void OnRFAutoEnableClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:424
void OnRFOffClicked(DynExp::ModuleInstance *Instance, bool) const
Definition ODMR.cpp:665
void OnRecordSensitivityClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:514
void OnSweepSeriesParamChanged(DynExp::ModuleInstance *Instance, int Index) const
Definition ODMR.cpp:580
void OnEnableSensitivityAnalysisClicked(DynExp::ModuleInstance *Instance, bool Checked) const
Definition ODMR.cpp:562
void OnRecordSensitivityOncePerSweepClicked(DynExp::ModuleInstance *Instance, Qt::CheckState Checked) const
Definition ODMR.cpp:520
void OnRFPowerChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:418
void OnInit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread starts. Override it to lock instruments this m...
Definition ODMR.cpp:378
void OnSweepSeriesStartChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:595
StateType ODMRTraceFinishFunc(DynExp::ModuleInstance &Instance)
Definition ODMR.cpp:779
void OnRFCenterFreqChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:430
void OnSensitivityDurationChanged(DynExp::ModuleInstance *Instance, double Value) const
Definition ODMR.cpp:556
const std::unique_ptr< ModuleDataType > ModuleData
Module data belonging to this ModuleBase instance.
Definition Module.h:788
Refer to ParamsBase::dispatch_tag.
Definition Module.h:191
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
Definition Module.h:840
const ModuleBase::ModuleDataGetterType ModuleDataGetter
Getter for module's data. Refer to ModuleBase::ModuleDataGetterType.
Definition Module.h:872
Refer to ParamsBase::dispatch_tag.
Definition Object.h:2018
QModuleWidget * Widget
User interface widget belonging to the module.
Definition Module.h:1807
void Connect(SenderType *Sender, SignalType Signal, ReceiverType *Receiver, EventType Event)
Uses Qt's connect mechanism to connect a QObject's signal to a DynExp module's event....
Definition Module.h:1816
const Object::ParamsGetterType ParamsGetter
Invoke to obtain the parameters (derived from ParamsBase) of Owner.
Definition Object.h:3710
void UnlockObject(LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer)
Unlocks an Object instance stored in the LinkedObjectWrapperContainer ObjectWrapperContainer....
Definition Object.h:3609
void LockObject(const ParamsBase::Param< ObjectLink< ObjectT > > &LinkParam, LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer, std::chrono::milliseconds Timeout=ObjectLinkBase::LockObjectTimeoutDefault)
Locks an Object instance referenced by a parameter LinkParam of type ParamsBase::Param< ObjectLink< O...
Definition Object.h:3593
const auto & GetOwner() const noexcept
Returns Owner.
Definition Object.h:3556
Data to operate on is invalid for a specific purpose. This indicates a corrupted data structure or fu...
Definition Exception.h:164
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
Definition Util.h:170
Thrown when an operation timed out before it could be completed, especially used for locking shared d...
Definition Exception.h:262
@ Rise
Trigger on rising edge.
@ ExternSingle
Run once after an external trigger signal has been detected.
std::tuple< double, double > FitParams
Definition ODMRWidget.h:45
void WaitForInstruments(InstrTs &... Instruments)
Blocks until every instrument passed to the function as a reference parameter has arrived at a synchr...
std::unique_ptr< ParamsBase > ParamsBasePtrType
Alias for a pointer to the parameter system base class ParamsBase.
Definition Object.h:1807
DynExpErrorCodes
DynExp's error codes
Definition Exception.h:22
std::string ToStr(const T &Value, int Precision=-1)
Converts a (numeric) value of type T to a std::string using operator<< of std::stringstream.
Definition Util.h:688
bool SaveToFile(const QString &Filename, std::string_view Text)
Saves a std::string_view to a file (using QFile). Creates a new file or truncates an existing file's ...
Definition QtUtil.cpp:236
auto RemoveExtFromPath(std::string Path)
Removes the filename's extension from a path.
Definition Util.h:913
std::vector< std::complex< double > > FFT(const std::vector< std::complex< double > > &Data, bool InverseTransform)
Computes the Fast Fourier Transform (FFT) a vector of complex values.
Definition Util.cpp:228
Accumulates include statements to provide a precompiled header.
@ Pulse
Pulse (binary) modulation switching the affected quantity between two values.
@ Frequency
Modulation affecting the waveform's frequency.
@ ExternSingle
Run once after an external trigger signal has been detected.