diff --git a/doc/img/FreqTracker_plugin.png b/doc/img/FreqTracker_plugin.png index 8ea6cbbee..cabc97428 100644 Binary files a/doc/img/FreqTracker_plugin.png and b/doc/img/FreqTracker_plugin.png differ diff --git a/doc/img/FreqTracker_plugin.xcf b/doc/img/FreqTracker_plugin.xcf index c542504ee..0c1217585 100644 Binary files a/doc/img/FreqTracker_plugin.xcf and b/doc/img/FreqTracker_plugin.xcf differ diff --git a/plugins/channelrx/freqtracker/freqtracker.cpp b/plugins/channelrx/freqtracker/freqtracker.cpp index 73e66fb6c..1b5f1ff75 100644 --- a/plugins/channelrx/freqtracker/freqtracker.cpp +++ b/plugins/channelrx/freqtracker/freqtracker.cpp @@ -182,6 +182,7 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force) << " m_rrc: " << settings.m_rrc << " m_rrcRolloff: " << settings.m_rrcRolloff << " m_streamIndex: " << settings.m_streamIndex + << " m_spanLog2: " << settings.m_spanLog2 << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -215,6 +216,9 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force) if ((m_settings.m_alphaEMA != settings.m_alphaEMA) || force) { reverseAPIKeys.append("alphaEMA"); } + if ((m_settings.m_spanLog2 != settings.m_spanLog2) || force) { + reverseAPIKeys.append("spanLog2"); + } if ((m_settings.m_tracking != settings.m_tracking) || force) { reverseAPIKeys.append("tracking"); } @@ -354,6 +358,9 @@ void FreqTracker::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("title")) { settings.m_title = *response.getFreqTrackerSettings()->getTitle(); } + if (channelSettingsKeys.contains("spanLog2")) { + settings.m_spanLog2 = response.getFreqTrackerSettings()->getSpanLog2(); + } if (channelSettingsKeys.contains("alphaEMA")) { float alphaEMA = response.getFreqTrackerSettings()->getAlphaEma(); settings.m_alphaEMA = alphaEMA < 0.01 ? 0.01 : alphaEMA > 1.0 ? 1.0 : alphaEMA; @@ -425,6 +432,7 @@ void FreqTracker::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r response.getFreqTrackerSettings()->setTitle(new QString(settings.m_title)); } + response.getFreqTrackerSettings()->setSpanLog2(settings.m_spanLog2); response.getFreqTrackerSettings()->setAlphaEma(settings.m_alphaEMA); response.getFreqTrackerSettings()->setTracking(settings.m_tracking ? 1 : 0); response.getFreqTrackerSettings()->setTrackerType((int) settings.m_trackerType); @@ -533,18 +541,42 @@ void FreqTracker::webapiFormatChannelSettings( if (channelSettingsKeys.contains("rfBandwidth") || force) { swgFreqTrackerSettings->setRfBandwidth(settings.m_rfBandwidth); } - if (channelSettingsKeys.contains("rgbColor") || force) { - swgFreqTrackerSettings->setRgbColor(settings.m_rgbColor); + if (channelSettingsKeys.contains("log2Decim") || force) { + swgFreqTrackerSettings->setLog2Decim(settings.m_log2Decim); } if (channelSettingsKeys.contains("squelch") || force) { swgFreqTrackerSettings->setSquelch(settings.m_squelch); } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgFreqTrackerSettings->setRgbColor(settings.m_rgbColor); + } if (channelSettingsKeys.contains("title") || force) { swgFreqTrackerSettings->setTitle(new QString(settings.m_title)); } + if (channelSettingsKeys.contains("spanLog2") || force) { + swgFreqTrackerSettings->setSpanLog2(settings.m_spanLog2); + } + if (channelSettingsKeys.contains("alphaEMA") || force) { + swgFreqTrackerSettings->setAlphaEma(settings.m_alphaEMA); + } + if (channelSettingsKeys.contains("tracking") || force) { + swgFreqTrackerSettings->setTracking(settings.m_tracking ? 1 : 0); + } if (channelSettingsKeys.contains("trackerType") || force) { swgFreqTrackerSettings->setTrackerType((int) settings.m_trackerType); } + if (channelSettingsKeys.contains("pllPskOrder") || force) { + swgFreqTrackerSettings->setPllPskOrder(settings.m_pllPskOrder); + } + if (channelSettingsKeys.contains("rrc") || force) { + swgFreqTrackerSettings->setRrc(settings.m_rrc ? 1 : 0); + } + if (channelSettingsKeys.contains("rrcRolloff") || force) { + swgFreqTrackerSettings->setRrcRolloff(settings.m_rrcRolloff); + } + if (channelSettingsKeys.contains("squelchGate") || force) { + swgFreqTrackerSettings->setSquelchGate(settings.m_squelchGate); + } if (channelSettingsKeys.contains("streamIndex") || force) { swgFreqTrackerSettings->setStreamIndex(settings.m_streamIndex); } diff --git a/plugins/channelrx/freqtracker/freqtrackergui.cpp b/plugins/channelrx/freqtracker/freqtrackergui.cpp index b876a872e..8df525b23 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.cpp +++ b/plugins/channelrx/freqtracker/freqtrackergui.cpp @@ -91,8 +91,8 @@ bool FreqTrackerGUI::handleMessage(const Message& message) m_basebandSampleRate = cfg.getSampleRate(); int sinkSampleRate = m_basebandSampleRate / (1<channelSampleRateText->setText(tr("%1k").arg(QString::number(sinkSampleRate / 1000.0f, 'g', 5))); - ui->glSpectrum->setSampleRate(sinkSampleRate); - m_pllChannelMarker.setBandwidth(sinkSampleRate/1000); + displaySpectrumBandwidth(m_settings.m_spanLog2); + m_pllChannelMarker.setBandwidth(sinkSampleRate/500); if (sinkSampleRate > 1000) { ui->rfBW->setMaximum(sinkSampleRate/100); @@ -153,8 +153,8 @@ void FreqTrackerGUI::on_log2Decim_currentIndexChanged(int index) m_settings.m_log2Decim = index < 0 ? 0 : index > 6 ? 6 : index; int sinkSampleRate = m_basebandSampleRate / (1<channelSampleRateText->setText(tr("%1k").arg(QString::number(sinkSampleRate / 1000.0f, 'g', 5))); - ui->glSpectrum->setSampleRate(sinkSampleRate); - m_pllChannelMarker.setBandwidth(sinkSampleRate/1000); + displaySpectrumBandwidth(m_settings.m_spanLog2); + m_pllChannelMarker.setBandwidth(sinkSampleRate/500); if (sinkSampleRate > 1000) { ui->rfBW->setMaximum(sinkSampleRate/100); @@ -235,6 +235,15 @@ void FreqTrackerGUI::on_squelchGate_valueChanged(int value) applySettings(); } +void FreqTrackerGUI::on_spanLog2_valueChanged(int value) +{ + if ((value < 0) || (value > 6)) { + return; + } + + applySpectrumBandwidth(ui->spanLog2->value()); +} + void FreqTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; @@ -332,9 +341,9 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B ui->glSpectrum->setCenterFrequency(0); m_pllChannelMarker.blockSignals(true); - m_pllChannelMarker.setColor(Qt::gray); + m_pllChannelMarker.setColor(Qt::white); m_pllChannelMarker.setCenterFrequency(0); - m_pllChannelMarker.setBandwidth(35); + m_pllChannelMarker.setBandwidth(70); m_pllChannelMarker.setTitle("Tracker"); m_pllChannelMarker.setMovable(false); m_pllChannelMarker.blockSignals(false); @@ -369,6 +378,13 @@ void FreqTrackerGUI::applySettings(bool force) } } +void FreqTrackerGUI::applySpectrumBandwidth(int spanLog2, bool force) +{ + displaySpectrumBandwidth(spanLog2); + m_settings.m_spanLog2 = spanLog2; + applySettings(force); +} + void FreqTrackerGUI::displaySettings() { m_channelMarker.blockSignals(true); @@ -407,11 +423,29 @@ void FreqTrackerGUI::displaySettings() ui->squelchGateText->setText(QString("%1").arg(m_settings.m_squelchGate * 10.0f, 0, 'f', 0)); ui->squelchGate->setValue(m_settings.m_squelchGate); + displaySpectrumBandwidth(m_settings.m_spanLog2); displayStreamIndex(); blockApplySettings(false); } +void FreqTrackerGUI::displaySpectrumBandwidth(int spanLog2) +{ + int spectrumRate = (m_basebandSampleRate / (1<spanLog2->blockSignals(true); + ui->spanLog2->setValue(spanLog2); + ui->spanLog2->blockSignals(false); + ui->spanText->setText(tr("%1k").arg(spanStr)); + ui->glSpectrum->setSampleRate(spectrumRate); +} + void FreqTrackerGUI::displayStreamIndex() { if (m_deviceUISet->m_deviceMIMOEngine) { diff --git a/plugins/channelrx/freqtracker/freqtrackergui.h b/plugins/channelrx/freqtracker/freqtrackergui.h index 6e9b6e78f..4c7943bef 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.h +++ b/plugins/channelrx/freqtracker/freqtrackergui.h @@ -73,7 +73,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); + void applySpectrumBandwidth(int spanLog2, bool force = false); void displaySettings(); + void displaySpectrumBandwidth(int spanLog2); void displayStreamIndex(); bool handleMessage(const Message& message); @@ -92,6 +94,7 @@ private slots: void on_rrcRolloff_valueChanged(int value); void on_squelch_valueChanged(int value); void on_squelchGate_valueChanged(int value); + void on_spanLog2_valueChanged(int value); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); void handleInputMessages(); diff --git a/plugins/channelrx/freqtracker/freqtrackergui.ui b/plugins/channelrx/freqtracker/freqtrackergui.ui index 1419b08ed..4e88d0d5b 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.ui +++ b/plugins/channelrx/freqtracker/freqtrackergui.ui @@ -40,7 +40,7 @@ 0 0 401 - 140 + 151 @@ -673,15 +673,88 @@ + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Span + + + + + + + Spectrum display frequency span + + + 0 + + + 6 + + + 1 + + + 0 + + + 0 + + + Qt::Horizontal + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Spectrum display frequency span (kHz) + + + 6.0k + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + 0 - 150 - 391 - 171 + 160 + 401 + 161 diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.cpp b/plugins/channelrx/freqtracker/freqtrackersettings.cpp index bf187540d..96a831e01 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.cpp +++ b/plugins/channelrx/freqtracker/freqtrackersettings.cpp @@ -37,6 +37,7 @@ void FreqTrackerSettings::resetToDefaults() m_squelch = -40.0; m_rgbColor = QColor(200, 244, 66).rgb(); m_title = "Frequency Tracker"; + m_spanLog2 = 0; m_alphaEMA = 0.1; m_tracking = false; m_trackerType = TrackerFLL; @@ -72,6 +73,7 @@ QByteArray FreqTrackerSettings::serialize() const s.writeFloat(8, m_alphaEMA); s.writeString(9, m_title); s.writeBool(10, m_tracking); + s.writeS32(11, m_spanLog2); s.writeS32(12, (int) m_trackerType); s.writeU32(13, m_pllPskOrder); s.writeBool(14, m_rrc); @@ -130,6 +132,7 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data) m_alphaEMA = ftmp < 0.01 ? 0.01 : ftmp > 1.0 ? 1.0 : ftmp; d.readString(9, &m_title, "Frequency Tracker"); d.readBool(10, &m_tracking, false); + d.readS32(11, &m_spanLog2, 0); d.readS32(12, &tmp, 0); m_trackerType = tmp < 0 ? TrackerFLL : tmp > 2 ? TrackerPLL : (TrackerType) tmp; d.readU32(13, &utmp, 2); diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.h b/plugins/channelrx/freqtracker/freqtrackersettings.h index 71e287f1e..c3ba9ef85 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.h +++ b/plugins/channelrx/freqtracker/freqtrackersettings.h @@ -42,6 +42,7 @@ struct FreqTrackerSettings QString m_title; Serializable *m_channelMarker; Serializable *m_spectrumGUI; + int m_spanLog2; float m_alphaEMA; //!< alpha factor for delta frequency EMA bool m_tracking; TrackerType m_trackerType; diff --git a/plugins/channelrx/freqtracker/freqtrackersink.cpp b/plugins/channelrx/freqtracker/freqtrackersink.cpp index 4cbb8e85b..4b8ee1c78 100644 --- a/plugins/channelrx/freqtracker/freqtrackersink.cpp +++ b/plugins/channelrx/freqtracker/freqtrackersink.cpp @@ -36,6 +36,7 @@ FreqTrackerSink::FreqTrackerSink() : m_sinkSampleRate(48000), m_spectrumSink(nullptr), m_sampleBufferCount(0), + m_undersampleCount(0), m_squelchOpen(false), m_squelchGate(0), m_magsqSum(0.0f), @@ -57,6 +58,7 @@ FreqTrackerSink::FreqTrackerSink() : m_magsq = 0.0; m_sampleBufferSize = m_sinkSampleRate / 20; // 50 ms m_sampleBuffer.resize(m_sampleBufferSize); + m_sum = Complex{0.0, 0.0}; m_rrcFilter = new fftfilt(m_settings.m_rfBandwidth / m_sinkSampleRate, 2*1024); m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain @@ -107,7 +109,18 @@ void FreqTrackerSink::processOneSample(Complex &ci) { fftfilt::cmplx *sideband; int n_out; - m_sampleBuffer[m_sampleBufferCount++] = Sample(ci.real(), ci.imag()); + int decim = 1<10: Squelch time gate +

10: Squelch time gate

Number of milliseconds following squelch gate opening after which the signal is declared open. 0 means squelch is declared open with no delay and is suitable for burst signals. The value can be varied in steps of 10 ms from 0 to 990 ms. -

11: Channel spectrum

+

11: Spectrum display frequency span

-This is the spectrum display of the tracker channel. When the tracker is locked to the signal the center of the channel should fall almost in the middle of the signal spectrum (ideally in the middle when the tracker error is zero). Thus the locking can be followed dynamically and it can be more reliable than the lock indicator. A channel marker shows the tracker offset from the channel center frequency (tracker error). Its width is the tracker error tolerance but is hardly visible since it is 1/1000th of the channel width. Controls on the bottom of the panel are identical to the ones of the main spectrum display. +The channel signal is decimated by a power of two before being applied to the channel spectrum display. It is a kind of zoom on the center of the spectrum. + +

12: Channel spectrum

+ +This is the spectrum display of the tracker channel. When the tracker is locked to the signal the center of the channel should fall almost in the middle of the signal spectrum (ideally in the middle when the tracker error is zero). Thus the locking can be followed dynamically and it can be more reliable than the lock indicator. A channel marker shows the tracker offset from the channel center frequency (tracker error). Its width is the tracker error tolerance and is ±1/1000th of the channel width. Controls on the bottom of the panel are identical to the ones of the main spectrum display.