1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 09:18:54 -05:00

Working unoptimzied WFM just mono (AF baseband)

This commit is contained in:
f4exb 2015-05-15 11:29:41 +02:00
parent b7c0e85329
commit 3f106ade9e
8 changed files with 120 additions and 33 deletions

View File

@ -5,7 +5,7 @@
#ifndef _FFTFILT_H
#define _FFTFILT_H
#include "complex.h"
#include <complex>
#include "gfft.h"
//----------------------------------------------------------------------
@ -13,6 +13,20 @@
class fftfilt {
enum {NONE, BLACKMAN, HAMMING, HANNING};
public:
typedef std::complex<float> cmplx;
fftfilt(float f1, float f2, int len);
fftfilt(float f, int len);
~fftfilt();
// f1 < f2 ==> bandpass
// f1 > f2 ==> band reject
void create_filter(float f1, float f2);
void rtty_filter(float);
int runFilt(const cmplx& in, cmplx **out);
int runSSB(const cmplx& in, cmplx **out, bool usb);
protected:
int flen;
int flen2;
@ -36,18 +50,6 @@ protected:
0.08 * cos(4.0 * M_PI * i / len));
}
void init_filter();
public:
fftfilt(float f1, float f2, int len);
fftfilt(float f, int len);
~fftfilt();
// f1 < f2 ==> bandpass
// f1 > f2 ==> band reject
void create_filter(float f1, float f2);
void rtty_filter(float);
int runFilt(const cmplx& in, cmplx **out);
int runSSB(const cmplx& in, cmplx **out, bool usb);
};
@ -55,6 +57,12 @@ public:
/* Sliding FFT filter from Fldigi */
class sfft {
#define K1 0.99999
public:
typedef std::complex<float> cmplx;
sfft(int len);
~sfft();
void run(const cmplx& input);
void fetch(float *result);
private:
int fftlen;
int first;
@ -64,11 +72,6 @@ private:
vrot_bins_pair *vrot_bins;
cmplx *delay;
float k2;
public:
sfft(int len);
~sfft();
void run(const cmplx& input);
void fetch(float *result);
};
#endif

View File

@ -5,5 +5,6 @@ add_subdirectory(am)
add_subdirectory(nfm)
add_subdirectory(ssb)
add_subdirectory(tcpsrc)
add_subdirectory(wfm)
#add_subdirectory(tetra)

View File

@ -62,7 +62,7 @@ void SSBDemod::configure(MessageQueue* messageQueue, Real Bandwidth, Real LowCut
void SSBDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{
Complex ci;
cmplx *sideband;
fftfilt::cmplx *sideband;
int n_out;
for(SampleVector::const_iterator it = begin; it < end; ++it) {

View File

@ -70,7 +70,7 @@ void TCPSrc::setSpectrum(MessageQueue* messageQueue, bool enabled)
void TCPSrc::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{
Complex ci;
cmplx* sideband;
fftfilt::cmplx* sideband;
Real l, r;
m_sampleBuffer.clear();

View File

@ -23,7 +23,7 @@
#include "dsp/pidcontroller.h"
#include "wfmdemod.h"
#include <iostream>
//#include <iostream>
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureWFMDemod, Message)
@ -31,13 +31,14 @@ WFMDemod::WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
m_sampleSink(sampleSink),
m_audioFifo(audioFifo)
{
m_config.m_inputSampleRate = 96000;
m_config.m_inputSampleRate = 384000;
m_config.m_inputFrequencyOffset = 0;
m_config.m_rfBandwidth = 180000;
m_config.m_afBandwidth = 15000;
m_config.m_squelch = -60.0;
m_config.m_volume = 2.0;
m_config.m_audioSampleRate = 48000;
m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, rfFilterFftLength);
apply();
@ -49,6 +50,8 @@ WFMDemod::WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
WFMDemod::~WFMDemod()
{
if (m_rfFilter)
delete m_rfFilter;
}
void WFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch)
@ -92,16 +95,51 @@ Real angleDist(Real a, Real b)
void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
{
Complex ci;
fftfilt::cmplx *rf;
int rf_out;
if(m_audioFifo->size() <= 0)
if (m_audioFifo->size() <= 0)
return;
for(SampleVector::const_iterator it = begin; it != end; ++it) {
for (SampleVector::const_iterator it = begin; it != end; ++it)
{
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ();
rf_out = m_rfFilter->runFilt(c, &rf); // filter RF before demod
for (int i =0 ; i <rf_out; i++)
{
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
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 demod = atan2(x,y) / M_PI;
m_lastSample = rf[i];
Complex e(demod, 0);
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, e, &ci))
{
quint16 sample = (qint16)(ci.real() * 3000 * m_running.m_volume);
m_sampleBuffer.push_back(Sample(sample, sample));
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill;
if(m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if(res != m_audioBufferFill)
qDebug("lost %u samples", m_audioBufferFill - res);
m_audioBufferFill = 0;
}
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
#if 0
{
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, e, &ci))
{
m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0));
@ -113,10 +151,12 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
if(m_squelchState > 0) {
m_squelchState--;
/*
Real argument = arg(ci);
argument /= M_PI;
Real demod = argument - m_lastArgument;
m_lastArgument = argument;
*/
//ci *= 32768.0;
@ -178,7 +218,10 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
#endif
}
if(m_audioBufferFill > 0) {
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if(res != m_audioBufferFill)
@ -234,20 +277,31 @@ void WFMDemod::apply()
{
if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate)) {
(m_config.m_inputSampleRate != m_running.m_inputSampleRate))
{
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth)) {
std::cerr << "WFMDemod::apply: in=" << m_config.m_inputSampleRate << ", rf=" << m_config.m_rfBandwidth << std::endl;
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2);
m_interpolatorDistanceRemain = 0;
(m_config.m_afBandwidth != m_running.m_afBandwidth))
{
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_afBandwidth);
m_interpolatorDistanceRemain = (Real) m_config.m_inputSampleRate / m_config.m_audioSampleRate;
m_interpolatorDistance = m_config.m_inputSampleRate / m_config.m_audioSampleRate;
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
(m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset))
{
Real lowCut = (m_config.m_inputFrequencyOffset - (m_config.m_rfBandwidth / 2.0)) / m_config.m_inputSampleRate;
Real hiCut = (m_config.m_inputFrequencyOffset + (m_config.m_rfBandwidth / 2.0)) / m_config.m_inputSampleRate;
m_rfFilter->create_filter(lowCut, hiCut);
}
if((m_config.m_afBandwidth != m_running.m_afBandwidth) ||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate)) {
(m_config.m_audioSampleRate != m_running.m_audioSampleRate))
{
m_lowpass.create(21, m_config.m_audioSampleRate, m_config.m_afBandwidth);
}
@ -262,4 +316,13 @@ void WFMDemod::apply()
m_running.m_squelch = m_config.m_squelch;
m_running.m_volume = m_config.m_volume;
m_running.m_audioSampleRate = m_config.m_audioSampleRate;
/*
std::cerr << "WFMDemod::apply: in=" << m_config.m_inputSampleRate
<< ", df=" << m_config.m_inputFrequencyOffset
<< ", rfbw=" << m_config.m_rfBandwidth
<< ", afbw=" << m_config.m_afBandwidth
<< std::endl;
*/
}

