mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 10:05:46 -05:00
Frequency tracker (4)
This commit is contained in:
parent
e1662d2f4e
commit
459063d4f2
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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)));
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user