mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04:00 
			
		
		
		
	Working unoptimzied WFM just mono (AF baseband)
This commit is contained in:
		
							parent
							
								
									b7c0e85329
								
							
						
					
					
						commit
						3f106ade9e
					
				| @ -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 | ||||
|  | ||||
| @ -5,5 +5,6 @@ add_subdirectory(am) | ||||
| add_subdirectory(nfm) | ||||
| add_subdirectory(ssb) | ||||
| add_subdirectory(tcpsrc) | ||||
| add_subdirectory(wfm) | ||||
| 
 | ||||
| #add_subdirectory(tetra) | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -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; | ||||
| 	*/ | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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) : | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user