View File

@ -24,9 +24,12 @@
#include "dsp/interpolator.h"
#include "dsp/lowpass.h"
#include "dsp/movingaverage.h"
#include "dsp/fftfilt.h"
#include "audio/audiofifo.h"
#include "util/message.h"
#define rfFilterFftLength 1024
class AudioFifo;
class WFMDemod : public SampleSink {
@ -111,6 +114,7 @@ private:
Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain;
Lowpass<Real> m_lowpass;
fftfilt* m_rfFilter;
Real m_squelchLevel;
int m_squelchState;

View File

@ -17,6 +17,16 @@ const int WFMDemodGUI::m_rfBW[] = {
48000, 80000, 120000, 140000, 160000, 180000, 200000, 220000, 250000
};
int requiredBW(int rfBW)
{
if (rfBW <= 48000)
return 48000;
else if (rfBW < 100000)
return 96000;
else
return 384000;
}
WFMDemodGUI* WFMDemodGUI::create(PluginAPI* pluginAPI)
{
WFMDemodGUI* gui = new WFMDemodGUI(pluginAPI);
@ -208,7 +218,7 @@ void WFMDemodGUI::applySettings()
{
setTitleColor(m_channelMarker->getColor());
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
256000, // TODO: this is where requested sample rate is specified
requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified
m_channelMarker->getCenterFrequency());
ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0);

View File

@ -96,11 +96,17 @@ bool Channelizer::handleMessage(Message* cmd)
void Channelizer::applyConfiguration()
{
freeFilterChain();
//std::cerr << "Channelizer::applyConfiguration in=" << m_inputSampleRate << ", req=" << m_requestedOutputSampleRate << std::endl;
m_currentCenterFrequency = createFilterChain(
m_inputSampleRate / -2, m_inputSampleRate / 2,
m_requestedCenterFrequency - m_requestedOutputSampleRate / 2, m_requestedCenterFrequency + m_requestedOutputSampleRate / 2);
m_currentOutputSampleRate = m_inputSampleRate / (1 << m_filterStages.size());
/*
std::cerr << "Channelizer::applyConfiguration in=" << m_inputSampleRate
<< ", req=" << m_requestedOutputSampleRate
<< ", out=" << m_currentOutputSampleRate
<< ", fc=" << m_currentCenterFrequency
<< std::endl;
*/
}
Channelizer::FilterStage::FilterStage(Mode mode) :