1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-23 01:55:48 -05:00

WFM demod: optimization (got rid of atan2) and implemented squelch

This commit is contained in:
f4exb 2015-05-15 15:05:28 +02:00
parent 3f106ade9e
commit 93c7188a33
3 changed files with 41 additions and 39 deletions

View File

@ -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, ...)

View File

@ -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()

View File

@ -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;