mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-22 17:45:48 -05:00
WFM demod: optimization (got rid of atan2) and implemented squelch
This commit is contained in:
parent
3f106ade9e
commit
93c7188a33
@ -59,9 +59,9 @@ Known Issues
|
||||
============
|
||||
|
||||
- Actually NFM seems to be working pretty well
|
||||
- WFM does not work for broadcast
|
||||
- NFM audio seems wrong (too slow) for RTL-SDR rates other than 1536 kHz. Maybe in SSB too.
|
||||
- Does not work properly for RTL-SDR sampling rates not multiple of AF sampling rate (48000 Hz). This is because the interpolator/decimator is not a rational resampler actually (just does one or the other). For now please use 288, 1152 or 1536 kHz sampling rates,
|
||||
- RTL frontend will have bad aliasing in noisy environments. Considering the size of the hardware there is no place for proper filters. With good filtering and a good antenna up front these devices work remarkably well for the price!
|
||||
- Aliasing can be annoying for broadcast FM. In this case try to shift the signal until you find a clear background for your station. This is a limitation of the RTL hardware so just use this workaround.
|
||||
|
||||
===================
|
||||
Done since the fork
|
||||
@ -81,12 +81,14 @@ Done since the fork
|
||||
- Added the possibility to change the brightness and/or color of the grid.
|
||||
- Make the low cutoff frequency of the SSB filter variable so it can be used for CW also.
|
||||
- NFM demodulation without using atan and smooth squelch with AGC suppressing most clicks on low level signals and hiss on carrier tails. Only useful modulation comes through.
|
||||
- Added working WFM demodulation.
|
||||
|
||||
=====
|
||||
To Do
|
||||
=====
|
||||
|
||||
- Fix and possibly enhance (stereo, RDS?) WFM. Maybe into two plugins one for plain WFM and the other for Broadcast FM
|
||||
- Missing de-accentuation on WFM
|
||||
- Optimize (no atan2) and enhance (stereo, RDS?) WFM.
|
||||
- Make the the SSB filter frequency bounds tunable so that it can be used for CW. Change marker overlay accordingly.
|
||||
- Possibility to completely undock the receiver in a separate window. Useful when there are many receivers
|
||||
- Larger decimation capability for narrowband and very narrowband work (32, 64, ...)
|
||||
|
@ -60,43 +60,12 @@ void WFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBa
|
||||
cmd->submit(messageQueue, this);
|
||||
}
|
||||
|
||||
/*
|
||||
float arctan2(Real y, Real x)
|
||||
{
|
||||
Real coeff_1 = M_PI / 4;
|
||||
Real coeff_2 = 3 * coeff_1;
|
||||
Real abs_y = fabs(y) + 1e-10; // kludge to prevent 0/0 condition
|
||||
Real angle;
|
||||
if( x>= 0) {
|
||||
Real r = (x - abs_y) / (x + abs_y);
|
||||
angle = coeff_1 - coeff_1 * r;
|
||||
} else {
|
||||
Real r = (x + abs_y) / (abs_y - x);
|
||||
angle = coeff_2 - coeff_1 * r;
|
||||
}
|
||||
if(y < 0)
|
||||
return(-angle);
|
||||
else return(angle);
|
||||
}
|
||||
|
||||
Real angleDist(Real a, Real b)
|
||||
{
|
||||
Real dist = b - a;
|
||||
|
||||
while(dist <= M_PI)
|
||||
dist += 2 * M_PI;
|
||||
while(dist >= M_PI)
|
||||
dist -= 2 * M_PI;
|
||||
|
||||
return dist;
|
||||
}
|
||||
*/
|
||||
|
||||
void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
|
||||
{
|
||||
Complex ci;
|
||||
fftfilt::cmplx *rf;
|
||||
int rf_out;
|
||||
Real msq, demod;
|
||||
|
||||
if (m_audioFifo->size() <= 0)
|
||||
return;
|
||||
@ -110,10 +79,40 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
|
||||
|
||||
for (int i =0 ; i <rf_out; i++)
|
||||
{
|
||||
/*
|
||||
// atan2 version
|
||||
Real x = rf[i].real() * m_lastSample.real() + rf[i].imag() * m_lastSample.imag();
|
||||
Real y = rf[i].real() * m_lastSample.imag() - rf[i].imag() * m_lastSample.real();
|
||||
Real y = rf[i].real() * m_m1Sample.imag() - rf[i].imag() * m_m1Sample.real();
|
||||
Real demod = atan2(x,y) / M_PI;
|
||||
m_lastSample = rf[i];
|
||||
*/
|
||||
|
||||
msq = rf[i].real()*rf[i].real() + rf[i].imag()*rf[i].imag();
|
||||
|
||||
m_movingAverage.feed(msq);
|
||||
|
||||
if(m_movingAverage.average() >= m_squelchLevel)
|
||||
m_squelchState = m_running.m_rfBandwidth / 20; // decay rate
|
||||
|
||||
if(m_squelchState > 0)
|
||||
{
|
||||
m_squelchState--;
|
||||
|
||||
// Alternative without atan
|
||||
// http://www.embedded.com/design/configurable-systems/4212086/DSP-Tricks--Frequency-demodulation-algorithms-
|
||||
// in addition it needs scaling by instantaneous magnitude squared and volume (0..10) adjustment factor
|
||||
Real ip = rf[i].real() - m_m2Sample.real();
|
||||
Real qp = rf[i].imag() - m_m2Sample.imag();
|
||||
Real h1 = m_m1Sample.real() * qp;
|
||||
Real h2 = m_m1Sample.imag() * ip;
|
||||
demod = (h1 - h2) / (msq * 10.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
demod = 0;
|
||||
}
|
||||
|
||||
m_m2Sample = m_m1Sample;
|
||||
m_m1Sample = rf[i];
|
||||
|
||||
Complex e(demod, 0);
|
||||
|
||||
@ -241,7 +240,7 @@ void WFMDemod::start()
|
||||
m_interpolatorRegulation = 0.9999;
|
||||
m_interpolatorDistance = 1.0;
|
||||
m_interpolatorDistanceRemain = 0.0;
|
||||
m_lastSample = 0;
|
||||
m_m1Sample = 0;
|
||||
}
|
||||
|
||||
void WFMDemod::stop()
|
||||
|
@ -120,7 +120,8 @@ private:
|
||||
int m_squelchState;
|
||||
|
||||
Real m_lastArgument;
|
||||
Complex m_lastSample;
|
||||
Complex m_m1Sample; // x^-1 sample
|
||||
Complex m_m2Sample; // x^-1 sample
|
||||
MovingAverage m_movingAverage;
|
||||
|
||||
AudioVector m_audioBuffer;
|
||||
|
Loading…
Reference in New Issue
Block a user