From 958abb9731e5c1946811c29da74844e4a1d5475f Mon Sep 17 00:00:00 2001 From: Josh Conway Date: Thu, 3 Sep 2020 07:12:49 -0400 Subject: [PATCH 1/2] added frequency offset feature to allow centering vertical graph around real captured frequency --- inputsource.cpp | 11 ++++++ inputsource.h | 3 ++ mainwindow.cpp | 17 +++++++++ mainwindow.h | 2 + plotview.cpp | 11 +++++- plotview.h | 2 + spectrogramcontrols.cpp | 10 +++++ spectrogramcontrols.h | 1 + spectrogramplot.cpp | 85 ++++++++++++++++++++++++++++------------- spectrogramplot.h | 2 + 10 files changed, 116 insertions(+), 28 deletions(-) diff --git a/inputsource.cpp b/inputsource.cpp index 6a7ebace..83877d49 100644 --- a/inputsource.cpp +++ b/inputsource.cpp @@ -249,6 +249,17 @@ double InputSource::rate() return sampleRate; } +void InputSource::setFrequencyOffset(double offset) +{ + frequencyOffset = offset; + invalidate(); +} + +double InputSource::offset() +{ + return frequencyOffset; +} + std::unique_ptr[]> InputSource::getSamples(size_t start, size_t length) { if (inputFile == nullptr) diff --git a/inputsource.h b/inputsource.h index d6d76e0d..b4602ce1 100644 --- a/inputsource.h +++ b/inputsource.h @@ -36,6 +36,7 @@ class InputSource : public SampleSource> QFile *inputFile = nullptr; size_t sampleCount = 0; double sampleRate = 0.0; + double frequencyOffset = 0.0; uchar *mmapData = nullptr; std::unique_ptr sampleAdapter; std::string _fmt; @@ -51,8 +52,10 @@ class InputSource : public SampleSource> return sampleCount; }; void setSampleRate(double rate); + void setFrequencyOffset(double rate); void setFormat(std::string fmt); double rate(); + double offset(); bool realSignal() { return _realSignal; }; diff --git a/mainwindow.cpp b/mainwindow.cpp index b5aa3ac7..477c3cda 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -44,6 +44,7 @@ MainWindow::MainWindow() // Connect dock inputs connect(dock, &SpectrogramControls::openFile, this, &MainWindow::openFile); connect(dock->sampleRate, static_cast(&QLineEdit::textChanged), this, static_cast(&MainWindow::setSampleRate)); + connect(dock->frequencyOffset, static_cast(&QLineEdit::textChanged), this, static_cast(&MainWindow::setFrequencyOffset)); connect(dock, static_cast(&SpectrogramControls::fftOrZoomChanged), plots, &PlotView::setFFTAndZoom); connect(dock->powerMaxSlider, &QSlider::valueChanged, plots, &PlotView::setPowerMax); connect(dock->powerMinSlider, &QSlider::valueChanged, plots, &PlotView::setPowerMin); @@ -107,11 +108,27 @@ void MainWindow::setSampleRate(QString rate) settings.setValue("SampleRate", sampleRate); } +void MainWindow::setFrequencyOffset(QString rate) +{ + auto frequencyOffset = rate.toDouble(); + input->setFrequencyOffset(frequencyOffset); + plots->setFrequencyOffset(frequencyOffset); + + // Save the frequency offset in settings as we're likely to be opening the same file across multiple runs + QSettings settings; + settings.setValue("FrequencyOffset", frequencyOffset); +} + void MainWindow::setSampleRate(double rate) { dock->sampleRate->setText(QString::number(rate)); } +void MainWindow::setFrequencyOffset(double rate) +{ + dock->frequencyOffset->setText(QString::number(rate)); +} + void MainWindow::setFormat(QString fmt) { input->setFormat(fmt.toUtf8().constData()); diff --git a/mainwindow.h b/mainwindow.h index 187400ca..8edb9440 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -36,6 +36,8 @@ public slots: void openFile(QString fileName); void setSampleRate(QString rate); void setSampleRate(double rate); + void setFrequencyOffset(QString rate); + void setFrequencyOffset(double rate); void setFormat(QString fmt); private: diff --git a/plotview.cpp b/plotview.cpp index b71ab7f5..211c9c45 100644 --- a/plotview.cpp +++ b/plotview.cpp @@ -505,7 +505,6 @@ void PlotView::paintTimeScale(QPainter &painter, QRect &rect, range_t sa painter.restore(); } - int PlotView::plotsHeight() { int height = 0; @@ -573,6 +572,16 @@ void PlotView::setSampleRate(double rate) emitTimeSelection(); } +void PlotView::setFrequencyOffset(double rate) +{ + frequencyOffset = rate; + + if (spectrogramPlot != nullptr) + spectrogramPlot->setFrequencyOffset(rate); + + emitTimeSelection(); +} + void PlotView::enableScales(bool enabled) { timeScaleEnabled = enabled; diff --git a/plotview.h b/plotview.h index e3cb0a6e..ed58cfe9 100644 --- a/plotview.h +++ b/plotview.h @@ -36,6 +36,7 @@ class PlotView : public QGraphicsView, Subscriber public: PlotView(InputSource *input); void setSampleRate(double rate); + void setFrequencyOffset(double rate); signals: void timeSelectionChanged(float time); @@ -76,6 +77,7 @@ public slots: int powerMax; bool cursorsEnabled; double sampleRate = 0.0; + double frequencyOffset = 0.0; bool timeScaleEnabled; int scrollZoomStepsAccumulated = 0; diff --git a/spectrogramcontrols.cpp b/spectrogramcontrols.cpp index 08007d9d..9a5c5852 100644 --- a/spectrogramcontrols.cpp +++ b/spectrogramcontrols.cpp @@ -41,6 +41,12 @@ SpectrogramControls::SpectrogramControls(const QString & title, QWidget * parent sampleRate->setValidator(double_validator); layout->addRow(new QLabel(tr("Sample rate:")), sampleRate); + frequencyOffset = new QLineEdit(); + auto freq_validator = new QDoubleValidator(this); + freq_validator->setBottom(0.0); + frequencyOffset->setValidator(freq_validator); + layout->addRow(new QLabel(tr("Frequency offset:")), frequencyOffset); + // Spectrogram settings layout->addRow(new QLabel()); // TODO: find a better way to add an empty row? layout->addRow(new QLabel(tr("Spectrogram"))); @@ -130,6 +136,10 @@ void SpectrogramControls::setDefaults() QSettings settings; int savedSampleRate = settings.value("SampleRate", 8000000).toInt(); sampleRate->setText(QString::number(savedSampleRate)); + + int savedFrequencyOffset = settings.value("FrequencyOffset", 0).toInt(); + frequencyOffset->setText(QString::number(savedFrequencyOffset)); + fftSizeSlider->setValue(settings.value("FFTSize", 9).toInt()); powerMaxSlider->setValue(settings.value("PowerMax", 0).toInt()); powerMinSlider->setValue(settings.value("PowerMin", -100).toInt()); diff --git a/spectrogramcontrols.h b/spectrogramcontrols.h index abe06d69..828f5eeb 100644 --- a/spectrogramcontrols.h +++ b/spectrogramcontrols.h @@ -62,6 +62,7 @@ private slots: public: QPushButton *fileOpenButton; QLineEdit *sampleRate; + QLineEdit *frequencyOffset; QSlider *fftSizeSlider; QSlider *zoomLevelSlider; QSlider *powerMaxSlider; diff --git a/spectrogramplot.cpp b/spectrogramplot.cpp index 975c69ba..eadf95f3 100644 --- a/spectrogramplot.cpp +++ b/spectrogramplot.cpp @@ -101,47 +101,73 @@ void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) int tickny = plotHeight / 2 + tick / bwPerPixel + y; if (!inputSource->realSignal()) - painter.drawLine(0, tickny, 30, tickny); - painter.drawLine(0, tickpy, 30, tickpy); + painter.drawLine(0, tickny, 30, tickny); // draws neg lines + painter.drawLine(0, tickpy, 30, tickpy); // draws pos lines - if (tick != 0) { + if (tick == 0) { char buf[128]; - if (bwPerTick % 1000000 == 0) { - snprintf(buf, sizeof(buf), "-%d MHz", (int)tick / 1000000); + if (bwPerTick % 1000000000 == 0) { + snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset + (int)tick) / 1000000000); + } else if (bwPerTick % 1000000 == 0) { + snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset + (int)tick) / 1000000); } else if(bwPerTick % 1000 == 0) { - snprintf(buf, sizeof(buf), "-%d kHz", tick / 1000); + snprintf(buf, sizeof(buf), "%d kHz", ((int)frequencyOffset + (int)tick) / 1000); } else { - snprintf(buf, sizeof(buf), "-%d Hz", tick); + snprintf(buf, sizeof(buf), "%d Hz", (int)frequencyOffset + tick); } - if (!inputSource->realSignal()) - painter.drawText(5, tickny - 5, buf); + painter.drawText(0, tickpy+5, buf); // draw 0 + } + + if (tick != 0) { + char buf[128]; + + if (!inputSource->realSignal()) { + if (bwPerTick % 1000000000 == 0) { + snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset - (int)tick) / 1000000000); + } else if (bwPerTick % 1000000 == 0) { + snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset - (int)tick) / 1000000); + } else if(bwPerTick % 1000 == 0) { + snprintf(buf, sizeof(buf), "%d kHz", ((int)frequencyOffset - (int)tick) / 1000); + } else { + snprintf(buf, sizeof(buf), "%d Hz", (int)frequencyOffset - tick); + } + painter.drawText(5, tickny - 5, buf); // draws neg text + } - buf[0] = ' '; - painter.drawText(5, tickpy + 15, buf); + if (bwPerTick % 1000000000 == 0) { + snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset + (int)tick) / 1000000000); + } else if (bwPerTick % 1000000 == 0) { + snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset + (int)tick) / 1000000); + } else if(bwPerTick % 1000 == 0) { + snprintf(buf, sizeof(buf), "%d kHz", ((int)frequencyOffset + (int)tick) / 1000); + } else { + snprintf(buf, sizeof(buf), "%d Hz", (int)frequencyOffset + tick); + } + painter.drawText(5, tickpy + 15, buf); // draws pos text } tick += bwPerTick; } // Draw small ticks - bwPerTick /= 10; - - if (bwPerTick >= 1 ) { - tick = 0; - while (tick <= sampleRate / 2) { - - int tickpy = plotHeight / 2 - tick / bwPerPixel + y; - int tickny = plotHeight / 2 + tick / bwPerPixel + y; - - if (!inputSource->realSignal()) - painter.drawLine(0, tickny, 3, tickny); - painter.drawLine(0, tickpy, 3, tickpy); - - tick += bwPerTick; - } - } +// bwPerTick /= 10; +// +// if (bwPerTick >= 1 ) { +// tick = 0; +// while (tick <= sampleRate / 2) { +// +// int tickpy = plotHeight / 2 - tick / bwPerPixel + y; +// int tickny = plotHeight / 2 + tick / bwPerPixel + y; +// +// if (!inputSource->realSignal()) +// painter.drawLine(0, tickny, 3, tickny); +// painter.drawLine(0, tickpy, 3, tickpy); +// +// tick += bwPerTick; +// } +// } painter.restore(); } @@ -329,6 +355,11 @@ void SpectrogramPlot::setSampleRate(size_t rate) sampleRate = rate; } +void SpectrogramPlot::setFrequencyOffset(size_t rate) +{ + frequencyOffset = rate; +} + void SpectrogramPlot::enableScales(bool enabled) { frequencyScaleEnabled = enabled; diff --git a/spectrogramplot.h b/spectrogramplot.h index ffe1d6a2..2181f2e5 100644 --- a/spectrogramplot.h +++ b/spectrogramplot.h @@ -46,6 +46,7 @@ class SpectrogramPlot : public Plot bool mouseEvent(QEvent::Type type, QMouseEvent event) override; std::shared_ptr>> input() { return inputSource; }; void setSampleRate(size_t sampleRate); + void setFrequencyOffset(size_t frequencyOffset); bool tunerEnabled(); void enableScales(bool enabled); @@ -72,6 +73,7 @@ public slots: float powerMax; float powerMin; size_t sampleRate; + size_t frequencyOffset; bool frequencyScaleEnabled; Tuner tuner; From a0162717c313ce74f22700cab55c913900ee3ecc Mon Sep 17 00:00:00 2001 From: Josh Conway Date: Thu, 3 Sep 2020 07:23:04 -0400 Subject: [PATCH 2/2] readded minor lines and cleaned up commit prior to PR --- plotview.cpp | 1 + spectrogramplot.cpp | 47 +++++++++++++++------------------------------ 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/plotview.cpp b/plotview.cpp index 211c9c45..1db9ce9c 100644 --- a/plotview.cpp +++ b/plotview.cpp @@ -505,6 +505,7 @@ void PlotView::paintTimeScale(QPainter &painter, QRect &rect, range_t sa painter.restore(); } + int PlotView::plotsHeight() { int height = 0; diff --git a/spectrogramplot.cpp b/spectrogramplot.cpp index eadf95f3..96db661d 100644 --- a/spectrogramplot.cpp +++ b/spectrogramplot.cpp @@ -104,22 +104,6 @@ void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) painter.drawLine(0, tickny, 30, tickny); // draws neg lines painter.drawLine(0, tickpy, 30, tickpy); // draws pos lines - if (tick == 0) { - char buf[128]; - - if (bwPerTick % 1000000000 == 0) { - snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset + (int)tick) / 1000000000); - } else if (bwPerTick % 1000000 == 0) { - snprintf(buf, sizeof(buf), "%d MHz", ((int)frequencyOffset + (int)tick) / 1000000); - } else if(bwPerTick % 1000 == 0) { - snprintf(buf, sizeof(buf), "%d kHz", ((int)frequencyOffset + (int)tick) / 1000); - } else { - snprintf(buf, sizeof(buf), "%d Hz", (int)frequencyOffset + tick); - } - - painter.drawText(0, tickpy+5, buf); // draw 0 - } - if (tick != 0) { char buf[128]; @@ -152,22 +136,21 @@ void SpectrogramPlot::paintFrequencyScale(QPainter &painter, QRect &rect) } // Draw small ticks -// bwPerTick /= 10; -// -// if (bwPerTick >= 1 ) { -// tick = 0; -// while (tick <= sampleRate / 2) { -// -// int tickpy = plotHeight / 2 - tick / bwPerPixel + y; -// int tickny = plotHeight / 2 + tick / bwPerPixel + y; -// -// if (!inputSource->realSignal()) -// painter.drawLine(0, tickny, 3, tickny); -// painter.drawLine(0, tickpy, 3, tickpy); -// -// tick += bwPerTick; -// } -// } + bwPerTick /= 10; + if (bwPerTick >= 1 ) { + tick = 0; + while (tick <= sampleRate / 2) { + + int tickpy = plotHeight / 2 - tick / bwPerPixel + y; + int tickny = plotHeight / 2 + tick / bwPerPixel + y; + + if (!inputSource->realSignal()) + painter.drawLine(0, tickny, 3, tickny); + painter.drawLine(0, tickpy, 3, tickpy); + + tick += bwPerTick; + } + } painter.restore(); }