kopia lustrzana https://github.com/f4exb/sdrangel
PLL cleanup
rodzic
ea5cdb034f
commit
2f8fda7137
|
@ -65,20 +65,13 @@ public:
|
||||||
void process(const std::vector<Real>& samples_in, std::vector<Real>& samples_out);
|
void process(const std::vector<Real>& samples_in, std::vector<Real>& samples_out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process samples and extract pilot tone. Generate phase-locked twice
|
* Process samples and track a pilot tone. Generate samples for single or multiple phase-locked
|
||||||
* the frequency tone with unit amplitude. Mostly useful for 19 kHz stereo
|
|
||||||
* pilot tone on broadcast FM.
|
|
||||||
* In flow version
|
|
||||||
*/
|
|
||||||
void process(const Real& sample_in, Real& sample_out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process samples and track a pilot tone. Generate samples for multiple phase-locked
|
|
||||||
* signals. Implement the processPhase virtual method to produce the output samples.
|
* signals. Implement the processPhase virtual method to produce the output samples.
|
||||||
* In flow version. Ex: Use 19 kHz stereo pilot tone to generate 38 kHz (stereo) and 57 kHz
|
* In flow version. Ex: Use 19 kHz stereo pilot tone to generate 38 kHz (stereo) and 57 kHz
|
||||||
* pilots (see RDSPhaseLock class below).
|
* pilots (see RDSPhaseLock class below).
|
||||||
|
* This is the in flow version
|
||||||
*/
|
*/
|
||||||
void process(const Real& sample_in, std::vector<Real>& samples_out);
|
void process(const Real& sample_in, Real *samples_out);
|
||||||
|
|
||||||
/** Return true if the phase-locked loop is locked. */
|
/** Return true if the phase-locked loop is locked. */
|
||||||
bool locked() const
|
bool locked() const
|
||||||
|
@ -100,7 +93,7 @@ protected:
|
||||||
* Callback method to produce multiple outputs from the current phase value in m_phase
|
* Callback method to produce multiple outputs from the current phase value in m_phase
|
||||||
* and/or the sin and cos values in m_psin and m_pcos
|
* and/or the sin and cos values in m_psin and m_pcos
|
||||||
*/
|
*/
|
||||||
virtual void processPhase(std::vector<Real>& samples_out) const {};
|
virtual void processPhase(Real *samples_out) const {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Real m_minfreq, m_maxfreq;
|
Real m_minfreq, m_maxfreq;
|
||||||
|
@ -132,7 +125,7 @@ public:
|
||||||
{}
|
{}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void processPhase(std::vector<Real>& samples_out) const
|
virtual void processPhase(Real *samples_out) const
|
||||||
{
|
{
|
||||||
samples_out[0] = m_psin; // f Pilot
|
samples_out[0] = m_psin; // f Pilot
|
||||||
// Generate double-frequency output.
|
// Generate double-frequency output.
|
||||||
|
@ -153,7 +146,7 @@ public:
|
||||||
{}
|
{}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void processPhase(std::vector<Real>& samples_out) const
|
virtual void processPhase(Real *samples_out) const
|
||||||
{
|
{
|
||||||
samples_out[0] = m_psin; // f Pilot
|
samples_out[0] = m_psin; // f Pilot
|
||||||
// Generate double-frequency output.
|
// Generate double-frequency output.
|
||||||
|
|
|
@ -126,11 +126,12 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
|
||||||
|
|
||||||
if (m_running.m_audioStereo)
|
if (m_running.m_audioStereo)
|
||||||
{
|
{
|
||||||
Real pilotSample;
|
//Real pilotSample;
|
||||||
m_pilotPLL.process(demod, pilotSample);
|
//m_pilotPLL.process(demod, pilotSample);
|
||||||
|
m_pilotPLL.process(demod, m_pilotPLLSamples);
|
||||||
//m_sampleBuffer.push_back(Sample(pilotSample * (1<<15), 0.0)); // debug pilot
|
//m_sampleBuffer.push_back(Sample(pilotSample * (1<<15), 0.0)); // debug pilot
|
||||||
|
|
||||||
Complex s(demod*2.0*pilotSample, 0);
|
Complex s(demod*2.0*m_pilotPLLSamples[1], 0);
|
||||||
|
|
||||||
if (m_interpolatorStereo.interpolate(&m_interpolatorStereoDistanceRemain, s, &cs))
|
if (m_interpolatorStereo.interpolate(&m_interpolatorStereoDistanceRemain, s, &cs))
|
||||||
{
|
{
|
||||||
|
|
|
@ -144,7 +144,8 @@ private:
|
||||||
SampleVector m_sampleBuffer;
|
SampleVector m_sampleBuffer;
|
||||||
QMutex m_settingsMutex;
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
PhaseLock m_pilotPLL;
|
StereoPhaseLock m_pilotPLL;
|
||||||
|
Real m_pilotPLLSamples[2];
|
||||||
|
|
||||||
void apply();
|
void apply();
|
||||||
};
|
};
|
||||||
|
|
|
@ -263,125 +263,8 @@ void PhaseLock::process(const Real& sample_in, Real& sample_out)
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
// Process samples.
|
|
||||||
void PhaseLock::process(const Real& sample_in, Real& sample_out)
|
|
||||||
{
|
|
||||||
bool was_locked = (m_lock_cnt >= m_lock_delay);
|
|
||||||
m_pps_events.clear();
|
|
||||||
|
|
||||||
//if (n > 0) m_pilot_level = 1000.0;
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
// Generate locked pilot tone.
|
|
||||||
Real psin = sin(m_phase);
|
|
||||||
Real pcos = cos(m_phase);
|
|
||||||
|
|
||||||
// Generate double-frequency output.
|
|
||||||
// sin(2*x) = 2 * sin(x) * cos(x)
|
|
||||||
sample_out = 2 * psin * pcos;
|
|
||||||
|
|
||||||
// Multiply locked tone with input.
|
|
||||||
Real x = sample_in;
|
|
||||||
Real phasor_i = psin * x;
|
|
||||||
Real phasor_q = pcos * x;
|
|
||||||
|
|
||||||
// Run IQ phase error through low-pass filter.
|
|
||||||
phasor_i = m_phasor_b0 * phasor_i
|
|
||||||
- m_phasor_a1 * m_phasor_i1
|
|
||||||
- m_phasor_a2 * m_phasor_i2;
|
|
||||||
phasor_q = m_phasor_b0 * phasor_q
|
|
||||||
- m_phasor_a1 * m_phasor_q1
|
|
||||||
- m_phasor_a2 * m_phasor_q2;
|
|
||||||
m_phasor_i2 = m_phasor_i1;
|
|
||||||
m_phasor_i1 = phasor_i;
|
|
||||||
m_phasor_q2 = m_phasor_q1;
|
|
||||||
m_phasor_q1 = phasor_q;
|
|
||||||
|
|
||||||
// Convert I/Q ratio to estimate of phase error.
|
|
||||||
Real phase_err;
|
|
||||||
if (phasor_i > abs(phasor_q)) {
|
|
||||||
// We are within +/- 45 degrees from lock.
|
|
||||||
// Use simple linear approximation of arctan.
|
|
||||||
phase_err = phasor_q / phasor_i;
|
|
||||||
} else if (phasor_q > 0) {
|
|
||||||
// We are lagging more than 45 degrees behind the input.
|
|
||||||
phase_err = 1;
|
|
||||||
} else {
|
|
||||||
// We are more than 45 degrees ahead of the input.
|
|
||||||
phase_err = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect pilot level (conservative).
|
|
||||||
// m_pilot_level = std::min(m_pilot_level, phasor_i);
|
|
||||||
m_pilot_level = phasor_i;
|
|
||||||
|
|
||||||
// Run phase error through loop filter and update frequency estimate.
|
|
||||||
m_freq += m_loopfilter_b0 * phase_err
|
|
||||||
+ m_loopfilter_b1 * m_loopfilter_x1;
|
|
||||||
m_loopfilter_x1 = phase_err;
|
|
||||||
|
|
||||||
// Limit frequency to allowable range.
|
|
||||||
m_freq = std::max(m_minfreq, std::min(m_maxfreq, m_freq));
|
|
||||||
|
|
||||||
// Update locked phase.
|
|
||||||
m_phase += m_freq;
|
|
||||||
if (m_phase > 2.0 * M_PI) {
|
|
||||||
m_phase -= 2.0 * M_PI;
|
|
||||||
m_pilot_periods++;
|
|
||||||
|
|
||||||
// Generate pulse-per-second.
|
|
||||||
if (m_pilot_periods == pilot_frequency) {
|
|
||||||
m_pilot_periods = 0;
|
|
||||||
//if (was_locked) {
|
|
||||||
// struct PpsEvent ev;
|
|
||||||
// ev.pps_index = m_pps_cnt;
|
|
||||||
// ev.sample_index = m_sample_cnt + i;
|
|
||||||
// ev.block_position = double(i) / double(n);
|
|
||||||
// m_pps_events.push_back(ev);
|
|
||||||
// m_pps_cnt++;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update lock status.
|
|
||||||
if (2 * m_pilot_level > m_minsignal)
|
|
||||||
{
|
|
||||||
if (m_lock_cnt < m_lock_delay)
|
|
||||||
{
|
|
||||||
m_lock_cnt += 1; // n
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_unlock_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (m_unlock_cnt < m_unlock_delay)
|
|
||||||
{
|
|
||||||
m_unlock_cnt += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_lock_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop PPS events when pilot not locked.
|
|
||||||
if (m_lock_cnt < m_lock_delay) {
|
|
||||||
m_pilot_periods = 0;
|
|
||||||
m_pps_cnt = 0;
|
|
||||||
m_pps_events.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update sample counter.
|
|
||||||
m_sample_cnt += 1; // n
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process samples. Multiple output
|
// Process samples. Multiple output
|
||||||
void PhaseLock::process(const Real& sample_in, std::vector<Real>& samples_out)
|
void PhaseLock::process(const Real& sample_in, Real *samples_out)
|
||||||
{
|
{
|
||||||
bool was_locked = (m_lock_cnt >= m_lock_delay);
|
bool was_locked = (m_lock_cnt >= m_lock_delay);
|
||||||
m_pps_events.clear();
|
m_pps_events.clear();
|
||||||
|
|
Ładowanie…
Reference in New Issue