From b8a5183b75497922573a19bdc6a2ac4cb9b5e99c Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Sun, 12 Mar 2023 10:57:53 -0400 Subject: [PATCH] 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();