diff --git a/plugins/channelrx/chanalyzerng/chanalyzerng.cpp b/plugins/channelrx/chanalyzerng/chanalyzerng.cpp index 63994c9c0..546985628 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzerng.cpp +++ b/plugins/channelrx/chanalyzerng/chanalyzerng.cpp @@ -197,8 +197,6 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd) } } - - void ChannelAnalyzerNG::apply(bool force) { if ((m_running.m_frequency != m_config.m_frequency) || @@ -253,6 +251,12 @@ void ChannelAnalyzerNG::apply(bool force) m_settingsMutex.unlock(); } + if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) || + (m_running.m_spanLog2 != m_config.m_spanLog2) || force) + { + m_pll.setSampleRate(m_running.m_channelSampleRate / (1<. // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_CHANALYZERNG_H -#define INCLUDE_CHANALYZERNG_H - -#include -#include - -#include "dsp/basebandsamplesink.h" -#include "channel/channelsinkapi.h" -#include "dsp/interpolator.h" -#include "dsp/ncof.h" -#include "dsp/fftfilt.h" -#include "dsp/phaselockcomplex.h" -#include "audio/audiofifo.h" -#include "util/message.h" - -#define ssbFftLen 1024 - -class DeviceSourceAPI; -class ThreadedBasebandSampleSink; -class DownChannelizer; - -class ChannelAnalyzerNG : public BasebandSampleSink, public ChannelSinkAPI { -public: - class MsgConfigureChannelAnalyzer : public Message { - MESSAGE_CLASS_DECLARATION - - public: - int getChannelSampleRate() const { return m_channelSampleRate; } - Real getBandwidth() const { return m_Bandwidth; } - Real getLoCutoff() const { return m_LowCutoff; } - int getSpanLog2() const { return m_spanLog2; } - bool getSSB() const { return m_ssb; } - bool getPLL() const { return m_pll; } - unsigned int getPLLPSKOrder() const { return m_pllPskOrder; } - - static MsgConfigureChannelAnalyzer* create( - int channelSampleRate, - Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb, - bool pll, - unsigned int pllPskOrder) - { - return new MsgConfigureChannelAnalyzer( - channelSampleRate, - Bandwidth, - LowCutoff, - spanLog2, - ssb, - pll, - pllPskOrder); - } - - private: - int m_channelSampleRate; - Real m_Bandwidth; - Real m_LowCutoff; - int m_spanLog2; - bool m_ssb; - bool m_pll; - unsigned int m_pllPskOrder; - - MsgConfigureChannelAnalyzer( - int channelSampleRate, - Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb, - bool pll, - unsigned int pllPskOrder) : - Message(), - m_channelSampleRate(channelSampleRate), - m_Bandwidth(Bandwidth), - m_LowCutoff(LowCutoff), - m_spanLog2(spanLog2), - m_ssb(ssb), - m_pll(pll), - m_pllPskOrder(pllPskOrder) - { } - }; - - class MsgConfigureChannelizer : public Message { - MESSAGE_CLASS_DECLARATION - - public: - int getSampleRate() const { return m_sampleRate; } - int getCenterFrequency() const { return m_centerFrequency; } - - static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) - { - return new MsgConfigureChannelizer(sampleRate, centerFrequency); - } - - private: - int m_sampleRate; - int m_centerFrequency; - - MsgConfigureChannelizer(int sampleRate, int centerFrequency) : - Message(), - m_sampleRate(sampleRate), - m_centerFrequency(centerFrequency) - { } - }; - - class MsgReportChannelSampleRateChanged : public Message { - MESSAGE_CLASS_DECLARATION - - public: - - static MsgReportChannelSampleRateChanged* create() - { - return new MsgReportChannelSampleRateChanged(); - } - - private: - - MsgReportChannelSampleRateChanged() : - Message() - { } - }; - - ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI); - virtual ~ChannelAnalyzerNG(); - virtual void destroy() { delete this; } - void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } - - void configure(MessageQueue* messageQueue, - int channelSampleRate, - Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb, - bool pll, - unsigned int pllPskOrder); - - DownChannelizer *getChannelizer() { return m_channelizer; } - int getInputSampleRate() const { return m_running.m_inputSampleRate; } - int getChannelSampleRate() const { return m_running.m_channelSampleRate; } - double getMagSq() const { return m_magsq; } - bool isPllLocked() const { return m_running.m_pll && m_pll.locked(); } - Real getPllFrequency() const { return m_pll.getFrequency(); } - Real getPllDeltaPhase() const { return m_pll.getDeltaPhi(); } - Real getPllPhase() const { return m_pll.getPhiHat(); } - - virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); - virtual void start(); - virtual void stop(); - virtual bool handleMessage(const Message& cmd); - - virtual void getIdentifier(QString& id) { id = objectName(); } - virtual void getTitle(QString& title) { title = objectName(); } - virtual qint64 getCenterFrequency() const { return m_running.m_frequency; } - - virtual QByteArray serialize() const { return QByteArray(); } - virtual bool deserialize(const QByteArray& data __attribute__((unused))) { return false; } - - static const QString m_channelIdURI; - static const QString m_channelId; - -private: - - struct Config - { - int m_frequency; - int m_inputSampleRate; - int m_channelSampleRate; - Real m_Bandwidth; - Real m_LowCutoff; - int m_spanLog2; - bool m_ssb; - bool m_pll; - unsigned int m_pllPskOrder; - - Config() : - m_frequency(0), - m_inputSampleRate(96000), - m_channelSampleRate(96000), - m_Bandwidth(5000), - m_LowCutoff(300), - m_spanLog2(3), - m_ssb(false), - m_pll(false), - m_pllPskOrder(1) - {} - }; - - Config m_config; - Config m_running; - - DeviceSourceAPI *m_deviceAPI; - ThreadedBasebandSampleSink* m_threadedChannelizer; - DownChannelizer* m_channelizer; - - int m_undersampleCount; - fftfilt::cmplx m_sum; - bool m_usb; - double m_magsq; - bool m_useInterpolator; - - NCOF m_nco; - PhaseLockComplex m_pll; - Interpolator m_interpolator; - Real m_interpolatorDistance; - Real m_interpolatorDistanceRemain; - - fftfilt* SSBFilter; - fftfilt* DSBFilter; - - BasebandSampleSink* m_sampleSink; - SampleVector m_sampleBuffer; - QMutex m_settingsMutex; - - void apply(bool force = false); - - void processOneSample(Complex& c, fftfilt::cmplx *sideband) - { - int n_out; - int decim = 1<runSSB(c, &sideband, m_usb); - } - else - { - n_out = DSBFilter->runDSB(c, &sideband); - } - - for (int i = 0; i < n_out; i++) - { - // Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display - // smart decimation with bit gain using float arithmetic (23 bits significand) - - m_sum += sideband[i]; - - if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1) - { - m_sum /= decim; - Real re = m_sum.real() / SDR_RX_SCALED; - Real im = m_sum.imag() / SDR_RX_SCALED; - m_magsq = re*re + im*im; - - if (m_running.m_pll) - { - m_pll.feed(re, im); - - // Use -fPLL to mix (exchange PLL real and image in the complex multiplication) - // Real mixI = m_sum.real() * m_pll.getImag() - m_sum.imag() * m_pll.getReal(); - // Real mixQ = m_sum.real() * m_pll.getReal() + m_sum.imag() * m_pll.getImag(); - Real mixI = m_pll.getReal() * SDR_RX_SCALED; - Real mixQ = m_pll.getImag() * SDR_RX_SCALED; - - if (m_running.m_ssb & !m_usb) - { // invert spectrum for LSB - m_sampleBuffer.push_back(Sample(mixQ, mixI)); - } - else - { - m_sampleBuffer.push_back(Sample(mixI, mixQ)); - } - } - else - { - if (m_running.m_ssb & !m_usb) - { // invert spectrum for LSB - m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real())); - } - else - { - m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag())); - } - } - - m_sum = 0; - } - } - } -}; - -#endif // INCLUDE_CHANALYZERNG_H +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// // +// 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 // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_CHANALYZERNG_H +#define INCLUDE_CHANALYZERNG_H + +#include +#include + +#include "dsp/basebandsamplesink.h" +#include "channel/channelsinkapi.h" +#include "dsp/interpolator.h" +#include "dsp/ncof.h" +#include "dsp/fftfilt.h" +#include "dsp/phaselockcomplex.h" +#include "audio/audiofifo.h" +#include "util/message.h" + +#define ssbFftLen 1024 + +class DeviceSourceAPI; +class ThreadedBasebandSampleSink; +class DownChannelizer; + +class ChannelAnalyzerNG : public BasebandSampleSink, public ChannelSinkAPI { +public: + class MsgConfigureChannelAnalyzer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getChannelSampleRate() const { return m_channelSampleRate; } + Real getBandwidth() const { return m_Bandwidth; } + Real getLoCutoff() const { return m_LowCutoff; } + int getSpanLog2() const { return m_spanLog2; } + bool getSSB() const { return m_ssb; } + bool getPLL() const { return m_pll; } + unsigned int getPLLPSKOrder() const { return m_pllPskOrder; } + + static MsgConfigureChannelAnalyzer* create( + int channelSampleRate, + Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb, + bool pll, + unsigned int pllPskOrder) + { + return new MsgConfigureChannelAnalyzer( + channelSampleRate, + Bandwidth, + LowCutoff, + spanLog2, + ssb, + pll, + pllPskOrder); + } + + private: + int m_channelSampleRate; + Real m_Bandwidth; + Real m_LowCutoff; + int m_spanLog2; + bool m_ssb; + bool m_pll; + unsigned int m_pllPskOrder; + + MsgConfigureChannelAnalyzer( + int channelSampleRate, + Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb, + bool pll, + unsigned int pllPskOrder) : + Message(), + m_channelSampleRate(channelSampleRate), + m_Bandwidth(Bandwidth), + m_LowCutoff(LowCutoff), + m_spanLog2(spanLog2), + m_ssb(ssb), + m_pll(pll), + m_pllPskOrder(pllPskOrder) + { } + }; + + class MsgConfigureChannelizer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + int getCenterFrequency() const { return m_centerFrequency; } + + static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) + { + return new MsgConfigureChannelizer(sampleRate, centerFrequency); + } + + private: + int m_sampleRate; + int m_centerFrequency; + + MsgConfigureChannelizer(int sampleRate, int centerFrequency) : + Message(), + m_sampleRate(sampleRate), + m_centerFrequency(centerFrequency) + { } + }; + + class MsgReportChannelSampleRateChanged : public Message { + MESSAGE_CLASS_DECLARATION + + public: + + static MsgReportChannelSampleRateChanged* create() + { + return new MsgReportChannelSampleRateChanged(); + } + + private: + + MsgReportChannelSampleRateChanged() : + Message() + { } + }; + + ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI); + virtual ~ChannelAnalyzerNG(); + virtual void destroy() { delete this; } + void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } + + void configure(MessageQueue* messageQueue, + int channelSampleRate, + Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb, + bool pll, + unsigned int pllPskOrder); + + DownChannelizer *getChannelizer() { return m_channelizer; } + int getInputSampleRate() const { return m_running.m_inputSampleRate; } + int getChannelSampleRate() const { return m_running.m_channelSampleRate; } + double getMagSq() const { return m_magsq; } + bool isPllLocked() const { return m_running.m_pll && m_pll.locked(); } + Real getPllDeltaPhase() const { return m_pll.getDeltaPhi(); } + Real getPllPhase() const { return m_pll.getPhiHat(); } + + virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); + virtual void start(); + virtual void stop(); + virtual bool handleMessage(const Message& cmd); + + virtual void getIdentifier(QString& id) { id = objectName(); } + virtual void getTitle(QString& title) { title = objectName(); } + virtual qint64 getCenterFrequency() const { return m_running.m_frequency; } + + virtual QByteArray serialize() const { return QByteArray(); } + virtual bool deserialize(const QByteArray& data __attribute__((unused))) { return false; } + + static const QString m_channelIdURI; + static const QString m_channelId; + +private: + + struct Config + { + int m_frequency; + int m_inputSampleRate; + int m_channelSampleRate; + Real m_Bandwidth; + Real m_LowCutoff; + int m_spanLog2; + bool m_ssb; + bool m_pll; + unsigned int m_pllPskOrder; + + Config() : + m_frequency(0), + m_inputSampleRate(96000), + m_channelSampleRate(96000), + m_Bandwidth(5000), + m_LowCutoff(300), + m_spanLog2(3), + m_ssb(false), + m_pll(false), + m_pllPskOrder(1) + {} + }; + + Config m_config; + Config m_running; + + DeviceSourceAPI *m_deviceAPI; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; + + int m_undersampleCount; + fftfilt::cmplx m_sum; + bool m_usb; + double m_magsq; + bool m_useInterpolator; + + NCOF m_nco; + PhaseLockComplex m_pll; + Interpolator m_interpolator; + Real m_interpolatorDistance; + Real m_interpolatorDistanceRemain; + + fftfilt* SSBFilter; + fftfilt* DSBFilter; + + BasebandSampleSink* m_sampleSink; + SampleVector m_sampleBuffer; + QMutex m_settingsMutex; + + void apply(bool force = false); + + void processOneSample(Complex& c, fftfilt::cmplx *sideband) + { + int n_out; + int decim = 1<runSSB(c, &sideband, m_usb); + } + else + { + n_out = DSBFilter->runDSB(c, &sideband); + } + + for (int i = 0; i < n_out; i++) + { + // Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display + // smart decimation with bit gain using float arithmetic (23 bits significand) + + m_sum += sideband[i]; + + if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1) + { + m_sum /= decim; + Real re = m_sum.real() / SDR_RX_SCALED; + Real im = m_sum.imag() / SDR_RX_SCALED; + m_magsq = re*re + im*im; + + if (m_running.m_pll) + { + m_pll.feed(re, im); + + // Use -fPLL to mix (exchange PLL real and image in the complex multiplication) + Real mixI = m_sum.real() * m_pll.getImag() - m_sum.imag() * m_pll.getReal(); + Real mixQ = m_sum.real() * m_pll.getReal() + m_sum.imag() * m_pll.getImag(); +// Real mixI = m_pll.getReal() * SDR_RX_SCALED; +// Real mixQ = m_pll.getImag() * SDR_RX_SCALED; + + if (m_running.m_ssb & !m_usb) + { // invert spectrum for LSB + m_sampleBuffer.push_back(Sample(mixQ, mixI)); + } + else + { + m_sampleBuffer.push_back(Sample(mixI, mixQ)); + } + } + else + { + if (m_running.m_ssb & !m_usb) + { // invert spectrum for LSB + m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real())); + } + else + { + m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag())); + } + } + + m_sum = 0; + } + } + } +}; + +#endif // INCLUDE_CHANALYZERNG_H diff --git a/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp b/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp index afc23019b..e8a862580 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp +++ b/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp @@ -237,15 +237,6 @@ void ChannelAnalyzerNGGUI::tick() } else { ui->pll->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); } - - if (ui->pll->isChecked()) - { - int fHz = round(m_channelAnalyzer->getPllFrequency()*m_rate); - ui->pll->setToolTip(tr("PLL lock (f:%1 Hz e:%2 rad p:%3 rad)") - .arg(fHz) - .arg(m_channelAnalyzer->getPllDeltaPhase()) - .arg(m_channelAnalyzer->getPllPhase())); - } } void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value) @@ -262,10 +253,6 @@ void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value) void ChannelAnalyzerNGGUI::on_pll_toggled(bool checked) { - if (!checked && m_usePll) { - ui->pll->setToolTip("PLL lock"); - } - m_usePll = checked; applySettings(); } diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 4a9611666..e81436311 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -82,7 +82,7 @@ AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) : m_deviceAPI->addThreadedSink(m_threadedChannelizer); m_deviceAPI->addChannelAPI(this); - m_pllFilt.create(101, m_audioSampleRate, 500.0); + m_pllFilt.create(101, m_audioSampleRate, 200.0); m_pll.computeCoefficients(0.05, 0.707, 1000); m_syncAMBuffIndex = 0; } @@ -374,7 +374,7 @@ void AMDemod::applyAudioSampleRate(int sampleRate) m_audioFifo.setSize(sampleRate); m_squelchDelayLine.resize(sampleRate/5); DSBFilter->create_dsb_filter((2.0f * m_settings.m_rfBandwidth) / (float) sampleRate); - m_pllFilt.create(101, sampleRate, 500.0); + m_pllFilt.create(101, sampleRate, 200.0); if (m_settings.m_pll) { m_volumeAGC.resizeNew(sampleRate, 0.003); @@ -383,6 +383,7 @@ void AMDemod::applyAudioSampleRate(int sampleRate) } m_syncAMAGC.resize(sampleRate/4, sampleRate/8, 0.1); + m_pll.setSampleRate(sampleRate); m_settingsMutex.unlock(); m_audioSampleRate = sampleRate; diff --git a/sdrbase/dsp/phaselockcomplex.cpp b/sdrbase/dsp/phaselockcomplex.cpp index c3440c0f2..b9d2fe255 100644 --- a/sdrbase/dsp/phaselockcomplex.cpp +++ b/sdrbase/dsp/phaselockcomplex.cpp @@ -44,9 +44,14 @@ PhaseLockComplex::PhaseLockComplex() : m_yRe(1.0), m_yIm(0.0), m_freq(0.0), + m_freqPrev(0.0), m_lock(0.0), m_lockCount(0), - m_pskOrder(1) + m_pskOrder(1), + m_lockTime1(480), + m_lockTime(2400), + m_lockTimef(2400.0f), + m_lockThreshold(4.8f) { } @@ -83,6 +88,16 @@ void PhaseLockComplex::computeCoefficients(Real wn, Real zeta, Real K) void PhaseLockComplex::setPskOrder(unsigned int order) { m_pskOrder = order > 0 ? order : 1; + reset(); +} + +void PhaseLockComplex::setSampleRate(unsigned int sampleRate) +{ + m_lockTime1 = sampleRate / 100; // 10ms for order 1 + m_lockTime = sampleRate / 20; // 50ms for order > 1 + m_lockTimef = (float) m_lockTime; + m_lockThreshold = m_lockTime * 0.002f; // threshold of 0.002 taking division by lock time into account + reset(); } void PhaseLockComplex::reset() @@ -103,6 +118,7 @@ void PhaseLockComplex::reset() m_yRe = 1.0f; m_yIm = 0.0f; m_freq = 0.0f; + m_freqPrev = 0.0f; m_lock = 0.0f; m_lockCount = 0; } @@ -148,40 +164,69 @@ void PhaseLockComplex::feed(float re, float im) m_phiHat += 2.0*M_PI; } - float dPhi = normalizeAngle(m_phiHat - m_phiHatPrev); - m_phiHatPrev = m_phiHat; - - if (m_phiHatCount < 9) + // lock estimation + if (m_pskOrder > 1) { - m_dPhiHatAccum += dPhi; + float dPhi = normalizeAngle(m_phiHat - m_phiHatPrev); + + if (m_phiHatCount < (m_lockTime-1)) + { + m_dPhiHatAccum += dPhi; // re-accumulate phase for differential calculation + m_phiHatCount++; + } + else + { + float dPhi11 = (m_dPhiHatAccum - m_phiHat1); // optimized out division by lock time + float dPhi12 = (m_phiHat1 - m_phiHat2); + m_lock = dPhi11 - dPhi12; // second derivative of phase to get lock status + + if ((m_lock > -m_lockThreshold) && (m_lock < m_lockThreshold)) // includes re-multiplication by lock time + { + if (m_lockCount < 20) { // [0..20] + m_lockCount++; + } + } + else + { + if (m_lockCount > 0) { + m_lockCount -= 2; + } + } + + m_phiHat2 = m_phiHat1; + m_phiHat1 = m_dPhiHatAccum; + m_dPhiHatAccum = 0.0f; + m_phiHatCount = 0; + } + + m_phiHatPrev = m_phiHat; } else { - float dPhi1 = (m_phiHat1 - m_dPhiHatAccum) / 10.0f; - float dPhi1Prev = (m_phiHat2 - m_phiHat1) / 10.0f; - m_lock = dPhi1 - dPhi1Prev; // second derivative of phase + m_freq = (m_phiHat - m_phiHatPrev) / (2.0*M_PI); - if ((m_lock > -0.01) && (m_lock < 0.01)) + if (m_freq < -1.0f) { + m_freq += 2.0f; + } else if (m_freq > 1.0f) { + m_freq -= 2.0f; + } + + float dFreq = m_freq - m_freqPrev; + + if ((dFreq > -0.01) && (dFreq < 0.01)) { - if (m_lockCount < 1000) { + if (m_lockCount < (m_lockTime1-1)) { // [0..479] m_lockCount++; } } else { - if (m_lockCount > 0) { - m_lockCount--; - } + m_lockCount = 0; } - m_freq = dPhi1 / 2.0*M_PI; // first derivative of phase - m_phiHat2 = m_phiHat1; - m_phiHat1 = m_dPhiHatAccum; - m_dPhiHatAccum = 0.0f; - m_phiHatCount = 0; + m_phiHatPrev = m_phiHat; + m_freqPrev = m_freq; } - - m_dPhiHatAccum += dPhi; } float PhaseLockComplex::normalizeAngle(float angle) diff --git a/sdrbase/dsp/phaselockcomplex.h b/sdrbase/dsp/phaselockcomplex.h index 675c12bb8..340d83dec 100644 --- a/sdrbase/dsp/phaselockcomplex.h +++ b/sdrbase/dsp/phaselockcomplex.h @@ -41,13 +41,14 @@ public: * \param order 0,1: no PSK (CW), 2: BPSK, 4: QPSK, 8: 8-PSK, ... use powers of two for real cases */ void setPskOrder(unsigned int order); + /** Set sample rate information only for frequency and lock condition calculation */ + void setSampleRate(unsigned int sampleRate); void reset(); void feed(float re, float im); const std::complex& getComplex() const { return m_y; } float getReal() const { return m_yRe; } float getImag() const { return m_yIm; } - bool locked() const { return m_lockCount > 500; } - float getFrequency() const { return m_freq; } + bool locked() const { return m_lockCount > (m_pskOrder > 1 ? 15 : (m_lockTime1-2)); } // 6 float getDeltaPhi() const { return m_deltaPhi; } float getPhiHat() const { return m_phiHat; } @@ -75,9 +76,14 @@ private: float m_yRe; float m_yIm; float m_freq; + float m_freqPrev; float m_lock; int m_lockCount; unsigned int m_pskOrder; + int m_lockTime1; + int m_lockTime; + float m_lockTimef; + float m_lockThreshold; };