Frequency tracker (4)

This commit is contained in:
f4exb 2019-05-04 22:00:24 +02:00
parent e1662d2f4e
commit 459063d4f2
4 changed files with 116 additions and 17 deletions

View File

@ -18,6 +18,7 @@
#include "freqtracker.h" #include "freqtracker.h"
#include <QTime> #include <QTime>
#include <QTimer>
#include <QDebug> #include <QDebug>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
@ -61,10 +62,21 @@ FreqTracker::FreqTracker(DeviceSourceAPI *deviceAPI) :
m_magsqSum(0.0f), m_magsqSum(0.0f),
m_magsqPeak(0.0f), m_magsqPeak(0.0f),
m_magsqCount(0), m_magsqCount(0),
m_timerConnected(false),
m_tickCount(0),
m_lastCorrAbs(0),
m_avgDeltaFreq(0.0),
m_settingsMutex(QMutex::Recursive) m_settingsMutex(QMutex::Recursive)
{ {
setObjectName(m_channelId); setObjectName(m_channelId);
#ifdef USE_INTERNAL_TIMER
#warning "Uses internal timer"
m_timer = new QTimer();
m_timer->start(50);
#else
m_timer = &DSPEngine::instance()->getMasterTimer();
#endif
m_magsq = 0.0; m_magsq = 0.0;
m_channelizer = new DownChannelizer(this); m_channelizer = new DownChannelizer(this);
@ -82,6 +94,11 @@ FreqTracker::FreqTracker(DeviceSourceAPI *deviceAPI) :
FreqTracker::~FreqTracker() FreqTracker::~FreqTracker()
{ {
disconnectTimer();
#ifdef USE_INTERNAL_TIMER
m_timer->stop();
delete m_timer;
#endif
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager; delete m_networkManager;
m_deviceAPI->removeChannelAPI(this); m_deviceAPI->removeChannelAPI(this);
@ -243,7 +260,7 @@ bool FreqTracker::handleMessage(const Message& cmd)
void FreqTracker::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force) void FreqTracker::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force)
{ {
qDebug() << "AMDemod::applyChannelSettings:" qDebug() << "FreqTracker::applyChannelSettings:"
<< " inputSampleRate: " << inputSampleRate << " inputSampleRate: " << inputSampleRate
<< " inputFrequencyOffset: " << inputFrequencyOffset; << " inputFrequencyOffset: " << inputFrequencyOffset;
@ -320,16 +337,26 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force)
if ((m_settings.m_tracking != settings.m_tracking) || force) if ((m_settings.m_tracking != settings.m_tracking) || force)
{ {
reverseAPIKeys.append("tracking"); reverseAPIKeys.append("tracking");
m_avgDeltaFreq = 0.0;
if (settings.m_tracking) if (settings.m_tracking)
{ {
m_pll.reset(); m_pll.reset();
m_fll.reset(); m_fll.reset();
m_lastCorrAbs = 0;
connectTimer();
}
else
{
disconnectTimer();
} }
} }
if ((m_settings.m_trackerType != settings.m_trackerType) || force) if ((m_settings.m_trackerType != settings.m_trackerType) || force)
{ {
reverseAPIKeys.append("trackerType"); reverseAPIKeys.append("trackerType");
m_lastCorrAbs = 0;
m_avgDeltaFreq = 0.0;
if (settings.m_trackerType == FreqTrackerSettings::TrackerFLL) { if (settings.m_trackerType == FreqTrackerSettings::TrackerFLL) {
m_fll.reset(); m_fll.reset();
@ -399,11 +426,32 @@ void FreqTracker::configureChannelizer()
if (m_guiMessageQueue) if (m_guiMessageQueue)
{ {
MsgSampleRateNotification *msg = MsgSampleRateNotification::create(m_deviceSampleRate / (1<<m_settings.m_log2Decim)); MsgSampleRateNotification *msg = MsgSampleRateNotification::create(
m_deviceSampleRate / (1<<m_settings.m_log2Decim),
m_settings.m_inputFrequencyOffset);
m_guiMessageQueue->push(msg); m_guiMessageQueue->push(msg);
} }
} }
void FreqTracker::connectTimer()
{
if (!m_timerConnected)
{
m_tickCount = 0;
connect(m_timer, SIGNAL(timeout()), this, SLOT(tick()));
m_timerConnected = true;
}
}
void FreqTracker::disconnectTimer()
{
if (m_timerConnected)
{
disconnect(m_timer, SIGNAL(timeout()), this, SLOT(tick()));
m_timerConnected = false;
}
}
QByteArray FreqTracker::serialize() const QByteArray FreqTracker::serialize() const
{ {
return m_settings.serialize(); return m_settings.serialize();
@ -631,3 +679,38 @@ void FreqTracker::networkManagerFinished(QNetworkReply *reply)
answer.chop(1); // remove last \n answer.chop(1); // remove last \n
qDebug("FreqTracker::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); qDebug("FreqTracker::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
} }
void FreqTracker::tick()
{
if (getSquelchOpen() && (m_settings.m_trackerType != FreqTrackerSettings::TrackerNone)) {
m_avgDeltaFreq = 0.1*getFrequency() + 0.9*m_avgDeltaFreq;
}
if (m_tickCount < 19)
{
m_tickCount++;
}
else
{
if (getSquelchOpen() && (m_settings.m_trackerType != FreqTrackerSettings::TrackerNone))
{
int decayAmount = m_channelSampleRate < 100 ? 1 : m_channelSampleRate / 100;
if (m_lastCorrAbs < decayAmount)
{
FreqTrackerSettings settings = m_settings;
settings.m_inputFrequencyOffset += m_avgDeltaFreq;
m_lastCorrAbs = m_avgDeltaFreq < 0 ? m_avgDeltaFreq : m_avgDeltaFreq;
applySettings(settings);
}
else
{
if (m_lastCorrAbs >= decayAmount) {
m_lastCorrAbs -= decayAmount;
}
}
}
m_tickCount = 0;
}
}

View File

@ -43,6 +43,7 @@ class QNetworkReply;
class DeviceSourceAPI; class DeviceSourceAPI;
class DownChannelizer; class DownChannelizer;
class ThreadedBasebandSampleSink; class ThreadedBasebandSampleSink;
class QTimer;
class fftfilt; class fftfilt;
class FreqTracker : public BasebandSampleSink, public ChannelSinkAPI { class FreqTracker : public BasebandSampleSink, public ChannelSinkAPI {
@ -98,20 +99,22 @@ public:
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
static MsgSampleRateNotification* create(int sampleRate) { static MsgSampleRateNotification* create(int sampleRate, int frequencyOffset) {
return new MsgSampleRateNotification(sampleRate); return new MsgSampleRateNotification(sampleRate, frequencyOffset);
} }
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
int getFrequencyOffset() const { return m_frequencyOffset; }
private: private:
MsgSampleRateNotification(int sampleRate, int frequencyOffset) :
MsgSampleRateNotification(int sampleRate) :
Message(), Message(),
m_sampleRate(sampleRate) m_sampleRate(sampleRate),
m_frequencyOffset(frequencyOffset)
{ } { }
int m_sampleRate; int m_sampleRate;
int m_frequencyOffset;
}; };
FreqTracker(DeviceSourceAPI *deviceAPI); FreqTracker(DeviceSourceAPI *deviceAPI);
@ -149,6 +152,7 @@ public:
bool getSquelchOpen() const { return m_squelchOpen; } bool getSquelchOpen() const { return m_squelchOpen; }
bool getPllLocked() const { return (m_settings.m_trackerType == FreqTrackerSettings::TrackerPLL) && m_pll.locked(); } bool getPllLocked() const { return (m_settings.m_trackerType == FreqTrackerSettings::TrackerPLL) && m_pll.locked(); }
Real getFrequency() const; Real getFrequency() const;
Real getAvgDeltaFreq() const { return m_avgDeltaFreq; }
void getMagSqLevels(double& avg, double& peak, int& nbSamples) void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{ {
@ -222,12 +226,19 @@ private:
QNetworkAccessManager *m_networkManager; QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest; QNetworkRequest m_networkRequest;
const QTimer *m_timer;
bool m_timerConnected;
uint32_t m_tickCount;
int m_lastCorrAbs;
Real m_avgDeltaFreq;
QMutex m_settingsMutex; QMutex m_settingsMutex;
void applySettings(const FreqTrackerSettings& settings, bool force = false); void applySettings(const FreqTrackerSettings& settings, bool force = false);
void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false); void applyChannelSettings(int inputSampleRate, int inputFrequencyOffset, bool force = false);
void setInterpolator(); void setInterpolator();
void configureChannelizer(); void configureChannelizer();
void connectTimer();
void disconnectTimer();
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const FreqTrackerSettings& settings); void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const FreqTrackerSettings& settings);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreqTrackerSettings& settings, bool force); void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreqTrackerSettings& settings, bool force);
@ -236,7 +247,7 @@ private:
private slots: private slots:
void networkManagerFinished(QNetworkReply *reply); void networkManagerFinished(QNetworkReply *reply);
void tick();
}; };
#endif // INCLUDE_FREQTRACKER_H #endif // INCLUDE_FREQTRACKER_H

View File

@ -111,6 +111,11 @@ bool FreqTrackerGUI::handleMessage(const Message& message)
const FreqTracker::MsgSampleRateNotification& cfg = (FreqTracker::MsgSampleRateNotification&) message; const FreqTracker::MsgSampleRateNotification& cfg = (FreqTracker::MsgSampleRateNotification&) message;
m_channelSampleRate = cfg.getSampleRate(); m_channelSampleRate = cfg.getSampleRate();
ui->channelSampleRateText->setText(tr("%1k").arg(QString::number(m_channelSampleRate / 1000.0f, 'g', 5))); ui->channelSampleRateText->setText(tr("%1k").arg(QString::number(m_channelSampleRate / 1000.0f, 'g', 5)));
blockApplySettings(true);
m_settings.m_inputFrequencyOffset = cfg.getFrequencyOffset();
ui->deltaFrequency->setValue(m_settings.m_inputFrequencyOffset);
m_channelMarker.setCenterFrequency(cfg.getFrequencyOffset());
blockApplySettings(false);
if (m_channelSampleRate > 1000) { if (m_channelSampleRate > 1000) {
ui->rfBW->setMaximum(m_channelSampleRate/100); ui->rfBW->setMaximum(m_channelSampleRate/100);
@ -396,7 +401,7 @@ void FreqTrackerGUI::tick()
ui->tracking->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); ui->tracking->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
} }
int freq = m_freqTracker->getFrequency(); int freq = m_freqTracker->getAvgDeltaFreq();
QLocale loc; QLocale loc;
ui->trackingFrequencyText->setText(tr("%1 Hz").arg(loc.toString(freq))); ui->trackingFrequencyText->setText(tr("%1 Hz").arg(loc.toString(freq)));

