DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
SpectrumViewer.cpp
Go to the documentation of this file.
1// This file is part of DynExp.
2
3#include "stdafx.h"
4#include "SpectrumViewer.h"
5
7
9{
11 {
12 std::stringstream CSVData;
13 CSVData << std::setprecision(6);
14 CSVData << "ExposureTime = " << ExposureTime.count() << " " << Util::ToUnitStr<DynExpInstr::SpectrometerData::TimeType>() << "\n";
15 CSVData << "HEADER_END\n";
16
18 for (const auto& Sample : Samples)
19 CSVData << Sample.x() << ";" << Sample.y() << "\n";
20
21 return CSVData.str();
22 }
23
28
49
51 {
55
56 try
57 {
58 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance.ModuleDataGetter());
59 auto InstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Spectrometer>(ModuleData->GetSpectrometer()->GetInstrumentData());
60
61 PlotInfo = ModuleData->PlotInfo;
62
63 ModuleData->CurrentExposureTime = InstrData->GetCurrentExposureTime();
64 ModuleData->CurrentLowerFrequency = InstrData->GetCurrentLowerFrequency();
65 ModuleData->CurrentUpperFrequency = InstrData->GetCurrentUpperFrequency();
66 ModuleData->SilentModeEnabled = InstrData->GetSilentModeEnabled();
67 ModuleData->CapturingState = InstrData->GetCapturingState();
68 ModuleData->CapturingProgress = InstrData->GetCapturingProgress();
69
70 if (InstrData->HasSpectrum() && !ModuleData->SpectrumRecordingPaused)
71 Spectrum = InstrData->GetSpectrum();
72
73 NumFailedUpdateAttempts = 0;
74 } // ModuleData and instruments' data unlocked here.
75 catch (const Util::TimeoutException& e)
76 {
77 if (NumFailedUpdateAttempts++ >= 3)
78 Instance.GetOwner().SetWarning(e);
79 }
80
81 if (Spectrum.HasSpectrum())
82 {
84 PlotInfo.ProcessSpectrum(std::move(Spectrum), ProcessedSamples.Samples, 0);
86
87 {
88 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance.ModuleDataGetter());
89
90 ModuleData->CurrentSpectrum = std::move(ProcessedSamples);
91 ModuleData->PlotInfo = std::move(PlotInfo);
92
93 if (!ModuleData->AutoSaveFilename.empty())
94 {
95 SaveSpectrum(ModuleData);
96 ModuleData->AutoSaveFilename.clear();
97
98 if (ModuleData->GetCommunicator().valid())
99 ModuleData->GetCommunicator()->PostEvent(*this, FinishedEvent{});
100 }
101 } // ModuleData unlocked here.
102 }
103 else
104 {
105 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance.ModuleDataGetter());
106
108 PlotInfo.ReprocessSamples(ModuleData->CurrentSpectrum.Samples, 0);
109
110 ModuleData->PlotInfo = std::move(PlotInfo);
111 }
112
114 }
115
117 {
118 IsSavingData = false;
119 NumFailedUpdateAttempts = 0;
120 }
121
122 void SpectrumViewer::MakeConnections(QObject* Backend)
123 {
124 QObject::connect(static_cast<SpectrumViewerBackend*>(Backend), &SpectrumViewerBackend::saveData, &SignalContext, [this]() { OnSaveSpectrum(); });
125
132 }
133
134 void SpectrumViewer::UpdateUIChild(const ModuleBase::ModuleDataGetterType& ModuleDataGetter)
135 {
136 auto Backend = GetBackend<SpectrumViewerBackend>();
137 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(ModuleDataGetter());
138
139 if (!ModuleData->IsUIInitialized())
140 {
141 Backend->SetExposureTimeRange({ Util::NumToT<int>(ModuleData->MinExposureTime.count()), Util::NumToT<int>(ModuleData->MaxExposureTime.count()) });
142 Backend->SetExposureTimeUnit(QString::fromStdString(Util::ToUnitStr<DynExpInstr::SpectrometerData::TimeType>()));
143 Backend->SetLimitRange({ ModuleData->MinFrequency, ModuleData->MaxFrequency });
144 Backend->SetLimitUnit(DynExp::Units::UnitTypeToStr(ModuleData->PlotInfo.XUnit));
145
146 Backend->GetGraph()->InsertSeries("Spectrum");
147
148 ModuleData->SetUIInitialized();
149 }
150
151 switch (ModuleData->CapturingState)
152 {
156 default: Backend->SetState(SpectrumViewerBackend::Ready);
157 }
158
159 if (!Backend->IsSilentFocused())
160 Backend->SetSilent(ModuleData->SilentModeEnabled);
161 if (!Backend->IsExposureTimeFocused())
162 Backend->SetExposureTime(Util::NumToT<int>(ModuleData->CurrentExposureTime.count()));
163 if (!Backend->IsLowerLimitFocused())
164 Backend->SetLowerLimit(ModuleData->CurrentLowerFrequency);
165 if (!Backend->IsUpperLimitFocused())
166 Backend->SetUpperLimit(ModuleData->CurrentUpperFrequency);
167 Backend->SetProgress(ModuleData->CapturingProgress > 0. && ModuleData->CapturingProgress <= 100. ? ModuleData->CapturingProgress / 100. : 0.);
168
169 Backend->GetGraph()->UpdateSeries(0, ModuleData->CurrentSpectrum.Samples, ModuleData->PlotInfo);
170 Backend->GetGraph()->UpdateData(ModuleData->PlotInfo);
171 }
172
174 {
175 if (!Util::SaveToFile(QString::fromStdString(ModuleData->AutoSaveFilename), ModuleData->CurrentSpectrum.ToStr(ModuleData->CurrentExposureTime, ModuleData->PlotInfo)))
176 Util::EventLog().Log("[SpectrumViewer] Saving spectrum as \"" + ModuleData->AutoSaveFilename + "\" to file failed.", Util::ErrorType::Error);
177 }
178
180 {
187
188 auto ModuleParams = DynExp::dynamic_Params_cast<SpectrumViewer>(Instance->ParamsGetter());
189 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
190
191 Instance->LockObject(ModuleParams->Spectrometer, ModuleData->GetSpectrometer());
192 if (ModuleParams->Communicator.ContainsID())
193 Instance->LockObject(ModuleParams->Communicator, ModuleData->GetCommunicator());
194
195 ModuleData->PlotInfo.XUnit = ModuleData->GetSpectrometer()->GetFrequencyUnit();
196 ModuleData->PlotInfo.YUnit = ModuleData->GetSpectrometer()->GetIntensityUnit();
197 ModuleData->MinFrequency = ModuleData->GetSpectrometer()->GetMinFrequency();
198 ModuleData->MaxFrequency = ModuleData->GetSpectrometer()->GetMaxFrequency();
199
200 auto InstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Spectrometer>(ModuleData->GetSpectrometer()->GetInstrumentData());
201 ModuleData->MinExposureTime = InstrData->GetMinExposureTime();
202 ModuleData->MaxExposureTime = InstrData->GetMaxExposureTime();
203 }
204
206 {
207 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
208
209 Instance->UnlockObject(ModuleData->GetSpectrometer());
210 Instance->UnlockObject(ModuleData->GetCommunicator());
211
218 }
219
221 {
222 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
223
224 if (ModuleData->CapturingState == DynExpInstr::SpectrometerData::CapturingStateType::Capturing)
225 return;
226
227 ModuleData->SpectrumRecordingPaused = false;
228 ModuleData->GetSpectrometer()->Record();
229 }
230
232 {
233 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
234
235 ModuleData->SpectrumRecordingPaused = false;
236 ModuleData->AutoSaveFilename.clear();
237 ModuleData->GetSpectrometer()->Abort();
238 }
239
241 {
242 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
243
244 ModuleData->GetSpectrometer()->SetSilentMode(Checked);
245 }
246
248 {
249 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
250
251 ModuleData->GetSpectrometer()->SetExposureTime(DynExpInstr::SpectrometerData::TimeType(Value));
252 }
253
255 {
256 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
257 auto InstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Spectrometer>(ModuleData->GetSpectrometer()->GetInstrumentData());
258
259 if (Value < InstrData->GetCurrentUpperFrequency())
260 ModuleData->GetSpectrometer()->SetFrequencyRange(Value, InstrData->GetCurrentUpperFrequency());
261 }
262
264 {
265 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
266 auto InstrData = DynExp::dynamic_InstrumentData_cast<DynExpInstr::Spectrometer>(ModuleData->GetSpectrometer()->GetInstrumentData());
267
268 if (Value > InstrData->GetCurrentLowerFrequency())
269 ModuleData->GetSpectrometer()->SetFrequencyRange(InstrData->GetCurrentLowerFrequency(), Value);
270 }
271
272 void SpectrumViewer::OnSetFilename(DynExp::ModuleInstance* Instance, const std::string& SaveFilename) const
273 {
274 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
275
276 OnStop(Instance);
277 ModuleData->AutoSaveFilename = SaveFilename + ".csv";
278 }
279
281 {
282 OnRunClicked(Instance);
283 }
284
286 {
287 OnStopClicked(Instance);
288 }
289
291 {
292 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
293 ModuleData->SpectrumRecordingPaused = true;
294 }
295
297 {
298 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(Instance->ModuleDataGetter());
299 ModuleData->SpectrumRecordingPaused = false;
300 }
301
303 {
304 EnsureCallFromOwningThread();
305
306 // As soon as FinishedSavingDataGuard is destroyed, IsSavingData is set back to false.
308 IsSavingData = true;
309
310 auto Filename = Util::PromptSaveFilePathModule(GetWidget(), "Save data", ".csv", " Comma-separated values file (*.csv)");
311 if (Filename.isEmpty())
312 return;
313
314 auto ModuleData = DynExp::dynamic_ModuleData_cast<SpectrumViewer>(GetModuleData());
315 if (!Util::SaveToFile(Filename, ModuleData->CurrentSpectrum.ToStr(ModuleData->CurrentExposureTime, ModuleData->PlotInfo)))
316 QMessageBox::warning(GetWidget(), "DynExp - Error", "Error writing data to file.");
317 }
318}
C++ backend of the SpectrumViewer QML module.
Implementation of a module to plot the spectrum stored in a spectrometer instrument.
Type describing a spectrum as acquired by the Spectrometer instrument.
bool HasSpectrum() const noexcept
Indicates whether the spectrum is empty.
auto & GetSpectrum() const noexcept
Getter for Samples.
@ Warning
The spectrometer is in a warning state, but still ready to acquire a spectrum.
@ Capturing
The spectrometer is currently acquiring a spectrum.
@ Error
The spectrometer is in an error state.
@ Ready
The spectrometer is ready to acquire a spectrum.
std::chrono::milliseconds TimeType
Time type describing the spectrometer's times like its exposure time.
This event signals that an action (like a measurement) started by a TriggerEvent has been completed.
DynExpInstr::SpectrometerData::TimeType CurrentExposureTime
DynExpInstr::SpectrometerData::CapturingStateType CapturingState
DynExpInstr::SpectrometerData::TimeType MinExposureTime
DynExpInstr::SpectrometerData::TimeType MaxExposureTime
void ResetImpl(dispatch_tag< QMLModuleDataBase >) override final
void OnExit(DynExp::ModuleInstance *Instance) const override final
This event is triggered right before the module thread terminates (not due to an exception,...
void SaveSpectrum(Util::SynchronizedPointer< SpectrumViewerData > &ModuleData)
void OnUpperLimitChanged(DynExp::ModuleInstance *Instance, double Value) const
void MakeConnections(QObject *Backend) override final
Use QModuleBase::Connect() to connect Qt QML signals to the module's event functions.
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...
void OnRunClicked(DynExp::ModuleInstance *Instance) const
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...
void OnPauseSpectrumRecording(DynExp::ModuleInstance *Instance) const
void OnLowerLimitChanged(DynExp::ModuleInstance *Instance, double Value) const
void OnTrigger(DynExp::ModuleInstance *Instance) const
void OnSetFilename(DynExp::ModuleInstance *Instance, const std::string &SaveFilename) const
void UpdateUIChild(const ModuleBase::ModuleDataGetterType &ModuleDataGetter) override final
void OnSilentModeToggled(DynExp::ModuleInstance *Instance, bool Checked) const
void OnStop(DynExp::ModuleInstance *Instance) const
void OnResumeSpectrumRecording(DynExp::ModuleInstance *Instance) const
void OnStopClicked(DynExp::ModuleInstance *Instance) const
void ResetImpl(dispatch_tag< QMLModuleBase >) override final
void OnExposureTimeChanged(DynExp::ModuleInstance *Instance, int Value) const
static void Register(const ModuleBase &Listener, CallableT EventFunc, ItemIDType CommunicatorID=ItemIDNotSet)
Registers/Subscribes module Listener to the event with the event function EventFunc....
Definition Module.h:1263
static void Deregister(const ModuleBase &Listener)
Deregisters/unsubscribes module Listener from the event, regardless of the inter-module communicator ...
Definition Module.h:1272
Refer to ParamsBase::dispatch_tag.
Definition Module.h:192
Defines data for a thread belonging to a ModuleBase instance. Refer to RunnableInstance.
Definition Module.h:841
const ModuleBase::ModuleDataGetterType ModuleDataGetter
Getter for module's data. Refer to ModuleBase::ModuleDataGetterType.
Definition Module.h:873
Refer to ParamsBase::dispatch_tag.
Definition Object.h:2026
const Object::ParamsGetterType ParamsGetter
Invoke to obtain the parameters (derived from ParamsBase) of Owner.
Definition Object.h:3718
void UnlockObject(LinkedObjectWrapperContainer< ObjectT > &ObjectWrapperContainer)
Unlocks an Object instance stored in the LinkedObjectWrapperContainer ObjectWrapperContainer....
Definition Object.h:3617
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:3601
const auto & GetOwner() const noexcept
Returns Owner.
Definition Object.h:3564
void Log(const std::string &Message, const ErrorType Type=ErrorType::Info, const size_t Line=0, const std::string &Function="", const std::string &File="", const int ErrorCode=0, const std::stacktrace &Trace={}) noexcept
Logs an event from information specified manually.
Definition Util.cpp:317
Holds a CallableMemberWrapper and invokes its callable when being destroyed.
Definition Util.h:495
Pointer to lock a class derived from ISynchronizedPointerLockable for synchronizing between threads....
Definition Util.h:171
Thrown when an operation timed out before it could be completed, especially used for locking shared d...
Definition Exception.h:262
const char * UnitTypeToStr(UnitType Unit)
Returns a descriptive string of the given unit's type (e.g. 'dBm').
Definition Units.cpp:104
DynExpErrorCodes
DynExp's error codes
Definition Exception.h:22
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
EventLogger & EventLog()
This function holds a static EventLogger instance and returns a reference to it. DynExp uses only one...
Definition Util.cpp:517
QString PromptSaveFilePathModule(DynExp::QModuleWidget *Parent, const QString &Title, const QString &DefaultSuffix, const QString &NameFilter)
Works as PromptOpenFilePath() but asks the user to select a single file which does not need to exist....
Definition QtUtil.cpp:143
Accumulates include statements to provide a precompiled header.
DynExp::Units::UnitType XUnit
Joint unit of the plot's x axis.
Definition GraphUtil.h:104
void AdjustAxesLimits()
Adjusts MinValues and MaxValues to best display all data series.
bool ProcessSpectrum(DynExpInstr::SpectrometerData::SpectrumType Spectrum, QList< QPointF > &Samples, const size_t SeriesIndex)
Converts Spectrum to displayable format and stores its minimal and maximal values in this DynExpLineG...
void ReprocessSamples(const QList< QPointF > &Samples, const size_t SeriesIndex)
If data plotting is not enabled (running), the available and already plotted samples have to be repro...
void ResetHoveredSample()
Removes the stored hovered sample.
void Reset()
Resets the instance to generate information from new sample series.
Definition GraphUtil.cpp:20
DynExp::Units::UnitType YUnit
Joint unit of the plot's y axis.
Definition GraphUtil.h:109
std::string ToStr(DynExpInstr::SpectrometerData::TimeType ExposureTime, const DynExpModule::Graph::LineGraphPlotInfo &PlotInfo) const