diff --git a/gr-util/include/gr-util/grfftfloatproxy.h b/gr-util/include/gr-util/grfftfloatproxy.h index cf2a25f248..631d3ec7cd 100644 --- a/gr-util/include/gr-util/grfftfloatproxy.h +++ b/gr-util/include/gr-util/grfftfloatproxy.h @@ -21,6 +21,7 @@ class SCOPY_GR_UTIL_EXPORT GRFFTFloatProc : public GRProxyBlock public: GRFFTFloatProc(QObject *parent = nullptr); void setWindow(gr::fft::window::win_type w); + void setWindowCorrection(bool b); void setPowerOffset(double); void setNrBits(int); void build_blks(GRTopBlock *top); @@ -31,7 +32,7 @@ class SCOPY_GR_UTIL_EXPORT GRFFTFloatProc : public GRProxyBlock int nrBits; QMap m_wincorr_factor; gr::fft::fft_v::sptr fft; - + bool m_windowCorr; gr::blocks::multiply_const_ff::sptr mult_nrbits; gr::blocks::complex_to_mag_squared::sptr ctm; gr::blocks::multiply_const_cc::sptr mult_wind_corr; @@ -49,6 +50,7 @@ class SCOPY_GR_UTIL_EXPORT GRFFTComplexProc : public GRProxyBlock GRFFTComplexProc(QObject *parent = nullptr); void setWindow(gr::fft::window::win_type w); void setPowerOffset(double); + void setWindowCorrection(bool b); void setNrBits(int); void build_blks(GRTopBlock *top); void destroy_blks(GRTopBlock *top); @@ -57,6 +59,7 @@ class SCOPY_GR_UTIL_EXPORT GRFFTComplexProc : public GRProxyBlock double m_powerOffset; QMap m_wincorr_factor; int nrBits; + bool m_windowCorr; gr::fft::fft_v::sptr fft_complex; gr::blocks::multiply_const_cc::sptr mult_nrbits; gr::blocks::complex_to_mag_squared::sptr ctm; diff --git a/gr-util/src/grfftfloatproxy.cpp b/gr-util/src/grfftfloatproxy.cpp index 3dcc516d76..157ac790fb 100644 --- a/gr-util/src/grfftfloatproxy.cpp +++ b/gr-util/src/grfftfloatproxy.cpp @@ -9,6 +9,7 @@ GRFFTFloatProc::GRFFTFloatProc(QObject *parent) m_fftwindow = gr::fft::window::WIN_HANN; m_powerOffset = 0; nrBits = 12; + m_windowCorr = true; m_wincorr_factor[gr::fft::window::WIN_HANN] = 2; m_wincorr_factor[gr::fft::window::WIN_HANNING] = 2; @@ -25,8 +26,12 @@ void GRFFTFloatProc::setWindow(gr::fft::window::win_type w) { m_fftwindow = w; Q_EMIT requestRebuild(); - /*if(mul) - mul->set_k(m_scale);*/ +} + +void GRFFTFloatProc::setWindowCorrection(bool b) +{ + m_windowCorr = b; + Q_EMIT requestRebuild(); } void GRFFTFloatProc::setPowerOffset(double val) @@ -52,7 +57,7 @@ void GRFFTFloatProc::build_blks(GRTopBlock *top) auto fft_size = top->vlen(); auto window = gr::fft::window::build(m_fftwindow, fft_size); - auto corr = m_wincorr_factor[m_fftwindow]; + auto corr = (m_windowCorr) ? m_wincorr_factor[m_fftwindow] : 1; fft = gr::fft::fft_v::make(fft_size, window, false); ctm = gr::blocks::complex_to_mag_squared::make(fft_size); @@ -101,6 +106,8 @@ GRFFTComplexProc::GRFFTComplexProc(QObject *parent) m_fftwindow = gr::fft::window::WIN_HANNING; nrBits = 12; m_powerOffset = 0; + m_windowCorr = true; + m_wincorr_factor[gr::fft::window::WIN_HANN] = 2; m_wincorr_factor[gr::fft::window::WIN_HANNING] = 2; m_wincorr_factor[gr::fft::window::WIN_BLACKMAN] = 2; @@ -120,6 +127,11 @@ void GRFFTComplexProc::setWindow(gr::fft::window::win_type w) mul->set_k(m_scale);*/ } +void GRFFTComplexProc::setWindowCorrection(bool b) { + m_windowCorr = b; + Q_EMIT requestRebuild(); +} + void GRFFTComplexProc::setPowerOffset(double val) { m_powerOffset = val; @@ -142,7 +154,7 @@ void GRFFTComplexProc::build_blks(GRTopBlock *top) m_top = top; auto fft_size = top->vlen(); auto window = gr::fft::window::build(m_fftwindow, fft_size); - auto corr = m_wincorr_factor[m_fftwindow]; + auto corr = (m_windowCorr) ? m_wincorr_factor[m_fftwindow] : 1; mult_nrbits = gr::blocks::multiply_const_cc::make(gr_complex(1.0 / (1<::make(fft_size, window, true); diff --git a/gr-util/src/griiocomplexchannelsrc.cpp b/gr-util/src/griiocomplexchannelsrc.cpp index b3223cd0aa..7c74b7691d 100644 --- a/gr-util/src/griiocomplexchannelsrc.cpp +++ b/gr-util/src/griiocomplexchannelsrc.cpp @@ -26,8 +26,8 @@ void GRIIOComplexChannelSrc::build_blks(GRTopBlock *top) s2v = gr::blocks::stream_to_vector::make(sizeof(gr_complex), top->vlen()); - top->connect(s2f[0], 0, f2c, 1); - top->connect(s2f[1], 0, f2c, 0); + top->connect(s2f[0], 0, f2c, 0); + top->connect(s2f[1], 0, f2c, 1); top->connect(f2c, 0, s2v, 0); start_blk.append(s2f[0]); start_blk.append(s2f[1]); diff --git a/gui/include/gui/plotchannel.h b/gui/include/gui/plotchannel.h index 33e26fa43f..3a2c8cdcd3 100644 --- a/gui/include/gui/plotchannel.h +++ b/gui/include/gui/plotchannel.h @@ -56,6 +56,7 @@ class SCOPY_GUI_EXPORT PlotChannel : public QObject void setYAxis(PlotAxis *newYAxis); void setXAxis(PlotAxis *newXAxis); + double getValueAt(double pos); public Q_SLOTS: void raise(); diff --git a/gui/include/gui/plotcursors.h b/gui/include/gui/plotcursors.h index 5e011ac3b8..a1d98f2651 100644 --- a/gui/include/gui/plotcursors.h +++ b/gui/include/gui/plotcursors.h @@ -46,7 +46,6 @@ public Q_SLOTS: void initUI(); void connectSignals(); void updateTracking(); - double getHorizIntersectionAt(double pos); }; } // namespace scopy diff --git a/gui/include/gui/widgets/measurementpanel.h b/gui/include/gui/widgets/measurementpanel.h index 605b9da8f6..4f5ad0d63a 100644 --- a/gui/include/gui/widgets/measurementpanel.h +++ b/gui/include/gui/widgets/measurementpanel.h @@ -121,5 +121,6 @@ public Q_SLOTS: QHBoxLayout *panelLayout; QList m_labels; }; + } // namespace scopy #endif // MEASUREMENTPANEL_H diff --git a/gui/include/gui/widgets/measurementsettings.h b/gui/include/gui/widgets/measurementsettings.h index 46cda88437..ff702299b7 100644 --- a/gui/include/gui/widgets/measurementsettings.h +++ b/gui/include/gui/widgets/measurementsettings.h @@ -1,6 +1,7 @@ #ifndef MEASUREMENTSETTINGS_H #define MEASUREMENTSETTINGS_H +#include "menusectionwidget.h" #include "scopy-gui_export.h" #include @@ -23,6 +24,13 @@ class SCOPY_GUI_EXPORT MeasurementSettings : public QWidget bool measurementEnabled(); bool statsEnabled(); + bool markerEnabled(); + + MenuSectionWidget *getMarkerSection() const; + + MenuSectionWidget *getStatsSection() const; + + MenuSectionWidget *getMeasureSection() const; Q_SIGNALS: void toggleAllMeasurements(bool); @@ -31,10 +39,16 @@ class SCOPY_GUI_EXPORT MeasurementSettings : public QWidget void sortStats(MeasurementSortingType type); void enableMeasurementPanel(bool b); void enableStatsPanel(bool b); + void enableMarkerPanel(bool b); private: MenuOnOffSwitch *measurePanelSwitch; MenuOnOffSwitch *statsPanelSwitch; + MenuOnOffSwitch *markerPanelSwitch; + + MenuSectionWidget *markerSection; + MenuSectionWidget *statsSection; + MenuSectionWidget *measureSection; }; } // namespace scopy diff --git a/gui/src/plotchannel.cpp b/gui/src/plotchannel.cpp index 1bc5bb9e55..7ec2fe275b 100644 --- a/gui/src/plotchannel.cpp +++ b/gui/src/plotchannel.cpp @@ -197,4 +197,61 @@ void PlotChannel::setStyle(int newStyle) setStyleInternal(newStyle); Q_EMIT styleChanged(); } + + +double PlotChannel::getValueAt(double pos) +{ + auto tmp = this; + QwtSeriesData *curve_data = tmp->curve()->data(); + int n = curve_data->size(); + + if(n == 0) { + return -1; + } else { + double leftTime, rightTime, leftCustom, rightCustom; + int rightIndex = -1; + int leftIndex = -1; + int left = 0; + int right = n - 1; + + if(curve_data->sample(right).x() < pos || curve_data->sample(left).x() > pos) { + return -1; + } + + while(left <= right) { + int mid = (left + right) / 2; + double xData = curve_data->sample(mid).x(); + + if(xData == pos) { + if(mid > 0) { + leftIndex = mid - 1; + rightIndex = mid; + } + break; + } else if(xData < pos) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + if((leftIndex == -1 || rightIndex == -1) && left > 0) { + leftIndex = left - 1; + rightIndex = left; + } + if(leftIndex == -1 || rightIndex == -1) { + return -1; + } + + leftTime = curve_data->sample(leftIndex).x(); + rightTime = curve_data->sample(rightIndex).x(); + + leftCustom = curve_data->sample(leftIndex).y(); + rightCustom = curve_data->sample(rightIndex).y(); + + double value = (rightCustom - leftCustom) / (rightTime - leftTime) * (pos - leftTime) + leftCustom; + + return value; + } +} #include "moc_plotchannel.cpp" diff --git a/gui/src/plotcursors.cpp b/gui/src/plotcursors.cpp index 1f9c2f9b9c..1c3ab401f2 100644 --- a/gui/src/plotcursors.cpp +++ b/gui/src/plotcursors.cpp @@ -149,8 +149,9 @@ void PlotCursors::displayIntersection() plotMarker1->setAxes(xaxis, yaxis); plotMarker2->setAxes(xaxis, yaxis); - plotMarker1->setValue(h1CursorPos, getHorizIntersectionAt(h1CursorPos)); - plotMarker2->setValue(h2CursorPos, getHorizIntersectionAt(h2CursorPos)); + auto ch = m_plot->selectedChannel(); + plotMarker1->setValue(h1CursorPos, ch->getValueAt(h1CursorPos)); + plotMarker2->setValue(h2CursorPos, ch->getValueAt(h2CursorPos)); Q_EMIT m_yCursors.first->scalePosChanged(plotMarker1->yValue()); Q_EMIT m_yCursors.second->scalePosChanged(plotMarker2->yValue()); @@ -170,60 +171,5 @@ void PlotCursors::setXHandlePos(HandlePos pos) m_xCursors.second->handle()->setHandlePos(pos); } -double PlotCursors::getHorizIntersectionAt(double pos) -{ - auto tmp = m_plot->selectedChannel(); - QwtSeriesData *curve_data = tmp->curve()->data(); - int n = curve_data->size(); - - if(n == 0) { - return -1; - } else { - double leftTime, rightTime, leftCustom, rightCustom; - int rightIndex = -1; - int leftIndex = -1; - int left = 0; - int right = n - 1; - - if(curve_data->sample(right).x() < pos || curve_data->sample(left).x() > pos) { - return -1; - } - - while(left <= right) { - int mid = (left + right) / 2; - double xData = curve_data->sample(mid).x(); - - if(xData == pos) { - if(mid > 0) { - leftIndex = mid - 1; - rightIndex = mid; - } - break; - } else if(xData < pos) { - left = mid + 1; - } else { - right = mid - 1; - } - } - - if((leftIndex == -1 || rightIndex == -1) && left > 0) { - leftIndex = left - 1; - rightIndex = left; - } - if(leftIndex == -1 || rightIndex == -1) { - return -1; - } - - leftTime = curve_data->sample(leftIndex).x(); - rightTime = curve_data->sample(rightIndex).x(); - - leftCustom = curve_data->sample(leftIndex).y(); - rightCustom = curve_data->sample(rightIndex).y(); - - double value = (rightCustom - leftCustom) / (rightTime - leftTime) * (pos - leftTime) + leftCustom; - - return value; - } -} #include "moc_plotcursors.cpp" diff --git a/gui/src/widgets/measurementsettings.cpp b/gui/src/widgets/measurementsettings.cpp index 6ebf37bfb6..787081cd36 100644 --- a/gui/src/widgets/measurementsettings.cpp +++ b/gui/src/widgets/measurementsettings.cpp @@ -13,7 +13,7 @@ MeasurementSettings::MeasurementSettings(QWidget *parent) // setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); lay->setMargin(0); - MenuSectionWidget *measureSection = new MenuSectionWidget(this); + measureSection = new MenuSectionWidget(this); measurePanelSwitch = new MenuOnOffSwitch("Measure Panel", this); measurePanelSwitch->onOffswitch()->setChecked(true); QHBoxLayout *hlay1 = new QHBoxLayout(); @@ -73,7 +73,7 @@ MeasurementSettings::MeasurementSettings(QWidget *parent) hlay2->addWidget(mesaureSortByChannel); hlay2->addWidget(measureSortByType); - MenuSectionWidget *statsSection = new MenuSectionWidget(this); + statsSection = new MenuSectionWidget(this); statsPanelSwitch = new MenuOnOffSwitch("Stats Panel", this); connect(statsPanelSwitch->onOffswitch(), &QAbstractButton::toggled, this, [=](bool b) { Q_EMIT enableStatsPanel(b); }); @@ -138,14 +138,40 @@ MeasurementSettings::MeasurementSettings(QWidget *parent) hlay4->addWidget(statsSortByChannel); hlay4->addWidget(statsSortByType); + markerSection = new MenuSectionWidget(this); + markerPanelSwitch = new MenuOnOffSwitch("Marker Panel", this); + connect(markerPanelSwitch->onOffswitch(), &QAbstractButton::toggled, this, + [=](bool b) { Q_EMIT enableMarkerPanel(b); }); + markerSection->contentLayout()->addWidget(markerPanelSwitch); + + markerPanelSwitch->onOffswitch()->setChecked(false); + lay->addWidget(measureSection); lay->addWidget(statsSection); + lay->addWidget(markerSection); + + } MeasurementSettings::~MeasurementSettings() {} bool MeasurementSettings::measurementEnabled() { return measurePanelSwitch->onOffswitch()->isChecked(); } - bool MeasurementSettings::statsEnabled() { return statsPanelSwitch->onOffswitch()->isChecked(); } +bool MeasurementSettings::markerEnabled() { return markerPanelSwitch->onOffswitch()->isChecked(); } + +MenuSectionWidget *MeasurementSettings::getMarkerSection() const +{ + return markerSection; +} + +MenuSectionWidget *MeasurementSettings::getStatsSection() const +{ + return statsSection; +} + +MenuSectionWidget *MeasurementSettings::getMeasureSection() const +{ + return measureSection; +} #include "moc_measurementsettings.cpp" diff --git a/gui/src/widgets/menuplotchannelcurvestylecontrol.cpp b/gui/src/widgets/menuplotchannelcurvestylecontrol.cpp index d1c60ed4fe..8462e4875f 100644 --- a/gui/src/widgets/menuplotchannelcurvestylecontrol.cpp +++ b/gui/src/widgets/menuplotchannelcurvestylecontrol.cpp @@ -100,7 +100,6 @@ void MenuPlotChannelCurveStyleControl::setThicknessSlot() } } - qInfo() << m_channels.count() << thickness; cbThicknessW->combo()->setCurrentText(QString::number(thickness)); } diff --git a/gui/src/widgets/plotinfowidgets.cpp b/gui/src/widgets/plotinfowidgets.cpp index 7fbed35248..0647f97f5c 100644 --- a/gui/src/widgets/plotinfowidgets.cpp +++ b/gui/src/widgets/plotinfowidgets.cpp @@ -14,6 +14,7 @@ HDivInfo::HDivInfo(PlotWidget *plot, QWidget *parent) { StyleHelper::PlotInfoLabel(this); m_mpf->setTrimZeroes(true); + m_mpf->setTwoDecimalMode(false); connect(m_plot->navigator(), &PlotNavigator::rectChanged, this, &HDivInfo::onRectChanged); onRectChanged(); @@ -55,6 +56,7 @@ TimeSamplingInfo::TimeSamplingInfo(QWidget *parent) { StyleHelper::PlotInfoLabel(this); m_mpf->setTrimZeroes(true); + m_mpf->setTwoDecimalMode(false); } TimeSamplingInfo::~TimeSamplingInfo() {} @@ -77,6 +79,7 @@ FFTSamplingInfo::FFTSamplingInfo(QWidget *parent) { StyleHelper::PlotInfoLabel(this); m_mpf->setTrimZeroes(true); + m_mpf->setTwoDecimalMode(false); } FFTSamplingInfo::~FFTSamplingInfo() {} @@ -84,9 +87,9 @@ FFTSamplingInfo::~FFTSamplingInfo() {} void FFTSamplingInfo::update(SamplingInfo info) { QString text; - text = QString("%1").arg(m_mpf->format(info.plotSize, "samples", 2)); + text = QString("%1").arg(m_mpf->format(info.plotSize, "samples", 3)); if(info.sampleRate != 1) { - text += QString(" at %2").arg(m_mpf->format(info.sampleRate, "sps", 2)); + text += QString(" at %2").arg(m_mpf->format(info.sampleRate, "sps", 3)); } if(info.freqOffset != 0) { text += QString("\nCenter Frequency: %1").arg(m_mpf->format(info.freqOffset, "Hz", 3)); diff --git a/plugins/adc/src/adcfftinstrumentcontroller.cpp b/plugins/adc/src/adcfftinstrumentcontroller.cpp index 2089784940..329d7977e0 100644 --- a/plugins/adc/src/adcfftinstrumentcontroller.cpp +++ b/plugins/adc/src/adcfftinstrumentcontroller.cpp @@ -91,6 +91,7 @@ void ADCFFTInstrumentController::init() m_ui->m_settingsBtn->animateClick(); m_ui->sync()->setVisible(false); + m_measureComponent->measureSettings()->getStatsSection()->setVisible(false); } void ADCFFTInstrumentController::createIIODevice(AcqTreeNode *node) @@ -153,6 +154,24 @@ void ADCFFTInstrumentController::createIIOFloatChannel(AcqTreeNode *node) m_defaultRealCh = c; m_plotComponentManager->selectChannel(c); } + connect(c->markerController(), &MarkerController::markerInfoUpdated,this, [=](){ + auto info = c->markerController()->markerInfo(); + QString name = c->name(); + m_plotComponentManager->markerPanel()->updateChannel(name, info); + }); + + + auto markerController = dynamic_cast(c->plotChannelCmpt())->markerController(); + connect(markerController, &MarkerController::markerEnabled, this, [=](bool b){ + if(b) { + m_plotComponentManager->markerPanel()->newChannel(c->name(), c->pen()); + } else { + m_plotComponentManager->markerPanel()->deleteChannel(c->name()); + } + + int markerCount = m_plotComponentManager->markerPanel()->markerCount(); + Q_EMIT m_measureComponent->measureSettings()->enableMarkerPanel(markerCount != 0); + }); } void ADCFFTInstrumentController::createIIOComplexChannel(AcqTreeNode *node_I, AcqTreeNode *node_Q) @@ -199,6 +218,23 @@ void ADCFFTInstrumentController::createIIOComplexChannel(AcqTreeNode *node_I, Ac if(m_defaultComplexCh == nullptr) { m_defaultComplexCh = c; } + + connect(c->markerController(), &MarkerController::markerInfoUpdated,this, [=](){ + auto info = c->markerController()->markerInfo(); + m_plotComponentManager->markerPanel()->updateChannel(c->name(), info); + }); + + auto markerController = dynamic_cast(c->plotChannelCmpt())->markerController(); + connect(markerController, &MarkerController::markerEnabled, this, [=](bool b){ + if(b) { + m_plotComponentManager->markerPanel()->newChannel(c->name(), c->pen()); + } else { + m_plotComponentManager->markerPanel()->deleteChannel(c->name()); + } + + int markerCount = m_plotComponentManager->markerPanel()->markerCount(); + Q_EMIT m_measureComponent->measureSettings()->enableMarkerPanel(markerCount != 0); + }); } void ADCFFTInstrumentController::createFFTSink(AcqTreeNode *node) @@ -226,10 +262,12 @@ void ADCFFTInstrumentController::createFFTSink(AcqTreeNode *node) connect(m_ui->m_complex, &QAbstractButton::toggled, m_fftPlotSettingsComponent, &FFTPlotManagerSettings::setComplexMode); connect(m_ui->m_complex, &QAbstractButton::toggled, this, [=]() { - if(m_ui->m_complex->isChecked()) { + if(m_ui->m_complex->isChecked()) { m_plotComponentManager->selectChannel(m_defaultComplexCh); + Q_EMIT m_defaultComplexCh->requestChannelMenu(false); } else { m_plotComponentManager->selectChannel(m_defaultRealCh); + Q_EMIT m_defaultRealCh->requestChannelMenu(false); } }); @@ -299,8 +337,8 @@ bool ADCFFTInstrumentController::getComplexChannelPair(AcqTreeNode *node, AcqTre return false; } - *node_i = m_complexChannels[cnt - 2]; - *node_q = m_complexChannels[cnt - 1]; + *node_i = m_complexChannels[cnt - 1]; + *node_q = m_complexChannels[cnt - 2]; return true; } diff --git a/plugins/adc/src/adcinstrument.cpp b/plugins/adc/src/adcinstrument.cpp index dacff79efe..382f19b003 100644 --- a/plugins/adc/src/adcinstrument.cpp +++ b/plugins/adc/src/adcinstrument.cpp @@ -155,7 +155,18 @@ void ADCInstrument::addDevice(CollapsableMenuControlButton *b, ToolComponent *de }); } -void ADCInstrument::addChannel(MenuControlButton *btn, ToolComponent *ch, CompositeWidget *c) +void ADCInstrument::switchToChannelMenu(QString id, bool force) { + if(force) { + if(!channelsBtn->button()->isChecked()) { + // Workaround because QButtonGroup and setChecked do not interact programatically + channelsBtn->button()->animateClick(1); + } + tool->requestMenu(channelsMenuId); + } + rightStack->show(id); +} + +void ADCInstrument::addChannel(MenuControlButton *btn, ChannelComponent *ch, CompositeWidget *c) { c->add(btn); channelGroup->addButton(btn); @@ -168,15 +179,12 @@ void ADCInstrument::addChannel(MenuControlButton *btn, ToolComponent *ch, Compos connect(btn, &QAbstractButton::clicked, this, [=](bool b) { if(b) { - if(!channelsBtn->button()->isChecked()) { - // Workaround because QButtonGroup and setChecked do not interact programatically - channelsBtn->button()->animateClick(1); - } - tool->requestMenu(channelsMenuId); - rightStack->show(id); + switchToChannelMenu(id, true); } }); + connect(ch, &ChannelComponent::requestChannelMenu, this, [=](bool f){ switchToChannelMenu(id, f);}); + /*setupChannelSnapshot(ch); setupChannelMeasurement(ch); setupChannelDelete(ch);*/ diff --git a/plugins/adc/src/adcinstrument.h b/plugins/adc/src/adcinstrument.h index 84a2515e0c..f09f084e76 100644 --- a/plugins/adc/src/adcinstrument.h +++ b/plugins/adc/src/adcinstrument.h @@ -50,7 +50,8 @@ public Q_SLOTS: void stopped(); void started(); void addDevice(CollapsableMenuControlButton *b, ToolComponent *dev); - void addChannel(MenuControlButton *btn, ToolComponent *ch, CompositeWidget *c); + void addChannel(MenuControlButton *btn, ChannelComponent *ch, CompositeWidget *c); + void switchToChannelMenu(QString id, bool force = true); Q_SIGNALS: void requestStart(); diff --git a/plugins/adc/src/adctimeinstrumentcontroller.cpp b/plugins/adc/src/adctimeinstrumentcontroller.cpp index b60d05d7fe..a06e8be5cd 100644 --- a/plugins/adc/src/adctimeinstrumentcontroller.cpp +++ b/plugins/adc/src/adctimeinstrumentcontroller.cpp @@ -92,6 +92,8 @@ void ADCTimeInstrumentController::init() m_ui->m_settingsBtn->animateClick(); m_ui->sync()->setVisible(false); + + m_measureComponent->measureSettings()->getMarkerSection()->setVisible(false); } void ADCTimeInstrumentController::createTimeSink(AcqTreeNode *node) diff --git a/plugins/adc/src/channelcomponent.h b/plugins/adc/src/channelcomponent.h index b40c4047ba..07496ec363 100644 --- a/plugins/adc/src/channelcomponent.h +++ b/plugins/adc/src/channelcomponent.h @@ -47,6 +47,9 @@ class SCOPY_ADC_EXPORT ChannelComponent : public QWidget, virtual SamplingInfo samplingInfo() override; virtual void setSamplingInfo(SamplingInfo p) override; +Q_SIGNALS: + void requestChannelMenu(bool force = true); + protected: QString m_channelName; QPen m_pen; diff --git a/plugins/adc/src/freq/fftplotcomponentchannel.cpp b/plugins/adc/src/freq/fftplotcomponentchannel.cpp index fd9d1b7a03..4393882485 100644 --- a/plugins/adc/src/freq/fftplotcomponentchannel.cpp +++ b/plugins/adc/src/freq/fftplotcomponentchannel.cpp @@ -16,11 +16,16 @@ FFTPlotComponentChannel::FFTPlotComponentChannel(ChannelComponent *ch, FFTPlotCo m_ch = ch; m_plotComponent = nullptr; + m_markerController = new MarkerController(this, this); initPlotComponent(plotComponent); m_fftPlotYAxis->setUnits("dB"); m_fftPlotCh->xAxis()->setUnits("samples"); m_fftPlotYAxis->setInterval(-2048, 2048); + + m_markerController->init(); + + } void FFTPlotComponentChannel::deinitPlotComponent() @@ -37,6 +42,11 @@ void FFTPlotComponentChannel::deinitPlotComponent() delete m_fftPlotAxisHandle; } +MarkerController *FFTPlotComponentChannel::markerController() const +{ + return m_markerController; +} + void FFTPlotComponentChannel::initPlotComponent(PlotComponent *pc) { FFTPlotComponent *plotComponent = dynamic_cast(pc); @@ -75,6 +85,8 @@ void FFTPlotComponentChannel::initPlotComponent(PlotComponent *pc) lockYAxis(true); m_fftPlotYAxis->setInterval(-2048, 2048); refreshData(true); + + m_markerController->setPlot(fftplot->plot()); } FFTPlotComponentChannel::~FFTPlotComponentChannel() {} @@ -88,19 +100,22 @@ void FFTPlotComponentChannel::refreshData(bool copy) void FFTPlotComponentChannel::onNewData(const float *xData_, const float *yData_, size_t size, bool copy) { refreshData(copy); + m_markerController->computeMarkers(); } void FFTPlotComponentChannel::lockYAxis(bool b) { m_singleYMode = b; if(m_singleYMode) { - PlotAxis *time = m_plotComponent->fftPlot()->yAxis(); - m_plotComponent->fftPlot()->plotChannelChangeYAxis(m_fftPlotCh, time); + PlotAxis *y = m_plotComponent->fftPlot()->yAxis(); + m_plotComponent->fftPlot()->plotChannelChangeYAxis(m_fftPlotCh, y); } else { - PlotAxis *time = m_fftPlotYAxis; - m_plotComponent->fftPlot()->plotChannelChangeYAxis(m_fftPlotCh, time); + PlotAxis *y = m_fftPlotYAxis; + m_plotComponent->fftPlot()->plotChannelChangeYAxis(m_fftPlotCh, y); } + m_markerController->setAxes(m_fftPlotCh->xAxis()->axisId(), m_fftPlotCh->yAxis()->axisId()); + m_fftPlotAxisHandle->handle()->setVisible(!b); m_plotComponent->refreshAxisLabels(); m_plotComponent->replot(); @@ -134,6 +149,7 @@ void FFTPlotComponentChannel::enable() m_fftPlotAxisHandle->handle()->raise(); } m_enabled = true; + m_markerController->setEnabled(true); } void FFTPlotComponentChannel::disable() @@ -143,4 +159,5 @@ void FFTPlotComponentChannel::disable() m_fftPlotAxisHandle->handle()->setVisible(false); } m_enabled = false; + m_markerController->setEnabled(false); } diff --git a/plugins/adc/src/freq/fftplotcomponentchannel.h b/plugins/adc/src/freq/fftplotcomponentchannel.h index fc1c1cfdc7..76b185d28b 100644 --- a/plugins/adc/src/freq/fftplotcomponentchannel.h +++ b/plugins/adc/src/freq/fftplotcomponentchannel.h @@ -7,6 +7,7 @@ #include #include "fftplotcomponent.h" #include +#include "markercontroller.h" namespace scopy { namespace adc { @@ -22,6 +23,7 @@ class SCOPY_ADC_EXPORT FFTPlotComponentChannel : public QObject, public PlotComp ChannelComponent *channelComponent() override; PlotComponent *plotComponent() override; PlotChannel *plotChannel() override; + MarkerController *markerController() const; public Q_SLOTS: void enable() override; @@ -42,6 +44,9 @@ public Q_SLOTS: ChannelComponent *m_ch; bool m_singleYMode = false; bool m_enabled; + +private: + MarkerController *m_markerController; }; } // namespace adc } // namespace scopy diff --git a/plugins/adc/src/freq/fftplotcomponentsettings.cpp b/plugins/adc/src/freq/fftplotcomponentsettings.cpp index acf2d530d5..ed9a6d85cb 100644 --- a/plugins/adc/src/freq/fftplotcomponentsettings.cpp +++ b/plugins/adc/src/freq/fftplotcomponentsettings.cpp @@ -79,6 +79,17 @@ FFTPlotComponentSettings::FFTPlotComponentSettings(FFTPlotComponent *plt, QWidge } }); + m_windowChkb = new MenuOnOffSwitch("Window Correction", this); + connect(m_windowChkb->onOffswitch(), &QAbstractButton::toggled, this, [=](bool b) { + for(auto c : m_channels) { + if(dynamic_cast(c)) { + FFTChannel *fc = dynamic_cast(c); + fc->setWindowCorrection(b); + } + } + }); + m_windowChkb->onOffswitch()->setChecked(true); + m_curve = new MenuPlotChannelCurveStyleControl(plotMenu); m_deletePlot = new QPushButton("DELETE PLOT"); @@ -88,7 +99,8 @@ FFTPlotComponentSettings::FFTPlotComponentSettings(FFTPlotComponent *plt, QWidge yaxis->contentLayout()->addWidget(m_yCtrl); yaxis->contentLayout()->addWidget(m_yPwrOffset); yaxis->contentLayout()->addWidget(m_windowCb); - + yaxis->contentLayout()->addWidget(m_windowChkb); + yaxis->contentLayout()->setSpacing(10); plotMenu->contentLayout()->addWidget(plotTitleLabel); plotMenu->contentLayout()->addWidget(plotTitle); diff --git a/plugins/adc/src/freq/fftplotcomponentsettings.h b/plugins/adc/src/freq/fftplotcomponentsettings.h index 86e273e965..032db866d7 100644 --- a/plugins/adc/src/freq/fftplotcomponentsettings.h +++ b/plugins/adc/src/freq/fftplotcomponentsettings.h @@ -36,6 +36,7 @@ public Q_SLOTS: MenuSpinbox *m_yPwrOffset; MenuCombo *m_windowCb; + MenuOnOffSwitch *m_windowChkb; QList m_channels; QPushButton *m_deletePlot; diff --git a/plugins/adc/src/freq/grfftchannelcomponent.cpp b/plugins/adc/src/freq/grfftchannelcomponent.cpp index 4210cdf259..0228cfdd74 100644 --- a/plugins/adc/src/freq/grfftchannelcomponent.cpp +++ b/plugins/adc/src/freq/grfftchannelcomponent.cpp @@ -47,6 +47,9 @@ GRFFTChannelComponent::GRFFTChannelComponent(GRIIOFloatChannelNode *node_I, GRII connect(this, &GRFFTChannelComponent::windowChanged, this, [=](int w) { dynamic_cast(m_grtch)->setWindow(w); }); + connect(this, &GRFFTChannelComponent::windowCorrectionChanged, this, + [=](bool b) { dynamic_cast(m_grtch)->setWindowCorrection(b); }); + m_complex = true; _init(); @@ -74,6 +77,9 @@ GRFFTChannelComponent::GRFFTChannelComponent(GRIIOFloatChannelNode *node, FFTPlo connect(this, &GRFFTChannelComponent::windowChanged, this, [=](int w) { dynamic_cast(m_grtch)->setWindow(w); }); + + connect(this, &GRFFTChannelComponent::windowCorrectionChanged, this, + [=](bool b) { dynamic_cast(m_grtch)->setWindowCorrection(b); }); _init(); } @@ -83,7 +89,7 @@ void GRFFTChannelComponent::_init() m_scaleAvailable = m_src->scaleAttributeAvailable(); // query from GRIIOFloatChannel; m_powerOffset = 0; m_window = 1; - + m_windowCorrection = true; /* m_measureMgr = new TimeMeasureManager(this); m_measureMgr->initMeasure(m_pen); @@ -97,12 +103,18 @@ void GRFFTChannelComponent::_init() m_lay->addWidget(widget); setLayout(m_lay); + m_fftPlotComponentChannel->markerController()->setComplex(m_complex); createMenuControlButton(this); } GRFFTChannelComponent::~GRFFTChannelComponent() {} MeasureManagerInterface *GRFFTChannelComponent::getMeasureManager() { return nullptr; } +MarkerController *GRFFTChannelComponent::markerController() +{ + return m_fftPlotComponentChannel->markerController(); +} + QWidget *GRFFTChannelComponent::createYAxisMenu(QWidget *parent) { m_yaxisMenu = new MenuSectionCollapseWidget("Y-AXIS", MenuCollapseSection::MHCW_ONOFF, parent); @@ -154,21 +166,25 @@ QWidget *GRFFTChannelComponent::createMenu(QWidget *parent) ChannelComponent::initMenu(parent); QWidget *yaxismenu = createYAxisMenu(m_menu); QWidget *curvemenu = createCurveMenu(m_menu); + QWidget *markerMenu = createMarkerMenu(m_menu); m_menu->add(yaxismenu, "yaxis"); + m_menu->add(markerMenu, "marker"); m_menu->add(curvemenu, "curve"); if(dynamic_cast(m_src) != nullptr) { auto src = dynamic_cast(m_src); - QWidget *attrmenui = createChAttrMenu(m_src_I->channel(), m_menu); + QWidget *attrmenui = createChAttrMenu(m_src_I->channel(), "ATTRIBUTES - I CHANNEL", m_menu); m_menu->add(attrmenui, "attr"); - QWidget *attrmenuq = createChAttrMenu(m_src_Q->channel(), m_menu); + QWidget *attrmenuq = createChAttrMenu(m_src_Q->channel(), "ATTRIBUTES - Q CHANNEL", m_menu); m_menu->add(attrmenuq, "attr"); } else { auto src = dynamic_cast(m_src); - QWidget *attrmenui = createChAttrMenu(src->channel(), m_menu); + QWidget *attrmenui = createChAttrMenu(src->channel(), "ATTRIBUTES", m_menu); m_menu->add(attrmenui, "attr"); } // QWidget *measuremenu = m_measureMgr->createMeasurementMenu(m_menu); + + m_snapBtn = createSnapshotButton(m_menu); // m_menu->add(measuremenu, "measure"); @@ -177,10 +193,69 @@ QWidget *GRFFTChannelComponent::createMenu(QWidget *parent) return m_menu; } -QWidget *GRFFTChannelComponent::createChAttrMenu(iio_channel *ch, QWidget *parent) +QWidget *GRFFTChannelComponent::createMarkerMenu(QWidget *parent) { + MenuSectionCollapseWidget *section = + new MenuSectionCollapseWidget("MARKER", MenuCollapseSection::MHCW_ONOFF, parent); + + auto layout = new QVBoxLayout(); + layout->setSpacing(10); + layout->setMargin(0); + + MenuCombo *markerCb = new MenuCombo("Marker Type", section); + markerCb->combo()->addItem("Peak", MarkerController::MC_PEAK); + markerCb->combo()->addItem("Fixed", MarkerController::MC_FIXED); + markerCb->combo()->addItem("Single Tone", MarkerController::MC_SINGLETONE); + if(m_complex) { + markerCb->combo()->addItem("Image", MarkerController::MC_IMAGE); + } + + markerCb->combo()->setCurrentIndex(0); + + MenuOnOffSwitch *fixedMarkerEditBtn = new MenuOnOffSwitch("Marker editable", section); + connect(fixedMarkerEditBtn->onOffswitch(), &QAbstractButton::toggled, this, [=](bool b) { + m_fftPlotComponentChannel->markerController()->setFixedHandleVisible(b); + }); + fixedMarkerEditBtn->onOffswitch()->setChecked(true); + fixedMarkerEditBtn->setVisible(false); + + MenuSpinbox *markerCnt = new MenuSpinbox("Marker count", 5, "markers",0,9,true,false,section); + markerCnt->setIncrementMode(MenuSpinbox::IS_FIXED); + markerCnt->setScaleRange(1,10); + markerCnt->setValue(5); + + connect(markerCnt, &MenuSpinbox::valueChanged,this,[=](double cnt){ + m_fftPlotComponentChannel->markerController()->setNrOfMarkers(cnt); + }); + + connect(section->collapseSection()->header(), &QAbstractButton::toggled, this, [=](bool b) { + if(b) { + auto markerType = static_cast(markerCb->combo()->currentData().toInt()); + m_fftPlotComponentChannel->markerController()->setMarkerType(markerType); + } else { + m_fftPlotComponentChannel->markerController()->setMarkerType(MarkerController::MC_NONE); + } + }); + + connect(markerCb->combo(), qOverload(&QComboBox::currentIndexChanged), this, [=](int idx) { + auto markerType = static_cast(markerCb->combo()->currentData().toInt()); + m_fftPlotComponentChannel->markerController()->setMarkerType(markerType); + fixedMarkerEditBtn->setVisible(markerCb->combo()->currentData().toInt() == MarkerController::MC_FIXED); + }); + + layout->addWidget(markerCb); + layout->addWidget(markerCnt); + layout->addWidget(fixedMarkerEditBtn); + + section->contentLayout()->addLayout(layout); + section->setCollapsed(true); + return section; + +} + +QWidget *GRFFTChannelComponent::createChAttrMenu(iio_channel *ch, QString title, QWidget *parent) { MenuSectionCollapseWidget *section = - new MenuSectionCollapseWidget("ATTRIBUTES", MenuCollapseSection::MHCW_NONE, parent); + new MenuSectionCollapseWidget(title, MenuCollapseSection::MHCW_NONE, parent); QList attrWidgets = IIOWidgetBuilder().channel(ch).buildAll(); auto layout = new QVBoxLayout(); @@ -283,6 +358,7 @@ void GRFFTChannelComponent::onNewData(const float *xData, const float *yData, si model->setDataSource(yData, size); model->measure();*/ m_snapBtn->setEnabled(true); + } bool GRFFTChannelComponent::sampleRateAvailable() { return m_src->samplerateAttributeAvailable(); } @@ -311,3 +387,16 @@ void GRFFTChannelComponent::setWindow(int newWindow) m_window = newWindow; Q_EMIT windowChanged(newWindow); } + +bool GRFFTChannelComponent::windowCorrection() const +{ + return m_windowCorrection; +} + +void GRFFTChannelComponent::setWindowCorrection(bool newWindowCorr) +{ + if (m_windowCorrection == newWindowCorr) + return; + m_windowCorrection = newWindowCorr; + Q_EMIT windowCorrectionChanged(newWindowCorr); +} diff --git a/plugins/adc/src/freq/grfftchannelcomponent.h b/plugins/adc/src/freq/grfftchannelcomponent.h index 8e0fd3b669..f50e6c0af3 100644 --- a/plugins/adc/src/freq/grfftchannelcomponent.h +++ b/plugins/adc/src/freq/grfftchannelcomponent.h @@ -2,7 +2,6 @@ #define GRFFTCHANNELCOMPONENT_H #include "grfftsinkcomponent.h" -#include "iioutil/iiounits.h" #include "scopy-adc_export.h" #include "channelcomponent.h" #include @@ -19,6 +18,7 @@ #include #include #include +#include "markercontroller.h" namespace scopy { namespace adc { @@ -64,10 +64,14 @@ class GRFFTComplexChannelSigpath : public QObject, public GRChannel, public FFTC double powerOffset() { return m_powerOffset; } - void setWindow(int w) override{ + void setWindow(int w) override { m_fft->setWindow(static_cast(w)); } + void setWindowCorrection(bool b) override { + m_fft->setWindowCorrection(b); + } + GRTopBlock *m_top; ChannelComponent *m_ch; GRSignalPath *m_signalPath; @@ -118,6 +122,10 @@ class GRFFTChannelSigpath : public QObject, public GRChannel, public FFTChannel m_fft->setWindow(static_cast(w)); } + void setWindowCorrection(bool b) override { + m_fft->setWindowCorrection(b); + } + GRTopBlock *m_top; ChannelComponent *m_ch; GRSignalPath *m_signalPath; @@ -141,6 +149,7 @@ class SCOPY_ADC_EXPORT GRFFTChannelComponent : public ChannelComponent, ~GRFFTChannelComponent(); MeasureManagerInterface *getMeasureManager() override; + MarkerController* markerController(); GRSignalPath *sigpath() override; QVBoxLayout *menuLayout(); @@ -150,7 +159,8 @@ class SCOPY_ADC_EXPORT GRFFTChannelComponent : public ChannelComponent, void setWindow(int) override; void setSamplingInfo(SamplingInfo p) override; int window() const; - + bool windowCorrection() const; + void setWindowCorrection(bool newWindowCorr) override; virtual bool enabled() const override; public Q_SLOTS: @@ -175,10 +185,12 @@ public Q_SLOTS: void fftSizeChanged(); void powerOffsetChanged(double); void windowChanged(int); + void windowCorrectionChanged(bool); private: double m_powerOffset; int m_window; + bool m_windowCorrection; GRIIOFloatChannelNode *m_node; GRIIOChannel *m_src; @@ -205,7 +217,8 @@ public Q_SLOTS: bool m_complex; QWidget *createMenu(QWidget *parent = nullptr); - QWidget *createChAttrMenu(iio_channel *ch, QWidget *parent); + QWidget *createChAttrMenu(iio_channel *ch, QString title, QWidget *parent); + QWidget *createMarkerMenu(QWidget *parent); QWidget *createYAxisMenu(QWidget *parent); QWidget *createCurveMenu(QWidget *parent); QPushButton *createSnapshotButton(QWidget *parent); @@ -215,6 +228,7 @@ public Q_SLOTS: Q_PROPERTY(double powerOffset READ powerOffset WRITE setPowerOffset NOTIFY powerOffsetChanged) Q_PROPERTY(int window READ window WRITE setWindow NOTIFY windowChanged) + Q_PROPERTY(bool windowCorrection READ windowCorrection WRITE setWindowCorrection NOTIFY windowCorrectionChanged) }; } // namespace adc diff --git a/plugins/adc/src/grdevicecomponent.cpp b/plugins/adc/src/grdevicecomponent.cpp index 7f82a31e67..2448e8ce35 100644 --- a/plugins/adc/src/grdevicecomponent.cpp +++ b/plugins/adc/src/grdevicecomponent.cpp @@ -58,14 +58,17 @@ QWidget *GRDeviceComponent::createChCommonAttrMenu(QWidget *parent) { } if(createAttr) { qInfo()<<"common "<(ctx)) - .device(const_cast(dev)) - .channel(const_cast(ch)) - createMultiDataStrategy + IIOWidget *w = IIOWidgetBuilder().context(const_cast(ctx)) + .device(const_cast(dev)) + .channel(const_cast(ch)) + .attribute(attrName).buildSingle(); + +// iiowidgetbuilder.convertToMulti(w) + /*createMultiDataStrategy Add rest of data strategies - attrWidgets.append(w); */ + attrWidgets.append(w); } } diff --git a/plugins/adc/src/interfaces.h b/plugins/adc/src/interfaces.h index 030239817d..33b8c70d5f 100644 --- a/plugins/adc/src/interfaces.h +++ b/plugins/adc/src/interfaces.h @@ -1,5 +1,6 @@ #ifndef INTERFACES_H #define INTERFACES_H +#include "markercontroller.h" #include "plotwidget.h" #include "scopy-adc_export.h" #include @@ -44,6 +45,7 @@ class SCOPY_ADC_EXPORT FFTChannel public: virtual void setPowerOffset(double) = 0; virtual void setWindow(int) = 0; + virtual void setWindowCorrection(bool) = 0; }; class SCOPY_ADC_EXPORT SampleRateProvider @@ -83,8 +85,10 @@ class SCOPY_ADC_EXPORT MeasurementPanelInterface public: virtual MeasurementsPanel *measurePanel() const = 0; virtual StatsPanel *statsPanel() const = 0; + virtual MarkerPanel *markerPanel() const = 0; virtual void enableMeasurementPanel(bool) = 0; virtual void enableStatsPanel(bool) = 0; + virtual void enableMarkerPanel(bool) = 0; }; } // namespace scopy::adc diff --git a/plugins/adc/src/markercontroller.cpp b/plugins/adc/src/markercontroller.cpp new file mode 100644 index 0000000000..c9d4902b11 --- /dev/null +++ b/plugins/adc/src/markercontroller.cpp @@ -0,0 +1,438 @@ +#include "markercontroller.h" +#include +#include + +using namespace scopy::adc; + +MarkerController::MarkerController(FFTPlotComponentChannel *ch, QObject *parent) + : QObject(parent), + m_ch(ch), + m_plot(nullptr), + m_xAxis(QwtAxis::XBottom), + m_yAxis(QwtAxis::YLeft) +{ + m_enabled = false; + m_complex = false; + m_handlesVisible = true; + +} + +void MarkerController::init() { + m_plot = m_ch->m_plotComponent->fftPlot()->plot(); + m_xAxis = m_ch->m_plotComponent->fftPlot()->xAxis()->axisId(); + m_yAxis = m_ch->m_plotComponent->fftPlot()->yAxis()->axisId(); + setNrOfMarkers(5); + setMarkerType(MC_NONE); +} + +MarkerController::~MarkerController() +{ + +} + +void MarkerController::setNrOfMarkers(int n) +{ + for(int i = 0; i < m_markers.count();i++){ + m_markers[i]->detach(); + delete m_markers[i]; + } + m_markers.clear(); + + m_nrOfMarkers = n; + if(m_markerType == MC_NONE) { + return; + } + + int nrOfMarkers = m_nrOfMarkers; + if(m_markerType == MC_IMAGE) { + nrOfMarkers = 3; + } + + for(int i = 0; i < nrOfMarkers; i++) { + QwtPlotMarker *marker = new QwtPlotMarker(); + m_markers.append(marker); + marker->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, QColor(237, 28, 36), + QPen(QColor(255, 255, 255, 140), 2, Qt::SolidLine), QSize(5, 5))); + m_markers[i]->setXAxis(m_xAxis); + m_markers[i]->setYAxis(m_yAxis); + m_markers[i]->attach(m_plot); + m_markers[i]->setVisible(m_enabled); + } +} + +void MarkerController::setMarkerType(MarkerTypes v) +{ + if(m_markerType == MC_FIXED) { + deinitFixedMarker(); + } + + m_markerType = v; + setNrOfMarkers(m_nrOfMarkers); + + if(v == MC_FIXED) { + initFixedMarker(); + } + + Q_EMIT markerEnabled(m_enabled && m_markerType != MC_NONE); + computeMarkers(); +} + +void MarkerController::setFixedMarkerFrequency(int idx, double freq) { + + if(idx > m_markerInfo.count() - 1) + return; + m_markerInfo[idx].peak.x = freq; +} + +void MarkerController::initFixedMarker() { + cacheMarkerInfo(); + for(int i = 0; i < m_nrOfMarkers; i++) { + double initX = popCacheMarkerInfo(); + MarkerInfo mi = {.name = QString("F")+ QString::number(i), + .marker = m_markers[i], + .peak = {initX, 0}}; + m_markerInfo.append(mi); + PlotAxisHandle *handle = new PlotAxisHandle(m_ch->plotComponent()->plot(0), m_ch->m_plotComponent->plot(0)->xAxis()); + connect(handle, &PlotAxisHandle::scalePosChanged,this,[=](double v) { + m_markerInfo[i].peak.x = v; computeMarkers(); }); + m_fixedHandles.append(handle); + + handle->setPositionSilent(initX); + } + + setFixedHandleVisible(m_handlesVisible); +} + +void MarkerController::setFixedHandleVisible(bool b) { + m_handlesVisible = b; + if(m_markerType == MC_FIXED) { + for(auto handle : m_fixedHandles) { + handle->handle()->setVisible(b); + handle->handle()->raise(); + } + } +} + +void MarkerController::deinitFixedMarker() +{ + for(auto handle : m_fixedHandles) { + delete handle; + } + m_fixedHandles.clear(); +} + +void MarkerController::computeFixedMarkerFrequency() { + for(int i = 0; i < m_nrOfMarkers; i++) { + m_markerInfo[i].peak.y = m_ch->plotChannel()->getValueAt(m_markerInfo[i].peak.x); + } +} + +const QList &MarkerController::markerInfo() const +{ + return m_markerInfo; +} + +void MarkerController::computeMarkers() +{ + + if(m_enabled == false) + return; + if(m_markerType == MC_NONE) + return; + + if(m_markerType == MC_PEAK) { + computePeaks(); + computePeakMarkers(); + } + + if(m_markerType == MC_SINGLETONE) { + computePeaks(); + computeSingleToneMarkers(); + } + + if(m_markerType == MC_FIXED) { + computeFixedMarkerFrequency(); + } + + if(m_markerType == MC_IMAGE) { + computePeaks(); + computeImageMarkers(); + } + + attachMarkersToPlot(); + Q_EMIT markerInfoUpdated(); + m_plot->replot(); +} + +void MarkerController::setAxes(QwtAxisId x, QwtAxisId y) +{ + m_xAxis = x; + m_yAxis = y; + + for(int i = 0;i < m_markers.count();i++){ + m_markers[i]->setXAxis(m_xAxis); + m_markers[i]->setYAxis(m_yAxis); + } + + if(m_markerType == MC_FIXED) { + deinitFixedMarker(); + initFixedMarker(); + } + +} + +void MarkerController::setPlot(QwtPlot *p) +{ + m_plot = p; + for(int i = 0;i < m_markers.count();i++){ + m_markers[i]->attach(m_plot);; + } + if(m_markerType == MC_FIXED) { + deinitFixedMarker(); + initFixedMarker(); + } + setEnabled(m_enabled); + if(m_enabled && m_markerType != MC_NONE) { + Q_EMIT markerInfoUpdated(); + } +} + +void MarkerController::setComplex(bool b) +{ + m_complex = b; +} + +void MarkerController::computePeaks() { + + auto data = m_ch->m_ch->chData(); + m_peakInfo.clear(); + + int m_start = 0; + int m_stop = (m_complex) ? data->size() : data->size() / 2; + + for(int i = m_start + 2; i < m_stop - 1;i++) { + if(data->yData()[i-2] < data->yData()[i-1] && + data->yData()[i-1] > data->yData()[i]) { // is there a better way to compute a peak ? + PeakInfo mi = { + .x = data->xData()[i-1], + .y = data->yData()[i-1], + .idx = i-1 + }; + m_peakInfo.append(mi); + } + } + + m_sortedPeakInfo.clear(); + for(auto v : m_peakInfo) { + m_sortedPeakInfo.append(v); + } + + std::sort(m_sortedPeakInfo.begin(), m_sortedPeakInfo.end(),[](const PeakInfo a, const PeakInfo b){ + return a.y > b.y; + }); +} + +void MarkerController::computePeakMarkers() +{ + m_markerInfo.clear(); + for(int i = 0;i < m_markers.count() && i < m_sortedPeakInfo.count();i++) { + MarkerInfo mi = {.name = QString("P") + QString::number(i), .marker = m_markers[i],.peak = m_sortedPeakInfo[i] }; + m_markerInfo.append(mi); + } + +} + +void MarkerController::computeSingleToneMarkers() +{ + auto data = m_ch->m_ch->chData(); + m_markerInfo.clear(); + int dc_idx = (m_complex) ? data->size()/2 : 0; + + if(m_sortedPeakInfo.count() == 0) + return; + + MarkerInfo dc = {.name = QString("DC"), .marker = m_markers[0],.peak = {data->xData()[dc_idx],data->yData()[dc_idx]}}; + MarkerInfo fund = {.name = QString("Fund"), .marker = m_markers[1],.peak = m_sortedPeakInfo[0]}; + int fund_offset = m_sortedPeakInfo[0].idx - dc_idx; + m_markerInfo.append(dc); + m_markerInfo.append(fund); + // Compute harmonics - need double PlotCursors::getHorizIntersectionAt(double pos) + + int histeresis = log2(data->size()); // easy hack - if data size is higher, so is the histeresis + + for(int i = 2; i < m_nrOfMarkers - 1; i++){ + int idx = findPeakNearIdx((fund_offset * i + dc_idx), histeresis); + MarkerInfo mi = {.name = QString::number(i) + "H", .marker = m_markers[i],.peak = {data->xData()[idx],data->yData()[idx]}}; + m_markerInfo.append(mi); + + } +} + +void MarkerController::computeImageMarkers() { + auto data = m_ch->m_ch->chData(); + m_markerInfo.clear(); + int dc_idx = (m_complex) ? data->size()/2 : 0; + + if(m_sortedPeakInfo.count() == 0) + return; + + MarkerInfo dc = {.name = QString("DC"), .marker = m_markers[0],.peak = {data->xData()[dc_idx],data->yData()[dc_idx]}}; + MarkerInfo fund = {.name = QString("Fund"), .marker = m_markers[1],.peak = m_sortedPeakInfo[0]}; + int fund_offset = m_sortedPeakInfo[0].idx - dc_idx; + int idx = dc_idx - fund_offset; + MarkerInfo imag = {.name = QString("Imag"), .marker = m_markers[2],.peak = {data->xData()[idx],data->yData()[idx]}}; + + m_markerInfo.append(dc); + m_markerInfo.append(fund); + m_markerInfo.append(imag); + + +} + +int MarkerController::findPeakNearIdx(int idx, int range) { + auto data = m_ch->m_ch->chData(); + int start = (idx - range) > 0 ? idx - range : 0; + int maxIdx = start; + double maxVal = data->yData()[start]; + for(int i = start; i <= idx+range && i < data->size();i++){ + if(maxVal < data->yData()[i]) { + maxVal = data->yData()[i]; + maxIdx = i; + } + } + return maxIdx; + +} + +void MarkerController::cacheMarkerInfo() +{ + m_markerCache.clear(); + for(auto mi : m_markerInfo) { + m_markerCache.push_back(mi.peak.x); + } + m_markerInfo.clear(); +} + +double MarkerController::popCacheMarkerInfo() +{ + double ret; + if(m_markerCache.empty()) { + ret = 0; + } else { + ret = m_markerCache.front(); + m_markerCache.pop_front(); + } + return ret; +} + +void MarkerController::attachMarkersToPlot(){ + for(auto m : m_markerInfo) { + m.marker->setValue(m.peak.x, m.peak.y); + + QwtText lbl; + lbl.setText(m.name); + lbl.setColor(m_ch->m_fftPlotCh->curve()->pen().color()); + m.marker->setLabel(lbl); + m.marker->setLabelAlignment(Qt::AlignTop); + m.marker->setSpacing(10); + } +} + +bool MarkerController::enabled() const +{ + return m_enabled; +} + +void MarkerController::setEnabled(bool newEnabled) +{ + m_enabled = newEnabled; + for(int i = 0;i < m_markers.count();i++){ + if(m_enabled) { + m_markers[i]->setVisible(true); + } else { + m_markers[i]->setVisible(false); + } + } + Q_EMIT markerEnabled(newEnabled && m_markerType != MC_NONE); +} + +MarkerPanel::MarkerPanel(QWidget *parent) +{ + m_panelLayout = new QHBoxLayout(this); + m_panelLayout->setAlignment(Qt::AlignLeft); + m_panelLayout->setSpacing(0); + m_panelLayout->setMargin(0); + setLayout(m_panelLayout); +} + +MarkerPanel::~MarkerPanel() +{ + +} + +void MarkerPanel::newChannel(QString name, QPen c) +{ + if(m_map.contains(name)) { + deleteChannel(name); + } + QWidget *w = new MarkerLabel(name, c, this); + m_panelLayout->addWidget(w); + m_map[name] = w; +} + +void MarkerPanel::deleteChannel(QString name) +{ + if(!m_map.contains(name)) + return; + QWidget *w = m_map[name]; + m_panelLayout->removeWidget(w); + delete w; + m_map.remove(name); + +} + +void MarkerPanel::updateChannel(QString name, QList mi) +{ + dynamic_cast(m_map[name])->updateInfo(mi); + setFixedHeight(20 + mi.count() * 20); + +} + +int MarkerPanel::markerCount() +{ + return m_map.count(); +} + +MarkerLabel::MarkerLabel(QString name, QPen c, QWidget *parent) +{ + m_lay = new QVBoxLayout(this); + setLayout(m_lay); + m_lay->setMargin(0); + m_name = name; + m_txt = new QTextEdit(); + m_txt->setTextColor(c.color()); + m_txt->setText(name); + m_lay->addWidget(m_txt); + m_mpf = new MetricPrefixFormatter(this); + m_mpf->setTwoDecimalMode(false); + setFixedWidth(200); + +} + +MarkerLabel::~MarkerLabel() +{ + +} + +QString MarkerLabel::name() +{ + return m_name; +} + +void MarkerLabel::updateInfo(QList markers) +{ + m_txt->setText(m_name); + for(auto m : markers) { + m_txt->append(m.name + ": " + m_mpf->format(m.peak.y,"db",2) + " @ " + m_mpf->format(m.peak.x,"Hz",3)); + } +} diff --git a/plugins/adc/src/markercontroller.h b/plugins/adc/src/markercontroller.h new file mode 100644 index 0000000000..a3d5e3c0df --- /dev/null +++ b/plugins/adc/src/markercontroller.h @@ -0,0 +1,141 @@ +#ifndef MARKERCONTROLLER_H +#define MARKERCONTROLLER_H + +#include "plot_utils.hpp" +#include "plotaxishandle.h" +#include "qboxlayout.h" +#include "qtextedit.h" +#include "qwidget.h" +#include "utils.h" +#include +#include +#include +#include + +namespace scopy { +namespace adc { + +class FFTPlotComponentChannel; +class SCOPY_ADC_EXPORT MarkerController : public QObject +{ + Q_OBJECT +public: + typedef enum { + MC_NONE, + MC_PEAK, + MC_FIXED, + MC_SINGLETONE, + MC_IMAGE + } MarkerTypes; + + typedef struct { + double x; + double y; + int idx; + } PeakInfo; + + typedef struct { + QString name; + QwtPlotMarker *marker; + PeakInfo peak; + } MarkerInfo; + + MarkerController(FFTPlotComponentChannel *ch, QObject *parent); + ~MarkerController(); + + + void init(); + bool enabled() const; + void setEnabled(bool newEnabled); + void attachMarkersToPlot(); + const QList &markerInfo() const; + +public Q_SLOTS: + void setNrOfMarkers(int); + void setMarkerType(MarkerTypes); + void computeMarkers(); + void setAxes(QwtAxisId x, QwtAxisId y); + void setPlot(QwtPlot *); + void setComplex(bool b); + void setFixedHandleVisible(bool b); + void setFixedMarkerFrequency(int idx, double freq); + +Q_SIGNALS: + void markerInfoUpdated(); + void markerEnabled(bool b); + +private: + void initFixedMarker(); + void deinitFixedMarker(); + void computePeaks(); + void computePeakMarkers(); + void computeSingleToneMarkers(); + void computeFixedMarkerFrequency(); + void computeImageMarkers(); + int findPeakNearIdx(int idx, int range); + + void cacheMarkerInfo(); + double popCacheMarkerInfo(); + + bool m_enabled; + int m_nrOfMarkers; + + bool m_complex; + bool m_handlesVisible; + + QList m_markers; + QList m_peakInfo; + QList m_sortedPeakInfo; + QList m_markerInfo; + QList m_fixedHandles; + QList m_markerCache; + + MarkerTypes m_markerType; + + FFTPlotComponentChannel *m_ch; + + QwtPlot *m_plot; + QwtAxisId m_xAxis; + QwtAxisId m_yAxis; + + +}; + +class SCOPY_ADC_EXPORT MarkerPanel : public QWidget +{ + Q_OBJECT; + QWIDGET_PAINT_EVENT_HELPER; +public: + MarkerPanel(QWidget *parent = nullptr); + ~MarkerPanel(); +public Q_SLOTS: + void newChannel(QString name, QPen c); + void deleteChannel(QString name); + void updateChannel(QString, QList); + int markerCount(); +private: + QHBoxLayout *m_panelLayout; + QMap m_map; +}; + +class SCOPY_ADC_EXPORT MarkerLabel : public QWidget +{ + Q_OBJECT; + QWIDGET_PAINT_EVENT_HELPER; +public: + MarkerLabel(QString name, QPen c, QWidget *parent = nullptr); + ~MarkerLabel(); + QString name(); + void updateInfo(QList m); + +private: + QVBoxLayout *m_lay; + QString m_name; + QTextEdit *m_txt; + MetricPrefixFormatter *m_mpf; + +}; +} +} + +#endif // MARKERCONTROLLER_H diff --git a/plugins/adc/src/measurecomponent.cpp b/plugins/adc/src/measurecomponent.cpp index ce918a79b1..b999d41b79 100644 --- a/plugins/adc/src/measurecomponent.cpp +++ b/plugins/adc/src/measurecomponent.cpp @@ -33,6 +33,7 @@ MeasureComponent::MeasureComponent(ToolTemplate *tool, MeasurementPanelInterface // tool->openBottomContainerHelper(b); m_measurementPanelInterface->enableMeasurementPanel(m_measureSettings->measurementEnabled() && b); m_measurementPanelInterface->enableStatsPanel(m_measureSettings->statsEnabled() && b); + m_measurementPanelInterface->enableMarkerPanel(m_measureSettings->markerEnabled() && b); }); tool->addWidgetToBottomContainerHelper(measure, TTA_RIGHT); @@ -43,6 +44,8 @@ MeasureComponent::MeasureComponent(ToolTemplate *tool, MeasurementPanelInterface SLOT(enableMeasurementPanel(bool))); connect(m_measureSettings, SIGNAL(enableStatsPanel(bool)), dynamic_cast(p), SLOT(enableStatsPanel(bool))); + connect(m_measureSettings, SIGNAL(enableMarkerPanel(bool)), dynamic_cast(p), + SLOT(enableMarkerPanel(bool))); connect(m_measureSettings, &MeasurementSettings::sortMeasurements, m_measurePanel, &MeasurementsPanel::sort); connect(m_measureSettings, &MeasurementSettings::sortStats, m_statsPanel, &StatsPanel::sort); } diff --git a/plugins/adc/src/plotmanager.cpp b/plugins/adc/src/plotmanager.cpp index 931244cfb3..02a41963b9 100644 --- a/plugins/adc/src/plotmanager.cpp +++ b/plugins/adc/src/plotmanager.cpp @@ -16,15 +16,18 @@ PlotManager::PlotManager(QString name, QWidget *parent) m_measurePanel = new MeasurementsPanel(this); m_measurePanel->setFixedHeight(110); - // tool->topStack()->add(measureMenuId, m_measurePanel); + m_measurePanel->setVisible(false); m_statsPanel = new StatsPanel(this); m_statsPanel->setFixedHeight(100); - // tool->bottomStack()->add(statsMenuId, m_statsPanel); - m_lay->addWidget(m_measurePanel); - m_measurePanel->setVisible(false); m_statsPanel->setVisible(false); + + m_markerPanel = new MarkerPanel(this); + m_markerPanel->setVisible(false); + + m_lay->addWidget(m_measurePanel); m_lay->addWidget(m_statsPanel); + m_lay->addWidget(m_markerPanel); } PlotManager::~PlotManager() {} @@ -33,6 +36,11 @@ void PlotManager::enableMeasurementPanel(bool b) { m_measurePanel->setVisible(b) void PlotManager::enableStatsPanel(bool b) { m_statsPanel->setVisible(b); } +void PlotManager::enableMarkerPanel(bool b) +{ + m_markerPanel->setVisible(b); +} + void PlotManager::setXInterval(double xMin, double xMax) { m_xInterval.first = xMin; @@ -63,6 +71,11 @@ MeasurementsPanel *PlotManager::measurePanel() const { return m_measurePanel; } StatsPanel *PlotManager::statsPanel() const { return m_statsPanel; } +MarkerPanel *PlotManager::markerPanel() const +{ + return m_markerPanel; +} + QWidget *PlotManager::plotCombo(ChannelComponent *c) { return m_channelPlotcomboMap[c]; } void PlotManager::updateAxisScales() diff --git a/plugins/adc/src/plotmanager.h b/plugins/adc/src/plotmanager.h index 2f80d27365..af5c14c144 100644 --- a/plugins/adc/src/plotmanager.h +++ b/plugins/adc/src/plotmanager.h @@ -1,5 +1,6 @@ #ifndef PLOTMANAGER_H #define PLOTMANAGER_H +#include "markercontroller.h" #include "scopy-adc_export.h" #include #include "toolcomponent.h" @@ -30,6 +31,7 @@ class SCOPY_ADC_EXPORT PlotManager : public QWidget, public MeasurementPanelInte QList plots() const; MeasurementsPanel *measurePanel() const override; StatsPanel *statsPanel() const override; + MarkerPanel *markerPanel() const override; QWidget *createMenu(QWidget *parent); QWidget *plotCombo(ChannelComponent *c); @@ -39,6 +41,7 @@ public Q_SLOTS: void replot(); void enableMeasurementPanel(bool) override; void enableStatsPanel(bool) override; + void enableMarkerPanel(bool) override; void setXInterval(double xMin, double xMax); void setXUnit(QString); @@ -54,6 +57,8 @@ public Q_SLOTS: QList m_plots; QList m_channels; MeasurementsPanel *m_measurePanel; + MarkerPanel *m_markerPanel; + StatsPanel *m_statsPanel; QMap m_channelPlotcomboMap; // PlotSettings *m_plotSettings; diff --git a/plugins/adc/src/time/timeplotcomponentsettings.cpp b/plugins/adc/src/time/timeplotcomponentsettings.cpp index 590e7abd93..3079a2b74e 100644 --- a/plugins/adc/src/time/timeplotcomponentsettings.cpp +++ b/plugins/adc/src/time/timeplotcomponentsettings.cpp @@ -112,6 +112,7 @@ TimePlotComponentSettings::TimePlotComponentSettings(TimePlotComponent *plt, QWi StyleHelper::BlueButton(m_deletePlot); connect(m_deletePlot, &QAbstractButton::clicked, this, [=]() { Q_EMIT requestDeletePlot(); }); + yaxis->contentLayout()->setSpacing(2); yaxis->contentLayout()->addWidget(m_autoscaleBtn); yaxis->contentLayout()->addWidget(m_yCtrl); yaxis->contentLayout()->addWidget(m_yModeCb);