View File

@ -153,9 +153,9 @@ bool DownChannelizer::handleMessage(const Message& cmd)
m_requestedOutputSampleRate = chan.getSampleRate(); m_requestedOutputSampleRate = chan.getSampleRate();
m_requestedCenterFrequency = chan.getCenterFrequency(); m_requestedCenterFrequency = chan.getCenterFrequency();
qDebug() << "DownChannelizer::handleMessage: DSPConfigureChannelizer:" // qDebug() << "DownChannelizer::handleMessage: DSPConfigureChannelizer:"
<< " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate // << " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate
<< " m_requestedCenterFrequency: " << m_requestedCenterFrequency; // << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
applyConfiguration(); applyConfiguration();
@ -309,12 +309,12 @@ Real DownChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanSta
Real sigBw = sigEnd - sigStart; Real sigBw = sigEnd - sigStart;
Real rot = sigBw / 4; Real rot = sigBw / 4;
qDebug("DownChannelizer::createFilterChain: Signal [%.1f, %.1f] (BW %.1f), Channel [%.1f, %.1f], Rot %.1f", sigStart, sigEnd, sigBw, chanStart, chanEnd, rot); //qDebug("DownChannelizer::createFilterChain: Signal [%.1f, %.1f] (BW %.1f), Channel [%.1f, %.1f], Rot %.1f", sigStart, sigEnd, sigBw, chanStart, chanEnd, rot);
// check if it fits into the left half // check if it fits into the left half
if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd)) if(signalContainsChannel(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd))
{ {
qDebug("DownChannelizer::createFilterChain: -> take left half (rotate by +1/4 and decimate by 2)"); //qDebug("DownChannelizer::createFilterChain: -> take left half (rotate by +1/4 and decimate by 2)");
m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf)); m_filterStages.push_back(new FilterStage(FilterStage::ModeLowerHalf));
return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd); return createFilterChain(sigStart, sigStart + sigBw / 2.0, chanStart, chanEnd);
} }
@ -322,7 +322,7 @@ Real DownChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanSta
// check if it fits into the right half // check if it fits into the right half
if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd)) if(signalContainsChannel(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd))
{ {
qDebug("DownChannelizer::createFilterChain: -> take right half (rotate by -1/4 and decimate by 2)"); //qDebug("DownChannelizer::createFilterChain: -> take right half (rotate by -1/4 and decimate by 2)");
m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf)); m_filterStages.push_back(new FilterStage(FilterStage::ModeUpperHalf));
return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd); return createFilterChain(sigEnd - sigBw / 2.0f, sigEnd, chanStart, chanEnd);
} }
@ -330,13 +330,13 @@ Real DownChannelizer::createFilterChain(Real sigStart, Real sigEnd, Real chanSta
// check if it fits into the center // check if it fits into the center
if(signalContainsChannel(sigStart + rot, sigEnd - rot, chanStart, chanEnd)) if(signalContainsChannel(sigStart + rot, sigEnd - rot, chanStart, chanEnd))
{ {
qDebug("DownChannelizer::createFilterChain: -> take center half (decimate by 2)"); //qDebug("DownChannelizer::createFilterChain: -> take center half (decimate by 2)");
m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter)); m_filterStages.push_back(new FilterStage(FilterStage::ModeCenter));
return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd); return createFilterChain(sigStart + rot, sigEnd - rot, chanStart, chanEnd);
} }
Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart); Real ofs = ((chanEnd - chanStart) / 2.0 + chanStart) - ((sigEnd - sigStart) / 2.0 + sigStart);
qDebug("DownChannelizer::createFilterChain: -> complete (final BW %.1f, frequency offset %.1f)", sigBw, ofs); //qDebug("DownChannelizer::createFilterChain: -> complete (final BW %.1f, frequency offset %.1f)", sigBw, ofs);
return ofs; return ofs;
} }