1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-22 17:45:48 -05:00

Spectrum markers peaks option

This commit is contained in:
f4exb 2022-10-03 00:23:47 +02:00
parent 8a9662cf3f
commit 949a103b25
17 changed files with 241 additions and 7 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -192,6 +192,7 @@ set(sdrbase_SOURCES
util/morse.cpp
util/openaip.cpp
util/osndb.cpp
util/peakfinder.cpp
util/planespotters.cpp
util/png.cpp
util/prettyprint.cpp
@ -415,6 +416,7 @@ set(sdrbase_HEADERS
util/movingaverage.h
util/openaip.h
util/osndb.h
util/peakfinder.h
util/planespotters.h
util/png.h
util/prettyprint.h

View File

@ -78,6 +78,7 @@ void SpectrumSettings::resetToDefaults()
m_measurementHighlight = true;
m_measurementsPosition = PositionBelow;
m_measurementPrecision = 1;
m_findHistogramPeaks = false;
}
QByteArray SpectrumSettings::serialize() const
@ -128,6 +129,7 @@ QByteArray SpectrumSettings::serialize() const
s.writeS32(44, (int)m_measurementsPosition);
s.writeS32(45, m_measurementPrecision);
s.writeS32(46, m_measurementCenterFrequencyOffset);
s.writeBool(47, m_findHistogramPeaks);
s.writeS32(100, m_histogramMarkers.size());
for (int i = 0; i < m_histogramMarkers.size(); i++) {
@ -239,6 +241,7 @@ bool SpectrumSettings::deserialize(const QByteArray& data)
d.readS32(44, (int*)&m_measurementsPosition, (int)PositionBelow);
d.readS32(45, &m_measurementPrecision, 1);
d.readS32(46, &m_measurementCenterFrequencyOffset, 0);
d.readBool(47, &m_findHistogramPeaks, false);
int histogramMarkersSize;
d.readS32(100, &histogramMarkersSize, 0);

View File

@ -117,6 +117,7 @@ public:
QList<SpectrumHistogramMarker> m_histogramMarkers;
QList<SpectrumWaterfallMarker> m_waterfallMarkers;
QList<SpectrumAnnotationMarker> m_annoationMarkers;
bool m_findHistogramPeaks;
MarkersDisplay m_markersDisplay;
QList<SpectrumCalibrationPoint> m_calibrationPoints;
bool m_useCalibration;
@ -149,6 +150,7 @@ public:
QList<SpectrumHistogramMarker>& getHistogramMarkers() { return m_histogramMarkers; }
QList<SpectrumWaterfallMarker>& getWaterfallMarkers() { return m_waterfallMarkers; }
bool getHistogramFindPeaks() { return m_findHistogramPeaks; }
static int getAveragingMaxScale(AveragingMode averagingMode); //!< Max power of 10 multiplier to 2,5,10 base ex: 2 -> 2,5,10,20,50,100,200,500,1000
static int getAveragingValue(int averagingIndex, AveragingMode averagingMode);

View File

@ -0,0 +1,55 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 F4EXB //
// written by Edouard Griffiths //
// //
// Find peaks in a series of real values //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "peakfinder.h"
PeakFinder::PeakFinder() :
m_prevValue(0.0),
m_index(0)
{}
PeakFinder::~PeakFinder()
{}
void PeakFinder::init(Real value)
{
m_prevValue = value;
m_peaks.clear();
m_index = 0;
}
void PeakFinder::push(Real value, bool last)
{
Real diff = value - m_prevValue;
if (diff < 0) {
m_peaks.push_back({m_prevValue, m_index});
} else if (last) {
m_peaks.push_back({value, m_index});
}
m_prevValue = value;
m_index++;
}
void PeakFinder::sortPeaks()
{
std::sort(m_peaks.rbegin(), m_peaks.rend()); // descending order of values
}

48
sdrbase/util/peakfinder.h Normal file
View File

@ -0,0 +1,48 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2022 F4EXB //
// written by Edouard Griffiths //
// //
// Find peaks in a series of real values //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_UTIL_PEAKFINDER_H_
#define SDRBASE_UTIL_PEAKFINDER_H_
#include <vector>
#include <utility>
#include "dsp/dsptypes.h"
#include "export.h"
class SDRBASE_API PeakFinder {
public:
PeakFinder();
~PeakFinder();
void init(Real value);
void push(Real value, bool last=false);
void sortPeaks();
const std::vector<std::pair<Real, int>>& getPeaks() { return m_peaks; }
private:
Real m_prevValue;
int m_index;
std::vector<std::pair<Real, int>> m_peaks; //!< index, value
};
#endif // SDRBASE_UTIL_PEAKFINDER_H_

View File

@ -95,6 +95,8 @@ public:
void updateMarkersDisplay() { m_spectrum->updateMarkersDisplay(); }
void updateCalibrationPoints() { m_spectrum->updateCalibrationPoints(); }
SpectrumSettings::MarkersDisplay& getMarkersDisplay() { return m_spectrum->getMarkersDisplay(); }
bool& getHistogramFindPeaks() { return m_spectrum->getHistogramFindPeaks(); }
void setHistogramFindPeaks(bool value) { m_spectrum->setHistogramFindPeaks(value); }
void setMarkersDisplay(SpectrumSettings::MarkersDisplay markersDisplay) { m_spectrum->setMarkersDisplay(markersDisplay); }
QList<SpectrumCalibrationPoint>& getCalibrationPoints() { return m_spectrum->getCalibrationPoints(); }
void setCalibrationPoints(const QList<SpectrumCalibrationPoint>& calibrationPoints) { m_spectrum->setCalibrationPoints(calibrationPoints); }

View File

@ -463,6 +463,7 @@ void GLSpectrumGUI::on_markers_clicked(bool checked)
m_glSpectrum->getWaterfallMarkers(),
m_glSpectrum->getAnnotationMarkers(),
m_glSpectrum->getMarkersDisplay(),
m_glSpectrum->getHistogramFindPeaks(),
m_calibrationShiftdB,
this
);

View File

@ -48,6 +48,7 @@ const float GLSpectrumView::m_annotationMarkerHeight = 20.0f;
GLSpectrumView::GLSpectrumView(QWidget* parent) :
QOpenGLWidget(parent),
m_markersDisplay(SpectrumSettings::MarkersDisplaySpectrum),
m_histogramFindPeaks(false),
m_cursorState(CSNormal),
m_cursorChannel(0),
m_spectrumVis(nullptr),
@ -1369,7 +1370,7 @@ void GLSpectrumView::paintGL()
}
// paint current spectrum line on top of histogram
if ((m_displayCurrent) && m_currentSpectrum)
if (m_displayCurrent && m_currentSpectrum)
{
Real bottom = -m_powerRange;
GLfloat *q3;
@ -1403,6 +1404,10 @@ void GLSpectrumView::paintGL()
}
{
if (m_histogramFindPeaks) {
m_peakFinder.init(m_currentSpectrum[0]);
}
// Draw line
q3 = m_q3FFT.m_array;
for (int i = 0; i < m_nbBins; i++)
@ -1418,6 +1423,9 @@ void GLSpectrumView::paintGL()
q3[2*i] = (Real) i;
q3[2*i+1] = v;
if (m_histogramFindPeaks && (i > 0)) {
m_peakFinder.push(m_currentSpectrum[i], i == m_nbBins - 1);
}
}
QVector4D color;
@ -1427,12 +1435,22 @@ void GLSpectrumView::paintGL()
color = QVector4D(1.0f, 1.0f, 0.25f, (float) m_displayTraceIntensity / 100.0f);
}
m_glShaderSimple.drawPolyline(m_glHistogramSpectrumMatrix, color, q3, m_nbBins);
if (m_histogramFindPeaks) {
m_peakFinder.sortPeaks();
}
}
}
if (m_markersDisplay & SpectrumSettings::MarkersDisplaySpectrum) {
if (m_displayCurrent && m_currentSpectrum && (m_markersDisplay & SpectrumSettings::MarkersDisplaySpectrum))
{
if (m_histogramFindPeaks) {
updateHistogramPeaks();
}
drawSpectrumMarkers();
}
if (m_markersDisplay & SpectrumSettings::MarkersDisplayAnnotations) {
drawAnnotationMarkers();
}
@ -1724,7 +1742,7 @@ void GLSpectrumView::paintGL()
}
m_mutex.unlock();
}
} // paintGL
// Hightlight power band for SFDR
void GLSpectrumView::drawPowerBandMarkers(float max, float min, const QVector4D &color)
@ -3289,7 +3307,7 @@ void GLSpectrumView::updateHistogramMarkers()
if (i > 0)
{
int64_t deltaFrequency = m_histogramMarkers.at(i).m_frequency - m_histogramMarkers.at(0).m_frequency;
m_histogramMarkers.back().m_deltaFrequencyStr = displayScaled(
m_histogramMarkers[i].m_deltaFrequencyStr = displayScaled(
deltaFrequency,
'f',
getPrecision(deltaFrequency/m_sampleRate),
@ -3297,7 +3315,7 @@ void GLSpectrumView::updateHistogramMarkers()
float power0 = m_linear ?
m_histogramMarkers.at(0).m_power * (m_useCalibration ? m_calibrationGain : 1.0f) :
CalcDb::dbPower(m_histogramMarkers.at(0).m_power) + (m_useCalibration ? m_calibrationShiftdB : 0.0f);
m_histogramMarkers.back().m_deltaPowerStr = displayPower(
m_histogramMarkers[i].m_deltaPowerStr = displayPower(
powerI - power0,
m_linear ? 'e' : 'f',
m_linear ? 3 : 1);
@ -3305,6 +3323,57 @@ void GLSpectrumView::updateHistogramMarkers()
}
}
void GLSpectrumView::updateHistogramPeaks()
{
int j = 0;
for (int i = 0; i < m_histogramMarkers.size(); i++)
{
if (j >= (int) m_peakFinder.getPeaks().size()) {
break;
}
int fftBin = m_peakFinder.getPeaks()[j].second;
Real power = m_peakFinder.getPeaks()[j].first;
// qDebug("GLSpectrumView::updateHistogramPeaks: %d %d %f", j, fftBin, power);
if ((m_histogramMarkers.at(i).m_markerType == SpectrumHistogramMarker::SpectrumMarkerTypePower) ||
((m_histogramMarkers.at(i).m_markerType == SpectrumHistogramMarker::SpectrumMarkerTypePowerMax) &&
(m_histogramMarkers.at(i).m_holdReset || (power > m_histogramMarkers.at(i).m_powerMax))))
{
float binSize = m_frequencyScale.getRange() / m_nbBins;
m_histogramMarkers[i].m_fftBin = fftBin;
m_histogramMarkers[i].m_frequency = m_frequencyScale.getRangeMin() + binSize*fftBin;
m_histogramMarkers[i].m_point.rx() = binSize*fftBin / m_frequencyScale.getRange();
if (i == 0)
{
m_histogramMarkers[i].m_frequencyStr = displayScaled(
m_histogramMarkers[i].m_frequency,
'f',
getPrecision((m_centerFrequency*1000)/m_sampleRate),
false
);
}
else
{
int64_t deltaFrequency = m_histogramMarkers.at(i).m_frequency - m_histogramMarkers.at(0).m_frequency;
m_histogramMarkers[i].m_deltaFrequencyStr = displayScaled(
deltaFrequency,
'f',
getPrecision(deltaFrequency/m_sampleRate),
true
);
}
}
else
{
continue;
}
j++;
}
}
void GLSpectrumView::updateWaterfallMarkers()
{
for (int i = 0; i < m_waterfallMarkers.size(); i++)

View File

@ -43,6 +43,7 @@
#include "util/incrementalarray.h"
#include "util/message.h"
#include "util/colormap.h"
#include "util/peakfinder.h"
class QOpenGLShaderProgram;
class MessageQueue;
@ -214,11 +215,14 @@ public:
QList<SpectrumAnnotationMarker>& getAnnotationMarkers() { return m_annotationMarkers; }
void setAnnotationMarkers(const QList<SpectrumAnnotationMarker>& annotationMarkers);
void updateHistogramMarkers();
void updateHistogramPeaks();
void updateWaterfallMarkers();
void updateAnnotationMarkers();
void updateMarkersDisplay();
void updateCalibrationPoints();
SpectrumSettings::MarkersDisplay& getMarkersDisplay() { return m_markersDisplay; }
SpectrumSettings::MarkersDisplay& getMarkersDisplay() { return m_markersDisplay; }
bool& getHistogramFindPeaks() { return m_histogramFindPeaks; }
void setHistogramFindPeaks(bool value) { m_histogramFindPeaks = value; }
void setMarkersDisplay(SpectrumSettings::MarkersDisplay markersDisplay);
QList<SpectrumCalibrationPoint>& getCalibrationPoints() { return m_calibrationPoints; }
void setCalibrationPoints(const QList<SpectrumCalibrationPoint>& calibrationPoints);
@ -258,6 +262,8 @@ private:
QList<SpectrumAnnotationMarker*> m_sortedAnnotationMarkers;
QList<SpectrumAnnotationMarker*> m_visibleAnnotationMarkers;
SpectrumSettings::MarkersDisplay m_markersDisplay;
bool m_histogramFindPeaks;
PeakFinder m_peakFinder;
QList<SpectrumCalibrationPoint> m_calibrationPoints;
CursorState m_cursorState;

View File

@ -72,6 +72,11 @@ This combo lets you select the type of marker:
Use this slider to adjust the power position of the marker. The units are in dB irrespective of the linear or log set of the spectrum display.
<h3>11. Peak detection</h3>
Activates or de-activates peak detection. With peak detection engaged markers with type "Cur" or "Max" will be automatically set to frequency (bin) of maximum power. The first marker in index order with "Cur" or "Max" will be set to the highest peak in magnitude then next marker to next peak in magnitude order etc,,, Markers of type "Cur" will track current peaks and markers of type "Max" will track peak maxima making it more suitable for transient signals.
<h2>Waterfall markers tab</h2>
![Spectrum Markers waterfall dialog](../../doc/img/Spectrum_Markers_dialog_wat.png)

View File

@ -32,6 +32,7 @@ SpectrumMarkersDialog::SpectrumMarkersDialog(
QList<SpectrumWaterfallMarker>& waterfallMarkers,
QList<SpectrumAnnotationMarker>& annotationMarkers,
SpectrumSettings::MarkersDisplay& markersDisplay,
bool& findPeaks,
float calibrationShiftdB,
QWidget* parent) :
QDialog(parent),
@ -40,6 +41,7 @@ SpectrumMarkersDialog::SpectrumMarkersDialog(
m_waterfallMarkers(waterfallMarkers),
m_annotationMarkers(annotationMarkers),
m_markersDisplay(markersDisplay),
m_findPeaks(findPeaks),
m_calibrationShiftdB(calibrationShiftdB),
m_histogramMarkerIndex(0),
m_waterfallMarkerIndex(0),
@ -63,6 +65,7 @@ SpectrumMarkersDialog::SpectrumMarkersDialog(
ui->fixedPower->setColorMapper(ColorMapper::GrayYellow);
ui->fixedPower->setValueRange(false, 4, -2000, 400, 1);
ui->showSelect->setCurrentIndex((int) m_markersDisplay);
ui->findPeaks->setChecked(m_findPeaks);
displayHistogramMarker();
displayWaterfallMarker();
displayAnnotationMarker();
@ -94,8 +97,12 @@ void SpectrumMarkersDialog::displayHistogramMarker()
}
else
{
bool disableFreq = m_findPeaks && (
(m_histogramMarkers[m_histogramMarkerIndex].m_markerType == SpectrumHistogramMarker::SpectrumMarkerTypePower) ||
(m_histogramMarkers[m_histogramMarkerIndex].m_markerType == SpectrumHistogramMarker::SpectrumMarkerTypePowerMax)
);
ui->marker->setEnabled(true);
ui->markerFrequency->setEnabled(true);
ui->markerFrequency->setEnabled(!disableFreq);
ui->powerMode->setEnabled(true);
ui->fixedPower->setEnabled(true);
ui->showMarker->setEnabled(true);
@ -403,6 +410,12 @@ void SpectrumMarkersDialog::on_powerHoldReset_clicked()
m_histogramMarkers[m_histogramMarkerIndex].m_holdReset = true;
}
void SpectrumMarkersDialog::on_findPeaks_toggled(bool checked)
{
m_findPeaks = checked;
displayHistogramMarker();
}
void SpectrumMarkersDialog::on_wMarkerFrequency_changed(qint64 value)
{
if (m_waterfallMarkers.size() == 0) {

View File

@ -39,6 +39,7 @@ public:
QList<SpectrumWaterfallMarker>& waterfallMarkers,
QList<SpectrumAnnotationMarker>& annotationMarkers,
SpectrumSettings::MarkersDisplay& markersDisplay,
bool& findPeaks,
float calibrationShiftdB,
QWidget* parent = nullptr
);
@ -55,6 +56,7 @@ private:
QList<SpectrumWaterfallMarker>& m_waterfallMarkers;
QList<SpectrumAnnotationMarker>& m_annotationMarkers;
SpectrumSettings::MarkersDisplay& m_markersDisplay;
bool &m_findPeaks;
float m_calibrationShiftdB;
int m_histogramMarkerIndex;
int m_waterfallMarkerIndex;
@ -82,6 +84,7 @@ private slots:
void on_markerDel_clicked();
void on_powerMode_currentIndexChanged(int index);
void on_powerHoldReset_clicked();
void on_findPeaks_toggled(bool checked);
void on_wMarkerFrequency_changed(qint64 value);
void on_timeCoarse_valueChanged(int value);

View File

@ -498,6 +498,26 @@ Max - Marker will move according to the maximum power at the marker frequency</s
</property>
</spacer>
</item>
<item>
<widget class="ButtonSwitch" name="findPeaks">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Put markers in find peaks mode</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/dsb.png</normaloff>:/dsb.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -1799,6 +1819,11 @@ All - Show all markers</string>
<extends>QLabel</extends>
<header>gui/clickablelabel.h</header>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>buttonBox</tabstop>