From b8a5183b75497922573a19bdc6a2ac4cb9b5e99c Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Sun, 12 Mar 2023 10:57:53 -0400 Subject: [PATCH 1/6] Update LLR & IQ plot with correct number of elements --- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 8 + openair1/PHY/TOOLS/nr_phy_qt_scope.cpp | 273 +++++++++++++----- openair1/PHY/TOOLS/nr_phy_qt_scope.h | 81 ++++++ openair1/PHY/TOOLS/phy_scope_interface.h | 24 ++ 4 files changed, 319 insertions(+), 67 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index b06b690c0b..f58251c597 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -8,6 +8,7 @@ #include "PHY/NR_ESTIMATION/nr_ul_estimation.h" #include "PHY/defs_nr_common.h" #include "common/utils/nr/nr_common.h" +#include //#define DEBUG_CH_COMP //#define DEBUG_RB_EXT @@ -2015,6 +2016,7 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB, ad_shift = -3; // For 2-layers, we are already doing a bit shift in the nr_ulsch_mmse_2layers() function, so we can use more bits } + int num_re_total = 0; for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); symbol++) { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; if (dmrs_symbol_flag == 1) { @@ -2037,6 +2039,7 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB, nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB; } + num_re_total += nb_re_pusch; pusch_vars->ul_valid_re_per_slot[symbol] = nb_re_pusch; LOG_D(PHY, "symbol %d: nb_re_pusch %d, DMRS symbl used for Chest :%d \n", symbol, nb_re_pusch, pusch_vars->dmrs_symbol); @@ -2214,4 +2217,9 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB, rxdataF_ext_offset += pusch_vars->ul_valid_re_per_slot[symbol]; } } // symbol loop + if (!(frame % 128)) { + int num_llr = num_re_total*rel15_ul->qam_mod_order; + GnbScopeUpdate(gNB, puschLLR, num_llr); + GnbScopeUpdate(gNB, puschIQ, num_re_total); + } } diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp index 4f73978448..d38af06f93 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,23 @@ float Limits_KPI_ue[2][2] = { {0.2, 10} // Throughput in Mbs }; +// Holds status of active plots +bool currentActivePlots[static_cast(PlotTypeGnb::config)]; + +LLRPlotGnb *puschLlr; +IQPlotGnb *puschIq; + +void scopeUpdaterGnb(enum PlotTypeGnbIf plotType, int numElt) +{ + if (plotType == puschLLR && currentActivePlots[static_cast(PlotTypeGnb::puschLLR)]) { + puschLlr->len = numElt; + puschLlr->newData->updateScope(); + } else if (plotType == puschIQ && currentActivePlots[static_cast(PlotTypeGnb::puschIQ)]) { + puschIq->len = numElt; + puschIq->newData->updateScope(); + } +} + /* This class creates the window when choosing the option 'Configs' to configure the threshold values. */ ConfigBoxFloat::ConfigBoxFloat(float *valuePtr, QWidget *parent) : QLineEdit(parent), valuePtr(valuePtr) { @@ -372,6 +390,61 @@ LLRPlot::LLRPlot(int16_t *data, int len) : data(data), len(len) startTimer(1000); } +LLRPlotGnb::LLRPlotGnb(int16_t *data, int len, PlotTypeGnb plotType) : data(data) +{ + this->len = len; + this->plotType = plotType; + NewDataHere *newData = new NewDataHere(); + this->newData = newData; + puschLlr = this; + connect(newData, &NewDataHere::updateScope, this, &LLRPlotGnb::updatePlot); + this->legend()->hide(); + + // add new series to the chart + this->series = new QScatterSeries(); + this->series->setMarkerSize(3); + this->series->setMarkerShape(QScatterSeries::MarkerShapeRectangle); + this->series->setColor(Qt::blue); + this->series->setPen(Qt::NoPen); + this->addSeries(series); + + // add new X axis + this->axisX = new QValueAxis(); + this->axisX->setLabelFormat("%d"); + this->axisX->setRange(0, len); + this->addAxis(this->axisX, Qt::AlignBottom); + this->series->attachAxis(this->axisX); + + // add new Y axis + this->axisY = new QValueAxis(); + this->addAxis(this->axisY, Qt::AlignLeft); + this->series->attachAxis(this->axisY); +} + +LLRPlotGnb::~LLRPlotGnb() +{ + currentActivePlots[static_cast(this->plotType)] = false; + puschLlr = nullptr; +} + +void LLRPlotGnb::updatePlot() +{ + if (!this->isVisible()) + return; + + 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->axisX->setRange(0, len); + this->axisY->setRange(-maxY, maxY); + this->series->replace(points); +} + void LLRPlot::timerEvent(QTimerEvent *event) { if (!this->isVisible()) @@ -411,6 +484,62 @@ void LLRPlotUE::timerEvent(QTimerEvent *event) } } +IQPlotGnb::IQPlotGnb(complex16 *data, int len, PlotTypeGnb plotType) : data(data) +{ + this->len = len; + this->plotType = plotType; + NewDataHere *newData = new NewDataHere(); + this->newData = newData; + puschIq = this; + connect(newData, &NewDataHere::updateScope, this, &IQPlotGnb::updatePlot); + this->legend()->hide(); + + // add new series to the chart + this->series = new QScatterSeries(); + this->series->setMarkerSize(3); + this->series->setMarkerShape(QScatterSeries::MarkerShapeRectangle); + this->series->setColor(Qt::blue); + this->series->setPen(Qt::NoPen); + this->addSeries(series); + + // add new X axis + this->axisX = new QValueAxis(); + this->addAxis(this->axisX, Qt::AlignBottom); + this->series->attachAxis(this->axisX); + + // add new Y axis + this->axisY = new QValueAxis(); + this->addAxis(this->axisY, Qt::AlignLeft); + this->series->attachAxis(this->axisY); +} + +IQPlotGnb::~IQPlotGnb() +{ + currentActivePlots[static_cast(this->plotType)] = false; + puschIq = nullptr; +} + +void IQPlotGnb::updatePlot() +{ + if (!this->isVisible()) + return; + + 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); +} + IQPlot::IQPlot(complex16 *data, int len) : data(data), len(len) { this->legend()->hide(); @@ -742,6 +871,15 @@ void PainterWidgetGnb::makeConnections(int type) return; } + if (currentActivePlots[static_cast(plotType)]) { + QMessageBox::information( + this, + tr("gNB Scope"), + tr("Plot already exists.")); + return; + } + + const PlotTypeGnb prevPlotType = this->plotType; this->plotType = plotType; this->chartView->hide(); QChart *prevChart = this->chartView->chart(); @@ -767,76 +905,76 @@ void PainterWidgetGnb::makeConnections(int type) QChart *newChart = nullptr; - switch (plotType) { - case PlotTypeGnb::empty: { - newChart = new QChart(); - break; - } - case PlotTypeGnb::CIR: { - newChart = new CIRPlot((complex16 *)p->gNB->pusch_vars[0].ul_ch_estimates_time[0], frame_parms->ofdm_symbol_size); - break; - } + if (plotType == PlotTypeGnb::empty) { + newChart = new QChart(); + currentActivePlots[static_cast(prevPlotType)] = false; + } else { + switch (plotType) { + case PlotTypeGnb::CIR: { + newChart = new CIRPlot((complex16 *)p->gNB->pusch_vars[0].ul_ch_estimates_time[0], frame_parms->ofdm_symbol_size); + break; + } - case PlotTypeGnb::puschLLR: { - int num_re = frame_parms->N_RB_UL * 12 * frame_parms->symbols_per_slot; - int Qm = 2; - int coded_bits_per_codeword = num_re * Qm; - newChart = new LLRPlot((int16_t *)p->gNB->pusch_vars[0].llr, coded_bits_per_codeword); - break; - } - case PlotTypeGnb::puschIQ: { - int num_re = frame_parms->N_RB_UL * 12 * frame_parms->symbols_per_slot; - newChart = new IQPlot((complex16 *)p->gNB->pusch_vars[0].rxdataF_comp[0], num_re); - break; - } - case PlotTypeGnb::puschSNR: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::puschBLER: { - newChart = new KPIPlot(this, Limits_KPI_gNB[0]); - break; - } - case PlotTypeGnb::puschMCS: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::puschRETX: { - newChart = new RTXPlot(targetUE->mac_stats.ul.rounds); - break; - } - case PlotTypeGnb::puschThroughput: { - newChart = new KPIPlot(this, Limits_KPI_gNB[1]); - break; - } + case PlotTypeGnb::puschLLR: { + int init_coded_bits_per_codeword = 100; + newChart = new LLRPlotGnb((int16_t *)p->gNB->pusch_vars[0].llr, init_coded_bits_per_codeword, plotType); + break; + } + case PlotTypeGnb::puschIQ: { + int init_num_re = 100; + newChart = new IQPlotGnb((complex16 *)p->gNB->pusch_vars[0].rxdataF_comp[0], init_num_re, plotType); + break; + } + case PlotTypeGnb::puschSNR: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::puschBLER: { + newChart = new KPIPlot(this, Limits_KPI_gNB[0]); + break; + } + case PlotTypeGnb::puschMCS: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::puschRETX: { + newChart = new RTXPlot(targetUE->mac_stats.ul.rounds); + break; + } + case PlotTypeGnb::puschThroughput: { + newChart = new KPIPlot(this, Limits_KPI_gNB[1]); + break; + } - case PlotTypeGnb::pdschSNR: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::pdschBLER: { - newChart = new KPIPlot(this, Limits_KPI_gNB[2]); - break; - } - case PlotTypeGnb::pdschMCS: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::pdschRETX: { - newChart = new RTXPlot(targetUE->mac_stats.dl.rounds); - break; - } - case PlotTypeGnb::pdschThroughput: { - newChart = new KPIPlot(this, Limits_KPI_gNB[3]); - break; - } - case PlotTypeGnb::pdschRBs: { - newChart = new KPIPlot(this); - break; - } + case PlotTypeGnb::pdschSNR: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::pdschBLER: { + newChart = new KPIPlot(this, Limits_KPI_gNB[2]); + break; + } + case PlotTypeGnb::pdschMCS: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::pdschRETX: { + newChart = new RTXPlot(targetUE->mac_stats.dl.rounds); + break; + } + case PlotTypeGnb::pdschThroughput: { + newChart = new KPIPlot(this, Limits_KPI_gNB[3]); + break; + } + case PlotTypeGnb::pdschRBs: { + newChart = new KPIPlot(this); + break; + } - default: - break; + default: + break; + } + currentActivePlots[static_cast(plotType)] = true; } this->chartView->setChart(newChart); @@ -1240,6 +1378,7 @@ void nrgNBinitQtScope(scopeParms_t *p) scope->argc = p->argc; scope->argv = p->argv; scope->ru = p->ru; + scope->scopeUpdater = scopeUpdaterGnb; scope->copyData = copyData; copyDataMutexInit(scope); diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.h b/openair1/PHY/TOOLS/nr_phy_qt_scope.h index 8a00d5fa96..494af14cb8 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.h +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.h @@ -245,6 +245,51 @@ class CIRPlotUE : public CIRPlot { ValueProviderUE *valueProvider; }; +/// New data signal emiter +class NewDataHere : public QObject { + Q_OBJECT + + signals: + void updateScope(); +}; + +/// Chart class for plotting LLRs +class LLRPlotGnb : public QChart { + Q_OBJECT + + public: + /// Constructor + /// \param data Pointer to the LLR data + /// \param len Length of the LLR data + LLRPlotGnb(int16_t *data, int len, PlotTypeGnb plotType); + ~LLRPlotGnb(); + + public slots: + void updatePlot(); + + public: + /// Length of the LLR data + int len; + + NewDataHere *newData; + + private: + /// Pointer to the LLR data + int16_t *data; + + /// Scatter series used to plot the LLR in the chart + QScatterSeries *series; + + /// Horizontal axis of the chart + QValueAxis *axisX; + + /// Vertical axis of the chart + QValueAxis *axisY; + + /// Currently plotted KPI type + PlotTypeGnb plotType; +}; + /// Chart class for plotting LLRs class LLRPlot : public QChart { Q_OBJECT @@ -291,6 +336,42 @@ class LLRPlotUE : public LLRPlot { ValueProviderUE *valueProvider; }; +/// Chart class for plotting the I/Q constellation diagram +class IQPlotGnb : public QChart { + Q_OBJECT + + public: + /// Constructor + /// \param data Pointer to the complex I/Q data + /// \param len Length of the I/Q data + IQPlotGnb(complex16 *data, int len, PlotTypeGnb plotType); + ~IQPlotGnb(); + + /// Length of the I/Q data + int len; + + NewDataHere *newData; + + public slots: + void updatePlot(); + + private: + /// Pointer to the I/Q data + complex16 *data; + + /// Scatter series used to plot the I/Q constellation diagram + QScatterSeries *series; + + /// Horizontal axis of the chart + QValueAxis *axisX; + + /// Vertical axis of the chart + QValueAxis *axisY; + + /// Currently plotted KPI type + PlotTypeGnb plotType; +}; + /// Chart class for plotting the I/Q constellation diagram class IQPlot : public QChart { Q_OBJECT diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index 3c520513cf..fd429db2c1 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -70,6 +70,26 @@ enum scopeDataType { MAX_SCOPE_TYPES }; +enum PlotTypeGnbIf { + empty, + waterFall, + CIR, + puschLLR, + puschIQ, + puschSNR, + puschBLER, + puschMCS, + puschRETX, + puschThroughput, + pdschSNR, + pdschBLER, + pdschMCS, + pdschRETX, + pdschThroughput, + pdschRBs, + config +}; + #define COPIES_MEM 4 typedef struct { @@ -89,6 +109,7 @@ typedef struct scopeData_s { pthread_mutex_t copyDataMutex; scopeGraphData_t *copyDataBufs[MAX_SCOPE_TYPES][COPIES_MEM]; int copyDataBufsIdx[MAX_SCOPE_TYPES]; + void (*scopeUpdater)(enum PlotTypeGnbIf plotType, int numElements); } scopeData_t; int load_softscope(char *exectype, void *initarg); @@ -102,6 +123,9 @@ void copyData(void *, enum scopeDataType type, void *dataIn, int elementSz, int #define gNBscopeCopy(gnb, type, ...) \ if (gnb->scopeData) \ ((scopeData_t *)gnb->scopeData)->copyData((scopeData_t *)gNB->scopeData, type, ##__VA_ARGS__); +#define GnbScopeUpdate(gnb, type, numElt) \ + if (gnb->scopeData) \ + ((scopeData_t *)gnb->scopeData)->scopeUpdater(type, numElt); extended_kpi_ue* getKPIUE(); From 4b15a77ab75a96c6b2c9c0ae3c192807293ee55e Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Sun, 12 Mar 2023 14:03:07 -0400 Subject: [PATCH 2/6] Fix build issue --- openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 4 ++-- openair1/PHY/TOOLS/nr_phy_qt_scope.cpp | 4 ++-- openair1/PHY/TOOLS/phy_scope_interface.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index f58251c597..bf5b619528 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -2219,7 +2219,7 @@ void nr_rx_pusch(PHY_VARS_gNB *gNB, } // symbol loop if (!(frame % 128)) { int num_llr = num_re_total*rel15_ul->qam_mod_order; - GnbScopeUpdate(gNB, puschLLR, num_llr); - GnbScopeUpdate(gNB, puschIQ, num_re_total); + GnbScopeUpdate(gNB, puschLLRe, num_llr); + GnbScopeUpdate(gNB, puschIQe, num_re_total); } } diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp index d38af06f93..ac179bf8e5 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp @@ -79,10 +79,10 @@ IQPlotGnb *puschIq; void scopeUpdaterGnb(enum PlotTypeGnbIf plotType, int numElt) { - if (plotType == puschLLR && currentActivePlots[static_cast(PlotTypeGnb::puschLLR)]) { + if (plotType == puschLLRe && currentActivePlots[static_cast(PlotTypeGnb::puschLLR)]) { puschLlr->len = numElt; puschLlr->newData->updateScope(); - } else if (plotType == puschIQ && currentActivePlots[static_cast(PlotTypeGnb::puschIQ)]) { + } else if (plotType == puschIQe && currentActivePlots[static_cast(PlotTypeGnb::puschIQ)]) { puschIq->len = numElt; puschIq->newData->updateScope(); } diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index fd429db2c1..f21cb6a1d9 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -74,8 +74,8 @@ enum PlotTypeGnbIf { empty, waterFall, CIR, - puschLLR, - puschIQ, + puschLLRe, + puschIQe, puschSNR, puschBLER, puschMCS, From 3d1d468705d105531553ba2971dc7841ad078a18 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 15 Mar 2023 11:10:05 +0100 Subject: [PATCH 3/6] changes from review and updated indentation with clang-format --- openair1/PHY/TOOLS/nr_phy_qt_scope.cpp | 333 +++++++++-------------- openair1/PHY/TOOLS/nr_phy_qt_scope.h | 121 +++----- openair1/PHY/TOOLS/phy_scope_interface.h | 15 - 3 files changed, 168 insertions(+), 301 deletions(-) diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp index ac179bf8e5..8c6a49110e 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -72,19 +71,22 @@ float Limits_KPI_ue[2][2] = { }; // Holds status of active plots -bool currentActivePlots[static_cast(PlotTypeGnb::config)]; - -LLRPlotGnb *puschLlr; -IQPlotGnb *puschIq; +std::set puschLlrSet; +std::set puschIqSet; void scopeUpdaterGnb(enum PlotTypeGnbIf plotType, int numElt) { - if (plotType == puschLLRe && currentActivePlots[static_cast(PlotTypeGnb::puschLLR)]) { - puschLlr->len = numElt; - puschLlr->newData->updateScope(); - } else if (plotType == puschIQe && currentActivePlots[static_cast(PlotTypeGnb::puschIQ)]) { - puschIq->len = numElt; - puschIq->newData->updateScope(); + switch (plotType) { + case puschLLRe: + for (auto puschLlr = puschLlrSet.begin(); puschLlr != puschLlrSet.end(); puschLlr++) { + (*puschLlr)->updatePlot(numElt); + } + break; + case puschIQe: + for (auto puschIq = puschIqSet.begin(); puschIq != puschIqSet.end(); puschIq++) { + (*puschIq)->updatePlot(numElt); + } + break; } } @@ -196,7 +198,8 @@ KPIListSelectUE::KPIListSelectUE(QWidget *parent) : QComboBox(parent) this->addItem("Configs", static_cast(PlotTypeUE::config)); } -WaterFall::WaterFall(complex16 *values, NR_DL_FRAME_PARMS *frame_parms, QWidget *parent) : QWidget(parent), values(values), frame_parms(frame_parms) +WaterFall::WaterFall(complex16 *values, NR_DL_FRAME_PARMS *frame_parms, QWidget *parent) + : QWidget(parent), values(values), frame_parms(frame_parms) { this->iteration = 0; this->image = nullptr; @@ -205,8 +208,8 @@ WaterFall::WaterFall(complex16 *values, NR_DL_FRAME_PARMS *frame_parms, QWidget startTimer(100); } -/* this function to plot the waterfall graph for the RX signal in time domain for one frame. x-axis shows the frame divided into slots - and the y-axis is a color map depending on the SquaredNorm of the received signal at the correspoinding slot. */ +/* this function to plot the waterfall graph for the RX signal in time domain for one frame. x-axis shows the frame divided into + slots and the y-axis is a color map depending on the SquaredNorm of the received signal at the correspoinding slot. */ void WaterFall::timerEvent(QTimerEvent *event) { if (!this->isVisible()) @@ -363,7 +366,8 @@ void CIRPlotUE::timerEvent(QTimerEvent *event) } } -LLRPlot::LLRPlot(int16_t *data, int len) : data(data), len(len) +LLRPlot::LLRPlot(int16_t *data, int len, int interval, std::set *notificationSet) + : data(data), len(len), notificationSet(notificationSet) { this->legend()->hide(); @@ -378,7 +382,6 @@ LLRPlot::LLRPlot(int16_t *data, int len) : data(data), len(len) // add new X axis this->axisX = new QValueAxis(); this->axisX->setLabelFormat("%d"); - this->axisX->setRange(0, len); this->addAxis(this->axisX, Qt::AlignBottom); this->series->attachAxis(this->axisX); @@ -387,55 +390,30 @@ LLRPlot::LLRPlot(int16_t *data, int len) : data(data), len(len) this->addAxis(this->axisY, Qt::AlignLeft); this->series->attachAxis(this->axisY); - startTimer(1000); + if (interval) + startTimer(interval); + + if (notificationSet) + notificationSet->insert(this); } -LLRPlotGnb::LLRPlotGnb(int16_t *data, int len, PlotTypeGnb plotType) : data(data) +LLRPlot::~LLRPlot() +{ + if (this->notificationSet) + this->notificationSet->erase(this); +} + +void LLRPlot::updatePlot(int len) { this->len = len; - this->plotType = plotType; - NewDataHere *newData = new NewDataHere(); - this->newData = newData; - puschLlr = this; - connect(newData, &NewDataHere::updateScope, this, &LLRPlotGnb::updatePlot); - this->legend()->hide(); - // add new series to the chart - this->series = new QScatterSeries(); - this->series->setMarkerSize(3); - this->series->setMarkerShape(QScatterSeries::MarkerShapeRectangle); - this->series->setColor(Qt::blue); - this->series->setPen(Qt::NoPen); - this->addSeries(series); - - // add new X axis - this->axisX = new QValueAxis(); - this->axisX->setLabelFormat("%d"); - this->axisX->setRange(0, len); - this->addAxis(this->axisX, Qt::AlignBottom); - this->series->attachAxis(this->axisX); - - // add new Y axis - this->axisY = new QValueAxis(); - this->addAxis(this->axisY, Qt::AlignLeft); - this->series->attachAxis(this->axisY); -} - -LLRPlotGnb::~LLRPlotGnb() -{ - currentActivePlots[static_cast(this->plotType)] = false; - puschLlr = nullptr; -} - -void LLRPlotGnb::updatePlot() -{ if (!this->isVisible()) return; - QVector points(this->len); + QVector points(len); int maxY = this->axisY->max(); - for (int i = 0; i < this->len; i++) { + for (int i = 0; i < len; i++) { points[i] = QPointF(i, this->data[i]); maxY = std::max(maxY, abs(this->data[i])); } @@ -447,19 +425,7 @@ void LLRPlotGnb::updatePlot() void LLRPlot::timerEvent(QTimerEvent *event) { - if (!this->isVisible()) - return; - - 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); + this->updatePlot(this->len); } void LLRPlotUE::timerEvent(QTimerEvent *event) @@ -484,14 +450,9 @@ void LLRPlotUE::timerEvent(QTimerEvent *event) } } -IQPlotGnb::IQPlotGnb(complex16 *data, int len, PlotTypeGnb plotType) : data(data) +IQPlot::IQPlot(complex16 *data, int len, int interval, std::set *notificationSet) + : data(data), len(len), notificationSet(notificationSet) { - this->len = len; - this->plotType = plotType; - NewDataHere *newData = new NewDataHere(); - this->newData = newData; - puschIq = this; - connect(newData, &NewDataHere::updateScope, this, &IQPlotGnb::updatePlot); this->legend()->hide(); // add new series to the chart @@ -511,24 +472,32 @@ IQPlotGnb::IQPlotGnb(complex16 *data, int len, PlotTypeGnb plotType) : data(data this->axisY = new QValueAxis(); this->addAxis(this->axisY, Qt::AlignLeft); this->series->attachAxis(this->axisY); + + if (interval) + startTimer(interval); + + if (notificationSet) + notificationSet->insert(this); } -IQPlotGnb::~IQPlotGnb() +IQPlot::~IQPlot() { - currentActivePlots[static_cast(this->plotType)] = false; - puschIq = nullptr; + if (this->notificationSet) + this->notificationSet->erase(this); } -void IQPlotGnb::updatePlot() +void IQPlot::updatePlot(int len) { + this->len = len; + if (!this->isVisible()) return; - QVector points(this->len); + QVector points(len); int maxX = this->axisX->max(); int maxY = this->axisY->max(); - for (int i = 0; i < this->len; i++) { + for (int i = 0; i < len; i++) { points[i] = QPointF(this->data[i].r, this->data[i].i); maxX = std::max(maxX, abs(this->data[i].r)); @@ -540,50 +509,9 @@ void IQPlotGnb::updatePlot() this->series->replace(points); } -IQPlot::IQPlot(complex16 *data, int len) : data(data), len(len) -{ - this->legend()->hide(); - - // add new series to the chart - this->series = new QScatterSeries(); - this->series->setMarkerSize(3); - this->series->setMarkerShape(QScatterSeries::MarkerShapeRectangle); - this->series->setColor(Qt::blue); - this->series->setPen(Qt::NoPen); - this->addSeries(series); - - // add new X axis - this->axisX = new QValueAxis(); - this->addAxis(this->axisX, Qt::AlignBottom); - this->series->attachAxis(this->axisX); - - // add new Y axis - this->axisY = new QValueAxis(); - this->addAxis(this->axisY, Qt::AlignLeft); - this->series->attachAxis(this->axisY); - - startTimer(1000); -} - void IQPlot::timerEvent(QTimerEvent *event) { - if (!this->isVisible()) - return; - - 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); + this->updatePlot(this->len); } void IQPlotUE::timerEvent(QTimerEvent *event) @@ -796,7 +724,10 @@ PainterWidgetGnb::PainterWidgetGnb(QWidget *config, QComboBox *comboBox, scopeDa this->plotType = PlotTypeGnb::empty; makeConnections(this->comboBox->currentIndex()); - connect(this->comboBox, static_cast(&QComboBox::currentIndexChanged), this, &PainterWidgetGnb::makeConnections); + connect(this->comboBox, + static_cast(&QComboBox::currentIndexChanged), + this, + &PainterWidgetGnb::makeConnections); } float PainterWidgetGnb::getValue() @@ -871,15 +802,6 @@ void PainterWidgetGnb::makeConnections(int type) return; } - if (currentActivePlots[static_cast(plotType)]) { - QMessageBox::information( - this, - tr("gNB Scope"), - tr("Plot already exists.")); - return; - } - - const PlotTypeGnb prevPlotType = this->plotType; this->plotType = plotType; this->chartView->hide(); QChart *prevChart = this->chartView->chart(); @@ -905,76 +827,74 @@ void PainterWidgetGnb::makeConnections(int type) QChart *newChart = nullptr; - if (plotType == PlotTypeGnb::empty) { - newChart = new QChart(); - currentActivePlots[static_cast(prevPlotType)] = false; - } else { - switch (plotType) { - case PlotTypeGnb::CIR: { - newChart = new CIRPlot((complex16 *)p->gNB->pusch_vars[0].ul_ch_estimates_time[0], frame_parms->ofdm_symbol_size); - break; - } - - case PlotTypeGnb::puschLLR: { - int init_coded_bits_per_codeword = 100; - newChart = new LLRPlotGnb((int16_t *)p->gNB->pusch_vars[0].llr, init_coded_bits_per_codeword, plotType); - break; - } - case PlotTypeGnb::puschIQ: { - int init_num_re = 100; - newChart = new IQPlotGnb((complex16 *)p->gNB->pusch_vars[0].rxdataF_comp[0], init_num_re, plotType); - break; - } - case PlotTypeGnb::puschSNR: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::puschBLER: { - newChart = new KPIPlot(this, Limits_KPI_gNB[0]); - break; - } - case PlotTypeGnb::puschMCS: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::puschRETX: { - newChart = new RTXPlot(targetUE->mac_stats.ul.rounds); - break; - } - case PlotTypeGnb::puschThroughput: { - newChart = new KPIPlot(this, Limits_KPI_gNB[1]); - break; - } - - case PlotTypeGnb::pdschSNR: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::pdschBLER: { - newChart = new KPIPlot(this, Limits_KPI_gNB[2]); - break; - } - case PlotTypeGnb::pdschMCS: { - newChart = new KPIPlot(this); - break; - } - case PlotTypeGnb::pdschRETX: { - newChart = new RTXPlot(targetUE->mac_stats.dl.rounds); - break; - } - case PlotTypeGnb::pdschThroughput: { - newChart = new KPIPlot(this, Limits_KPI_gNB[3]); - break; - } - case PlotTypeGnb::pdschRBs: { - newChart = new KPIPlot(this); - break; - } - - default: - break; + switch (plotType) { + case PlotTypeGnb::empty: { + newChart = new QChart(); + break; } - currentActivePlots[static_cast(plotType)] = true; + case PlotTypeGnb::CIR: { + newChart = new CIRPlot((complex16 *)p->gNB->pusch_vars[0].ul_ch_estimates_time[0], frame_parms->ofdm_symbol_size); + break; + } + + case PlotTypeGnb::puschLLR: { + int init_coded_bits_per_codeword = 100; + newChart = new LLRPlot((int16_t *)p->gNB->pusch_vars[0].llr, init_coded_bits_per_codeword, 0, &puschLlrSet); + break; + } + case PlotTypeGnb::puschIQ: { + int init_num_re = 100; + newChart = new IQPlot((complex16 *)p->gNB->pusch_vars[0].rxdataF_comp[0], init_num_re, 0, &puschIqSet); + break; + } + case PlotTypeGnb::puschSNR: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::puschBLER: { + newChart = new KPIPlot(this, Limits_KPI_gNB[0]); + break; + } + case PlotTypeGnb::puschMCS: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::puschRETX: { + newChart = new RTXPlot(targetUE->mac_stats.ul.rounds); + break; + } + case PlotTypeGnb::puschThroughput: { + newChart = new KPIPlot(this, Limits_KPI_gNB[1]); + break; + } + + case PlotTypeGnb::pdschSNR: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::pdschBLER: { + newChart = new KPIPlot(this, Limits_KPI_gNB[2]); + break; + } + case PlotTypeGnb::pdschMCS: { + newChart = new KPIPlot(this); + break; + } + case PlotTypeGnb::pdschRETX: { + newChart = new RTXPlot(targetUE->mac_stats.dl.rounds); + break; + } + case PlotTypeGnb::pdschThroughput: { + newChart = new KPIPlot(this, Limits_KPI_gNB[3]); + break; + } + case PlotTypeGnb::pdschRBs: { + newChart = new KPIPlot(this); + break; + } + + default: + break; } this->chartView->setChart(newChart); @@ -984,7 +904,8 @@ void PainterWidgetGnb::makeConnections(int type) /* @UE: This is the main function of the UE sub-widgets, i.e., for each KPI. This function will be called only once when the the sub-widget is created, and it mainly initializes the widget variables and structures. */ -PainterWidgetUE::PainterWidgetUE(QWidget *config, QComboBox *comboBox, PHY_VARS_NR_UE *ue) : config(config), comboBox(comboBox), ue(ue) +PainterWidgetUE::PainterWidgetUE(QWidget *config, QComboBox *comboBox, PHY_VARS_NR_UE *ue) + : config(config), comboBox(comboBox), ue(ue) { this->chartView = new QChartView(this); this->chartView->hide(); @@ -992,7 +913,10 @@ PainterWidgetUE::PainterWidgetUE(QWidget *config, QComboBox *comboBox, PHY_VARS_ this->plotType = PlotTypeUE::empty; makeConnections(this->comboBox->currentIndex()); - connect(this->comboBox, static_cast(&QComboBox::currentIndexChanged), this, &PainterWidgetUE::makeConnections); + connect(this->comboBox, + static_cast(&QComboBox::currentIndexChanged), + this, + &PainterWidgetUE::makeConnections); } float PainterWidgetUE::getValue() @@ -1029,7 +953,6 @@ float PainterWidgetUE::getValue() case PlotTypeUE::timingAdvance: return (float)this->ue->timing_advance; - default: return 0; } diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.h b/openair1/PHY/TOOLS/nr_phy_qt_scope.h index 494af14cb8..95369e28a0 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.h +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.h @@ -24,6 +24,7 @@ #ifndef QT_SCOPE_MAINWINDOW_H #define QT_SCOPE_MAINWINDOW_H +#include #include extern "C" { @@ -94,7 +95,8 @@ class ValueProvider { class ValueProviderUE : public ValueProvider { public: /// This pure virtual function is meant to provide the graph values to be plotted - virtual scopeGraphData_t *getPlotValue() { + virtual scopeGraphData_t *getPlotValue() + { return nullptr; } }; @@ -234,7 +236,9 @@ class CIRPlotUE : public CIRPlot { Q_OBJECT public: - CIRPlotUE(complex16 *data, int len, ValueProviderUE *valueProvider) : CIRPlot(data, len), valueProvider(valueProvider) {} + 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 @@ -253,43 +257,6 @@ class NewDataHere : public QObject { void updateScope(); }; -/// Chart class for plotting LLRs -class LLRPlotGnb : public QChart { - Q_OBJECT - - public: - /// Constructor - /// \param data Pointer to the LLR data - /// \param len Length of the LLR data - LLRPlotGnb(int16_t *data, int len, PlotTypeGnb plotType); - ~LLRPlotGnb(); - - public slots: - void updatePlot(); - - public: - /// Length of the LLR data - int len; - - NewDataHere *newData; - - private: - /// Pointer to the LLR data - int16_t *data; - - /// Scatter series used to plot the LLR in the chart - QScatterSeries *series; - - /// Horizontal axis of the chart - QValueAxis *axisX; - - /// Vertical axis of the chart - QValueAxis *axisY; - - /// Currently plotted KPI type - PlotTypeGnb plotType; -}; - /// Chart class for plotting LLRs class LLRPlot : public QChart { Q_OBJECT @@ -298,10 +265,19 @@ class LLRPlot : public QChart { /// Constructor /// \param data Pointer to the LLR data /// \param len Length of the LLR data - LLRPlot(int16_t *data, int len); + /// \param interval update interval in ms (0 means no timer-triggered updates) + /// \param notificationSet pointer to a std::set for update notifications + LLRPlot(int16_t *data, int len, int interval = 1000, std::set *notificationSet = nullptr); + + /// Destructor + ~LLRPlot(); + + public slots: + /// This function updates the plotted LLR + void updatePlot(int len); protected: - /// This function is triggered when the own timer expires. It updates the plotted LLR + /// This function is triggered when the own timer expires. It calls updatePlot() to update the plotted LLR /// \param event Pointer to the timer event virtual void timerEvent(QTimerEvent *event) override; @@ -311,6 +287,9 @@ class LLRPlot : public QChart { /// Length of the LLR data int len; + /// Pointer to a std::set for update notifications + std::set *notificationSet; + /// Scatter series used to plot the LLR in the chart QScatterSeries *series; @@ -325,7 +304,9 @@ class LLRPlotUE : public LLRPlot { Q_OBJECT public: - LLRPlotUE(int16_t *data, int len, ValueProviderUE *valueProvider) : LLRPlot(data, len), valueProvider(valueProvider) {} + 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 @@ -336,42 +317,6 @@ class LLRPlotUE : public LLRPlot { ValueProviderUE *valueProvider; }; -/// Chart class for plotting the I/Q constellation diagram -class IQPlotGnb : public QChart { - Q_OBJECT - - public: - /// Constructor - /// \param data Pointer to the complex I/Q data - /// \param len Length of the I/Q data - IQPlotGnb(complex16 *data, int len, PlotTypeGnb plotType); - ~IQPlotGnb(); - - /// Length of the I/Q data - int len; - - NewDataHere *newData; - - public slots: - void updatePlot(); - - private: - /// Pointer to the I/Q data - complex16 *data; - - /// Scatter series used to plot the I/Q constellation diagram - QScatterSeries *series; - - /// Horizontal axis of the chart - QValueAxis *axisX; - - /// Vertical axis of the chart - QValueAxis *axisY; - - /// Currently plotted KPI type - PlotTypeGnb plotType; -}; - /// Chart class for plotting the I/Q constellation diagram class IQPlot : public QChart { Q_OBJECT @@ -380,10 +325,19 @@ class IQPlot : public QChart { /// Constructor /// \param data Pointer to the complex I/Q data /// \param len Length of the I/Q data - IQPlot(complex16 *data, int len); + /// \param interval update interval in ms (0 means no timer-triggered updates) + /// \param notificationSet pointer to a std::set for update notifications + IQPlot(complex16 *data, int len, int interval = 1000, std::set *notificationSet = nullptr); + + /// Destructor + ~IQPlot(); + + public slots: + /// This function updates the plotted I/Q constellation diagram + void updatePlot(int len); protected: - /// This function is triggered when the own timer expires. It updates the plotted I/Q constellation diagram + /// This function is triggered when the own timer expires. It calls updatePlot() to update the plotted I/Q constellation diagram /// \param event Pointer to the timer event virtual void timerEvent(QTimerEvent *event) override; @@ -393,6 +347,9 @@ class IQPlot : public QChart { /// Length of the I/Q data int len; + /// Pointer to a std::set for update notifications + std::set *notificationSet; + /// Scatter series used to plot the I/Q constellation diagram QScatterSeries *series; @@ -407,7 +364,9 @@ class IQPlotUE : public IQPlot { Q_OBJECT public: - IQPlotUE(complex16 *data, int len, ValueProviderUE *valueProvider) : IQPlot(data, len), valueProvider(valueProvider) {} + 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 diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index f21cb6a1d9..ca0f14e019 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -71,23 +71,8 @@ enum scopeDataType { }; enum PlotTypeGnbIf { - empty, - waterFall, - CIR, puschLLRe, puschIQe, - puschSNR, - puschBLER, - puschMCS, - puschRETX, - puschThroughput, - pdschSNR, - pdschBLER, - pdschMCS, - pdschRETX, - pdschThroughput, - pdschRBs, - config }; #define COPIES_MEM 4 From c36d81a0939e864efb07bc1031f39e1ca781d655 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 26 Jul 2023 13:02:36 +0200 Subject: [PATCH 4/6] replace std::set<> for active plots with PlotUpdater emitting queued signals --- openair1/PHY/TOOLS/nr_phy_qt_scope.cpp | 40 +++++++++++--------------- openair1/PHY/TOOLS/nr_phy_qt_scope.h | 33 +++++++++++---------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp index 8c6a49110e..36b0dc2b93 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp @@ -70,22 +70,18 @@ float Limits_KPI_ue[2][2] = { {0.2, 10} // Throughput in Mbs }; -// Holds status of active plots -std::set puschLlrSet; -std::set puschIqSet; +// Plot updater +PlotUpdater puschLlrUpdater; +PlotUpdater puschIqUpdater; void scopeUpdaterGnb(enum PlotTypeGnbIf plotType, int numElt) { switch (plotType) { case puschLLRe: - for (auto puschLlr = puschLlrSet.begin(); puschLlr != puschLlrSet.end(); puschLlr++) { - (*puschLlr)->updatePlot(numElt); - } + puschLlrUpdater.updatePlot(numElt); break; case puschIQe: - for (auto puschIq = puschIqSet.begin(); puschIq != puschIqSet.end(); puschIq++) { - (*puschIq)->updatePlot(numElt); - } + puschIqUpdater.updatePlot(numElt); break; } } @@ -366,8 +362,7 @@ void CIRPlotUE::timerEvent(QTimerEvent *event) } } -LLRPlot::LLRPlot(int16_t *data, int len, int interval, std::set *notificationSet) - : data(data), len(len), notificationSet(notificationSet) +LLRPlot::LLRPlot(int16_t *data, int len, int interval, PlotUpdater *plotUpdater) : data(data), len(len), plotUpdater(plotUpdater) { this->legend()->hide(); @@ -393,14 +388,14 @@ LLRPlot::LLRPlot(int16_t *data, int len, int interval, std::set *noti if (interval) startTimer(interval); - if (notificationSet) - notificationSet->insert(this); + if (plotUpdater) + connect(plotUpdater, &PlotUpdater::updatePlot, this, &LLRPlot::updatePlot, Qt::QueuedConnection); } LLRPlot::~LLRPlot() { - if (this->notificationSet) - this->notificationSet->erase(this); + if (this->plotUpdater) + disconnect(this->plotUpdater, &PlotUpdater::updatePlot, this, &LLRPlot::updatePlot); } void LLRPlot::updatePlot(int len) @@ -450,8 +445,7 @@ void LLRPlotUE::timerEvent(QTimerEvent *event) } } -IQPlot::IQPlot(complex16 *data, int len, int interval, std::set *notificationSet) - : data(data), len(len), notificationSet(notificationSet) +IQPlot::IQPlot(complex16 *data, int len, int interval, PlotUpdater *plotUpdater) : data(data), len(len), plotUpdater(plotUpdater) { this->legend()->hide(); @@ -476,14 +470,14 @@ IQPlot::IQPlot(complex16 *data, int len, int interval, std::set *notif if (interval) startTimer(interval); - if (notificationSet) - notificationSet->insert(this); + if (plotUpdater) + connect(plotUpdater, &PlotUpdater::updatePlot, this, &IQPlot::updatePlot, Qt::QueuedConnection); } IQPlot::~IQPlot() { - if (this->notificationSet) - this->notificationSet->erase(this); + if (this->plotUpdater) + disconnect(this->plotUpdater, &PlotUpdater::updatePlot, this, &IQPlot::updatePlot); } void IQPlot::updatePlot(int len) @@ -839,12 +833,12 @@ void PainterWidgetGnb::makeConnections(int type) case PlotTypeGnb::puschLLR: { int init_coded_bits_per_codeword = 100; - newChart = new LLRPlot((int16_t *)p->gNB->pusch_vars[0].llr, init_coded_bits_per_codeword, 0, &puschLlrSet); + newChart = new LLRPlot((int16_t *)p->gNB->pusch_vars[0].llr, init_coded_bits_per_codeword, 0, &puschLlrUpdater); break; } case PlotTypeGnb::puschIQ: { int init_num_re = 100; - newChart = new IQPlot((complex16 *)p->gNB->pusch_vars[0].rxdataF_comp[0], init_num_re, 0, &puschIqSet); + newChart = new IQPlot((complex16 *)p->gNB->pusch_vars[0].rxdataF_comp[0], init_num_re, 0, &puschIqUpdater); break; } case PlotTypeGnb::puschSNR: { diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.h b/openair1/PHY/TOOLS/nr_phy_qt_scope.h index 95369e28a0..08296e03d7 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.h +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.h @@ -24,7 +24,6 @@ #ifndef QT_SCOPE_MAINWINDOW_H #define QT_SCOPE_MAINWINDOW_H -#include #include extern "C" { @@ -101,6 +100,14 @@ class ValueProviderUE : public ValueProvider { } }; +/// Class for emitting a queued signal to update plots +class PlotUpdater : public QObject { + Q_OBJECT + + signals: + void updatePlot(int numElt); +}; + /// An editable GUI field for a dialog box to set certain KPI configurations class ConfigBoxFloat : public QLineEdit { Q_OBJECT @@ -249,14 +256,6 @@ class CIRPlotUE : public CIRPlot { ValueProviderUE *valueProvider; }; -/// New data signal emiter -class NewDataHere : public QObject { - Q_OBJECT - - signals: - void updateScope(); -}; - /// Chart class for plotting LLRs class LLRPlot : public QChart { Q_OBJECT @@ -266,8 +265,8 @@ class LLRPlot : public QChart { /// \param data Pointer to the LLR data /// \param len Length of the LLR data /// \param interval update interval in ms (0 means no timer-triggered updates) - /// \param notificationSet pointer to a std::set for update notifications - LLRPlot(int16_t *data, int len, int interval = 1000, std::set *notificationSet = nullptr); + /// \param plotUpdater pointer to a PlotUpdater for update notifications + LLRPlot(int16_t *data, int len, int interval = 1000, PlotUpdater *plotUpdater = nullptr); /// Destructor ~LLRPlot(); @@ -287,8 +286,8 @@ class LLRPlot : public QChart { /// Length of the LLR data int len; - /// Pointer to a std::set for update notifications - std::set *notificationSet; + /// Pointer to a PlotUpdater for update notifications + PlotUpdater *plotUpdater; /// Scatter series used to plot the LLR in the chart QScatterSeries *series; @@ -326,8 +325,8 @@ class IQPlot : public QChart { /// \param data Pointer to the complex I/Q data /// \param len Length of the I/Q data /// \param interval update interval in ms (0 means no timer-triggered updates) - /// \param notificationSet pointer to a std::set for update notifications - IQPlot(complex16 *data, int len, int interval = 1000, std::set *notificationSet = nullptr); + /// \param plotUpdater pointer to a PlotUpdater for update notifications + IQPlot(complex16 *data, int len, int interval = 1000, PlotUpdater *plotUpdater = nullptr); /// Destructor ~IQPlot(); @@ -347,8 +346,8 @@ class IQPlot : public QChart { /// Length of the I/Q data int len; - /// Pointer to a std::set for update notifications - std::set *notificationSet; + /// Pointer to a PlotUpdater for update notifications + PlotUpdater *plotUpdater; /// Scatter series used to plot the I/Q constellation diagram QScatterSeries *series; From d41147f411ac12047b61b7d5b4e84210fd3dd836 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 26 Jul 2023 13:53:55 +0200 Subject: [PATCH 5/6] fix introduced segfault in old scope --- openair1/PHY/TOOLS/nr_phy_scope.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openair1/PHY/TOOLS/nr_phy_scope.c b/openair1/PHY/TOOLS/nr_phy_scope.c index 9b0d152c6d..d07bf07076 100644 --- a/openair1/PHY/TOOLS/nr_phy_scope.c +++ b/openair1/PHY/TOOLS/nr_phy_scope.c @@ -738,6 +738,18 @@ static void *scope_thread_gNB(void *arg) { } #endif +static void scopeUpdaterGnb(enum PlotTypeGnbIf plotType, int numElt) +{ + switch (plotType) { + case puschLLRe: + /* update PUSCH LLR plot */ + break; + case puschIQe: + /* update PUSCH IQ plot */ + break; + } +} + STATICFORXSCOPE void gNBinitScope(scopeParms_t *p) { AssertFatal(p->gNB->scopeData = calloc(sizeof(scopeData_t), 1), ""); @@ -746,6 +758,7 @@ STATICFORXSCOPE void gNBinitScope(scopeParms_t *p) scope->argv=p->argv; scope->ru=p->ru; scope->gNB=p->gNB; + scope->scopeUpdater = scopeUpdaterGnb; scope->copyData = copyData; #ifndef WEBSRVSCOPE pthread_t forms_thread; From 17b191a01dbb950622baaf7eb74c33400f77f303 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 28 Jul 2023 13:49:52 +0200 Subject: [PATCH 6/6] use OpenGL for LLR and IQ Plots and fix UE LLR Plot Using OpenGL for IQ and LLR Plots improves plotting time significantly! Also use the correct length for UE CIR and UE LLR Plots. --- openair1/PHY/TOOLS/nr_phy_qt_scope.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp index 36b0dc2b93..4151a7e4cd 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp @@ -357,6 +357,7 @@ void CIRPlotUE::timerEvent(QTimerEvent *event) maxY = std::max(maxY, value); } + this->axisX->setRange(-this->len / 2, this->len / 2); this->axisY->setMax(maxY); this->series->replace(points); } @@ -368,6 +369,7 @@ LLRPlot::LLRPlot(int16_t *data, int len, int interval, PlotUpdater *plotUpdater) // add new series to the chart this->series = new QScatterSeries(); + this->series->setUseOpenGL(); this->series->setMarkerSize(3); this->series->setMarkerShape(QScatterSeries::MarkerShapeRectangle); this->series->setColor(Qt::blue); @@ -440,6 +442,7 @@ void LLRPlotUE::timerEvent(QTimerEvent *event) maxY = std::max(maxY, abs(this->data[i])); } + this->axisX->setRange(0, this->len); this->axisY->setRange(-maxY, maxY); this->series->replace(points); } @@ -451,6 +454,7 @@ IQPlot::IQPlot(complex16 *data, int len, int interval, PlotUpdater *plotUpdater) // add new series to the chart this->series = new QScatterSeries(); + this->series->setUseOpenGL(); this->series->setMarkerSize(3); this->series->setMarkerShape(QScatterSeries::MarkerShapeRectangle); this->series->setColor(Qt::blue);