diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp index f1da2dce36..5aecc3906b 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp @@ -317,6 +317,34 @@ void CIRPlot::timerEvent(QTimerEvent *event) this->series->replace(points); } +void CIRPlotUE::timerEvent(QTimerEvent *event) +{ + if (!this->isVisible()) + return; + + scopeGraphData_t *data = this->valueProvider->getPlotValue(); + if (data) { + this->data = (complex16 *)(data + 1); + this->len = data->lineSz; + QVector points(this->len); + float maxY = this->axisY->max(); + + for (int i = 0; i < this->len / 2; i++) { + float value = SquaredNorm(this->data[i + this->len / 2]); + points[i] = QPointF(i - this->len / 2, value); + maxY = std::max(maxY, value); + } + for (int i = 0; i < this->len / 2; i++) { + float value = SquaredNorm(this->data[i]); + points[i + this->len / 2] = QPointF(i, value); + maxY = std::max(maxY, value); + } + + this->axisY->setMax(maxY); + this->series->replace(points); + } +} + LLRPlot::LLRPlot(int16_t *data, int len) : data(data), len(len) { this->legend()->hide(); @@ -361,6 +389,28 @@ void LLRPlot::timerEvent(QTimerEvent *event) this->series->replace(points); } +void LLRPlotUE::timerEvent(QTimerEvent *event) +{ + if (!this->isVisible()) + return; + + scopeGraphData_t *data = this->valueProvider->getPlotValue(); + if (data) { + this->data = (int16_t *)(data + 1); + this->len = data->lineSz; + QVector points(this->len); + int maxY = this->axisY->max(); + + for (int i = 0; i < this->len; i++) { + points[i] = QPointF(i, this->data[i]); + maxY = std::max(maxY, abs(this->data[i])); + } + + this->axisY->setRange(-maxY, maxY); + this->series->replace(points); + } +} + IQPlot::IQPlot(complex16 *data, int len) : data(data), len(len) { this->legend()->hide(); @@ -407,6 +457,32 @@ void IQPlot::timerEvent(QTimerEvent *event) this->series->replace(points); } +void IQPlotUE::timerEvent(QTimerEvent *event) +{ + if (!this->isVisible()) + return; + + scopeGraphData_t *data = this->valueProvider->getPlotValue(); + if (data) { + this->data = (complex16 *)(data + 1); + this->len = data->lineSz; + QVector points(this->len); + int maxX = this->axisX->max(); + int maxY = this->axisY->max(); + + for (int i = 0; i < this->len; i++) { + points[i] = QPointF(this->data[i].r, this->data[i].i); + + maxX = std::max(maxX, abs(this->data[i].r)); + maxY = std::max(maxY, abs(this->data[i].i)); + } + + this->axisX->setRange(-maxX, maxX); + this->axisY->setRange(-maxY, maxY); + this->series->replace(points); + } +} + KPIPlot::KPIPlot(ValueProvider *valueProvider, float *limits) : valueProvider(valueProvider), limits(limits) { this->series = new QLineSeries(); @@ -815,11 +891,42 @@ float PainterWidgetUE::getValue() case PlotTypeUE::timingAdvance: return (float)this->ue->timing_advance; + default: return 0; } } +scopeGraphData_t *PainterWidgetUE::getPlotValue() +{ + scopeData_t *scope = (scopeData_t *)this->ue->scopeData; + scopeGraphData_t **data = (scopeGraphData_t **)scope->liveData; + switch (this->plotType) { + case PlotTypeUE::CIR: + return data[pbchDlChEstimateTime]; + + case PlotTypeUE::pbchLLR: + return data[pbchLlr]; + case PlotTypeUE::pbchIQ: + return data[pbchRxdataF_comp]; + + case PlotTypeUE::pdcchLLR: + return data[pdcchLlr]; + + case PlotTypeUE::pdcchIQ: + return data[pdcchRxdataF_comp]; + + case PlotTypeUE::pdschLLR: + return data[pdschLlr]; + + case PlotTypeUE::pdschIQ: + return data[pdschRxdataF_comp]; + + default: + return nullptr; + } +} + /* @UE Class: this function is called when a resize event is detected, then the widget will be adjusted accordignly. */ void PainterWidgetUE::resizeEvent(QResizeEvent *event) { @@ -890,7 +997,7 @@ void PainterWidgetUE::makeConnections(int type) this->comboBox->setCurrentIndex(static_cast(PlotTypeUE::empty)); break; } - newChart = new LLRPlot((int16_t *)(data[pbchLlr] + 1), data[pbchLlr]->lineSz); + newChart = new LLRPlotUE((int16_t *)(data[pbchLlr] + 1), data[pbchLlr]->lineSz, this); break; } case PlotTypeUE::pbchIQ: { @@ -900,7 +1007,7 @@ void PainterWidgetUE::makeConnections(int type) this->comboBox->setCurrentIndex(static_cast(PlotTypeUE::empty)); break; } - newChart = new IQPlot((complex16 *)(data[pbchRxdataF_comp] + 1), data[pbchRxdataF_comp]->lineSz); + newChart = new IQPlotUE((complex16 *)(data[pbchRxdataF_comp] + 1), data[pbchRxdataF_comp]->lineSz, this); break; } case PlotTypeUE::pdcchLLR: { @@ -910,7 +1017,7 @@ void PainterWidgetUE::makeConnections(int type) this->comboBox->setCurrentIndex(static_cast(PlotTypeUE::empty)); break; } - newChart = new LLRPlot((int16_t *)(data[pdcchLlr] + 1), data[pdcchLlr]->lineSz); + newChart = new LLRPlotUE((int16_t *)(data[pdcchLlr] + 1), data[pdcchLlr]->lineSz, this); break; } case PlotTypeUE::pdcchIQ: { @@ -920,7 +1027,7 @@ void PainterWidgetUE::makeConnections(int type) this->comboBox->setCurrentIndex(static_cast(PlotTypeUE::empty)); break; } - newChart = new IQPlot((complex16 *)(data[pdcchRxdataF_comp] + 1), data[pdcchRxdataF_comp]->lineSz); + newChart = new IQPlotUE((complex16 *)(data[pdcchRxdataF_comp] + 1), data[pdcchRxdataF_comp]->lineSz, this); break; } case PlotTypeUE::pdschLLR: { @@ -930,7 +1037,7 @@ void PainterWidgetUE::makeConnections(int type) this->comboBox->setCurrentIndex(static_cast(PlotTypeUE::empty)); break; } - newChart = new LLRPlot((int16_t *)(data[pdschLlr] + 1), data[pdschLlr]->lineSz); + newChart = new LLRPlotUE((int16_t *)(data[pdschLlr] + 1), data[pdschLlr]->lineSz, this); break; } case PlotTypeUE::pdschIQ: { @@ -940,7 +1047,7 @@ void PainterWidgetUE::makeConnections(int type) this->comboBox->setCurrentIndex(static_cast(PlotTypeUE::empty)); break; } - newChart = new IQPlot((complex16 *)(data[pdschRxdataF_comp] + 1), data[pdschRxdataF_comp]->lineSz); + newChart = new IQPlotUE((complex16 *)(data[pdschRxdataF_comp] + 1), data[pdschRxdataF_comp]->lineSz, this); break; } diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.h b/openair1/PHY/TOOLS/nr_phy_qt_scope.h index f10fef9d61..8a00d5fa96 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.h +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.h @@ -91,6 +91,14 @@ class ValueProvider { virtual float getValue() = 0; }; +class ValueProviderUE : public ValueProvider { + public: + /// This pure virtual function is meant to provide the graph values to be plotted + virtual scopeGraphData_t *getPlotValue() { + return nullptr; + } +}; + /// An editable GUI field for a dialog box to set certain KPI configurations class ConfigBoxFloat : public QLineEdit { Q_OBJECT @@ -206,7 +214,6 @@ class CIRPlot : public QChart { /// \param event Pointer to the timer event virtual void timerEvent(QTimerEvent *event) override; - private: /// Pointer to the CIR data complex16 *data; @@ -223,6 +230,21 @@ class CIRPlot : public QChart { QValueAxis *axisY; }; +class CIRPlotUE : public CIRPlot { + Q_OBJECT + + public: + CIRPlotUE(complex16 *data, int len, ValueProviderUE *valueProvider) : CIRPlot(data, len), valueProvider(valueProvider) {} + + protected: + /// This function is triggered when the own timer expires. It updates the plotted CIR + /// \param event Pointer to the timer event + virtual void timerEvent(QTimerEvent *event) override; + + private: + ValueProviderUE *valueProvider; +}; + /// Chart class for plotting LLRs class LLRPlot : public QChart { Q_OBJECT @@ -238,7 +260,6 @@ class LLRPlot : public QChart { /// \param event Pointer to the timer event virtual void timerEvent(QTimerEvent *event) override; - private: /// Pointer to the LLR data int16_t *data; @@ -255,6 +276,21 @@ class LLRPlot : public QChart { QValueAxis *axisY; }; +class LLRPlotUE : public LLRPlot { + Q_OBJECT + + public: + LLRPlotUE(int16_t *data, int len, ValueProviderUE *valueProvider) : LLRPlot(data, len), valueProvider(valueProvider) {} + + protected: + /// This function is triggered when the own timer expires. It updates the plotted I/Q constellation diagram + /// \param event Pointer to the timer event + virtual void timerEvent(QTimerEvent *event) override; + + private: + ValueProviderUE *valueProvider; +}; + /// Chart class for plotting the I/Q constellation diagram class IQPlot : public QChart { Q_OBJECT @@ -270,7 +306,6 @@ class IQPlot : public QChart { /// \param event Pointer to the timer event virtual void timerEvent(QTimerEvent *event) override; - private: /// Pointer to the I/Q data complex16 *data; @@ -287,6 +322,22 @@ class IQPlot : public QChart { QValueAxis *axisY; }; +class IQPlotUE : public IQPlot { + Q_OBJECT + + public: + IQPlotUE(complex16 *data, int len, ValueProviderUE *valueProvider) : IQPlot(data, len), valueProvider(valueProvider) {} + + protected: + /// This function is triggered when the own timer expires. It updates the plotted I/Q constellation diagram + /// \param event Pointer to the timer event + virtual void timerEvent(QTimerEvent *event) override; + + private: + /// Pointer to an instance of a class that implements the ValueProvider interface + ValueProviderUE *valueProvider; +}; + /// Generic class for plotting KPI values with min., max. and average bars class KPIPlot : public QChart { Q_OBJECT @@ -422,7 +473,7 @@ class PainterWidgetGnb : public QWidget, public ValueProvider { }; /// Widget showing one selectable UE KPI -class PainterWidgetUE : public QWidget, public ValueProvider { +class PainterWidgetUE : public QWidget, public ValueProviderUE { Q_OBJECT public: @@ -435,6 +486,8 @@ class PainterWidgetUE : public QWidget, public ValueProvider { /// This function provides the current KPI value to be plotted virtual float getValue() override; + virtual scopeGraphData_t *getPlotValue() override; + protected: /// This function is called to change the widget size /// \param event Pointer to the resize event