Skip to content

Commit

Permalink
Merge pull request #1242 from willcode/feature/limit-plot-rate
Browse files Browse the repository at this point in the history
plotter: limit plot update rate
  • Loading branch information
argilo authored Jun 21, 2023
2 parents 21a3432 + 1456793 commit 3fa6595
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 41 deletions.
2 changes: 1 addition & 1 deletion resources/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
IMPROVED: Peak detection algorithm.
IMPROVED: Peak detection uses peak hold data when available.
IMPROVED: Maximum FFT size increased to 4M.
IMPROVED: Maximum frame rate increased to 250.
IMPROVED: Maximum frame rate increased to 500.
IMPROVED: Averaging slider is consistent across frame rates.
IMPROVED: Visibility of text in axes.
IMPROVED: Full support for high-DPI screens in plot & waterfall.
Expand Down
4 changes: 2 additions & 2 deletions src/applications/gqrx/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1796,8 +1796,8 @@ void MainWindow::setIqFftRate(int fps)
ui->plotter->setRunningState(true);
}

// Limit to 250 fps
if (interval > 3 && iq_fft_timer->isActive())
// Limit to 500 fps
if (interval > 1 && iq_fft_timer->isActive())
iq_fft_timer->setInterval(interval);

uiDockFft->setWfResolution(ui->plotter->getWfTimeRes());
Expand Down
12 changes: 11 additions & 1 deletion src/qtgui/dockfft.ui
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
</property>
<property name="toolTip">
<string>Amount of smoothing for plot
(histogram is not affected)</string>
(persistence for histogram)</string>
</property>
<property name="maximum">
<number>100</number>
Expand Down Expand Up @@ -646,6 +646,16 @@
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>500 fps</string>
</property>
</item>
<item>
<property name="text">
<string>333 fps</string>
</property>
</item>
<item>
<property name="text">
<string>250 fps</string>
Expand Down
81 changes: 44 additions & 37 deletions src/qtgui/plotter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ CPlotter::CPlotter(QWidget *parent) : QFrame(parent)

// always update waterfall
tlast_wf_ms = 0;
tlast_plot_drawn_ms = 0;
tlast_wf_drawn_ms = 0;
wf_valid_since_ms = 0;
msec_per_wfline = 0;
Expand Down Expand Up @@ -1245,11 +1246,15 @@ void CPlotter::draw(bool newData)

const double frameTime = 1.0 / (double)fft_rate;

// Redraw the plot if it is visible.
const bool doPlotter = !m_2DPixmap.isNull();
// Do plotter work only if visible.
const bool plotterVisible = (!m_2DPixmap.isNull());

// Limit plotter drawing rate.
const bool drawPlotter = (plotterVisible
&& tnow_ms >= tlast_plot_drawn_ms + PLOTTER_UPDATE_LIMIT_MS);

// Do not waste time with histogram calculations unless in this mode.
const bool doHistogram = m_PlotMode == PLOT_MODE_HISTOGRAM;
const bool doHistogram = (plotterVisible && m_PlotMode == PLOT_MODE_HISTOGRAM);

// Use fewer histogram bins when statistics are sparse
const int histBinsDisplayed = std::min(
Expand Down Expand Up @@ -1520,45 +1525,47 @@ void CPlotter::draw(bool newData)
}
}

// Update histogram IIR if it will be used.
if (doHistogram)
{
const double gamma = 1.0;
const double a = powf(1.0 - m_alpha, gamma);
// fast attack ... leaving alternative here in case it's useful
const double aAttack = 1.0;
// const double aAttack = 1.0 - a * frameTime;
const double aDecay = 1.0 - pow(a, 4.0 * frameTime);

histMax = 0.0;
for (i = xmin; i < xmax; ++i) {
for (j = 0; j < histBinsDisplayed; ++j)
{
double histV;
const double histPrev = m_histIIR[i][j];
const double histNew = m_histogram[i][j];
// Fast response when invalid
if (!m_histIIRValid)
histV = histNew;
else
histV = histPrev + aAttack * histNew - aDecay * histPrev;
m_histIIR[i][j] = std::max(histV, 0.0);
histMax = std::max(histMax, histV);
}
}
m_histIIRValid = true;

// 5 Hz time constant for colormap adjustment
const double histMaxAlpha = std::min(5.0 * frameTime, 1.0);
m_histMaxIIR = m_histMaxIIR * (1.0 - histMaxAlpha) + histMax * histMaxAlpha;
}

// get/draw the 2D spectrum
if (doPlotter)
if (drawPlotter)
{
tlast_plot_drawn_ms = tnow_ms;

m_2DPixmap.fill(PLOTTER_BGD_COLOR);
QPainter painter2(&m_2DPixmap);

// Update histogram IIR
const double frameTime = 1.0 / (double)fft_rate;
if (m_PlotMode == PLOT_MODE_HISTOGRAM)
{
const double gamma = 1.0;
const double a = powf(1.0 - m_alpha, gamma);
// fast attack ... leaving alternative here in case it's useful
const double aAttack = 1.0;
// const double aAttack = 1.0 - a * frameTime;
const double aDecay = 1.0 - pow(a, 4.0 * frameTime);

histMax = 0.0;
for (i = xmin; i < xmax; ++i) {
for (j = 0; j < histBinsDisplayed; ++j)
{
double histV;
const double histPrev = m_histIIR[i][j];
const double histNew = m_histogram[i][j];
// Fast response when invalid
if (!m_histIIRValid)
histV = histNew;
else
histV = histPrev + aAttack * histNew - aDecay * histPrev;
m_histIIR[i][j] = std::max(histV, 0.0);
histMax = std::max(histMax, histV);
}
}
m_histIIRValid = true;

// 5 Hz time constant for colormap adjustment
const double histMaxAlpha = std::min(5.0 * frameTime, 1.0);
m_histMaxIIR = m_histMaxIIR * (1.0 - histMaxAlpha) + histMax * histMaxAlpha;
}

// draw the pandapter
QBrush fillBrush = QBrush(m_FftFillCol);
Expand Down
2 changes: 2 additions & 0 deletions src/qtgui/plotter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define PEAK_CLICK_MAX_V_DISTANCE 20 //Maximum vertical distance of clicked point from peak
#define PEAK_WINDOW_HALF_WIDTH 10
#define PEAK_UPDATE_PERIOD 100 // msec
#define PLOTTER_UPDATE_LIMIT_MS 16 // 16ms = 62.5 Hz

#define MARKER_OFF std::numeric_limits<qint64>::min()

Expand Down Expand Up @@ -330,6 +331,7 @@ public slots:

// Waterfall averaging
quint64 tlast_wf_ms; // last time waterfall has been updated
quint64 tlast_plot_drawn_ms;// last time the plot was drawn
quint64 tlast_wf_drawn_ms; // last time waterfall was drawn
quint64 wf_valid_since_ms; // last time before action that invalidates time line
double msec_per_wfline{}; // milliseconds between waterfall updates
Expand Down

0 comments on commit 3fa6595

Please sign in to comment.