From 810533750f638cf2f2c918a7d1eb76c4a30ac1cd Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 11 Nov 2014 21:42:18 -0500 Subject: [PATCH] waterfall optimize, fm demod audio filtering Moved waterfall increment into rendering to reduce audio processing impact. Added another test filter and resample stage to FM demod experiment to clean up audio and remove high pitch on stereo channels until it can be demodulated. --- src/Demodulator.cpp | 45 +++++++++++++++++++++++++++++++--------- src/Demodulator.h | 14 ++++++++++--- src/PrimaryGLContext.cpp | 26 ++++++++++++++--------- src/PrimaryGLContext.h | 7 ++----- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/Demodulator.cpp b/src/Demodulator.cpp index 792a2f0..3927d2c 100644 --- a/src/Demodulator.cpp +++ b/src/Demodulator.cpp @@ -41,10 +41,12 @@ static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned Demodulator::Demodulator() { - bandwidth = 800000; + bandwidth = 300000; resample_ratio = (float) (bandwidth) / (float) SRATE; - audio_frequency = 44100; - audio_resample_ratio = (float) (audio_frequency) / (float) bandwidth; + wbfm_frequency = 32000; + wbfm_resample_ratio = (float) (wbfm_frequency) / (float) bandwidth; + audio_frequency = 48000; + audio_resample_ratio = (float) (audio_frequency) / (float) wbfm_frequency; PaError err; err = Pa_Initialize(); @@ -83,7 +85,7 @@ Demodulator::Demodulator() { stream = NULL; - err = Pa_OpenStream(&stream, NULL, &outputParameters, 44100, 256, paClipOff, &patestCallback, this); + err = Pa_OpenStream(&stream, NULL, &outputParameters, audio_frequency, 256, paClipOff, &patestCallback, this); err = Pa_StartStream(stream); if (err != paNoError) { @@ -103,14 +105,22 @@ Demodulator::Demodulator() { fir_filter = firfilt_crcf_create(h, h_len); + h_len = estimate_req_filter_len(ft, As); + liquid_firdes_kaiser(h_len, 0.3f, As, mu, h); + + fir_audio_filter = firfilt_crcf_create(h, h_len); + // create multi-stage arbitrary resampler object resampler = msresamp_crcf_create(resample_ratio, As); msresamp_crcf_print(resampler); + wbfm_resampler = msresamp_crcf_create(wbfm_resample_ratio, As); + msresamp_crcf_print(wbfm_resampler); + audio_resampler = msresamp_crcf_create(audio_resample_ratio, As); msresamp_crcf_print(audio_resampler); - float kf = 0.1f; // modulation factor + float kf = 0.5f; // modulation factor fdem = freqdem_create(kf); freqdem_print(fdem); @@ -166,17 +176,32 @@ void Demodulator::writeBuffer(std::vector *data) { } } - int audio_out_size = ceil((float) (num_written) * audio_resample_ratio); + + int wbfm_out_size = ceil((float) (num_written) * wbfm_resample_ratio); + liquid_float_complex resampled_wbfm_output[wbfm_out_size]; + + unsigned int num_wbfm_written; + msresamp_crcf_execute(wbfm_resampler, resampled_output, num_written, resampled_wbfm_output, &num_wbfm_written); + + + for (int i = 0; i < num_wbfm_written; i++) { + firfilt_crcf_push(fir_audio_filter, resampled_wbfm_output[i]); + firfilt_crcf_execute(fir_audio_filter, &resampled_wbfm_output[i]); + } + + int audio_out_size = ceil((float) (num_wbfm_written) * audio_resample_ratio); liquid_float_complex resampled_audio_output[audio_out_size]; - unsigned int num_audio_written; // number of values written to buffer - msresamp_crcf_execute(audio_resampler, resampled_output, num_written, resampled_audio_output, &num_audio_written); + unsigned int num_audio_written; + msresamp_crcf_execute(audio_resampler, resampled_wbfm_output, num_wbfm_written, resampled_audio_output, &num_audio_written); std::vector *newBuffer = new std::vector; newBuffer->resize(num_audio_written * 2); for (int i = 0; i < num_audio_written; i++) { - (*newBuffer)[i * 2] = resampled_audio_output[i].real; - (*newBuffer)[i * 2 + 1] = resampled_audio_output[i].real; + liquid_float_complex y = resampled_audio_output[i]; + + (*newBuffer)[i * 2] = y.real; + (*newBuffer)[i * 2 + 1] = y.real; } audio_queue.push(newBuffer); diff --git a/src/Demodulator.h b/src/Demodulator.h index 6d085c4..cbf483e 100644 --- a/src/Demodulator.h +++ b/src/Demodulator.h @@ -31,14 +31,22 @@ public: private: firfilt_crcf fir_filter; + firfilt_crcf fir_audio_filter; + + unsigned int bandwidth; msresamp_crcf resampler; - msresamp_crcf audio_resampler; float resample_ratio; - unsigned int bandwidth; - unsigned int audio_frequency; + + msresamp_crcf wbfm_resampler; + float wbfm_resample_ratio; + unsigned int wbfm_frequency; + + msresamp_crcf audio_resampler; float audio_resample_ratio; + unsigned int audio_frequency; + PaStreamParameters outputParameters; PaStream *stream; freqdem fdem; diff --git a/src/PrimaryGLContext.cpp b/src/PrimaryGLContext.cpp index 8ffa11b..a2f55fe 100644 --- a/src/PrimaryGLContext.cpp +++ b/src/PrimaryGLContext.cpp @@ -95,12 +95,25 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas) : CheckGLError(); } -void PrimaryGLContext::Plot(std::vector &points, std::vector &points2, unsigned char *waterfall_tex) { +void PrimaryGLContext::Plot(std::vector &points, std::vector &points2) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); + if (points.size()) { + memmove(waterfall_tex + FFT_SIZE, waterfall_tex, (NUM_WATERFALL_LINES - 1) * FFT_SIZE); + + for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) { + float v = points[i*2+1]; + + float wv = v; + if (wv<0.0) wv = 0.0; + if (wv>1.0) wv = 1.0; + waterfall_tex[i] = (unsigned char) floor(wv * 255.0); + } + } + glBindTexture(GL_TEXTURE_2D, waterfall); // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FFT_SIZE, NUM_WATERFALL_LINES, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, waterfall_tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, FFT_SIZE, NUM_WATERFALL_LINES, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, (GLvoid *) waterfall_tex); @@ -132,6 +145,7 @@ void PrimaryGLContext::Plot(std::vector &points, std::vector &poin glPopMatrix(); } + glEnable(GL_TEXTURE_2D); // glEnable(GL_COLOR_TABLE); glBindTexture(GL_TEXTURE_2D, waterfall); @@ -184,7 +198,7 @@ void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { PrimaryGLContext& canvas = wxGetApp().GetContext(this); glViewport(0, 0, ClientSize.x, ClientSize.y); - canvas.Plot(spectrum_points, test_demod.waveform_points, waterfall_tex); + canvas.Plot(spectrum_points, test_demod.waveform_points); SwapBuffers(); } @@ -281,16 +295,8 @@ void TestGLCanvas::setData(std::vector *data) { // fftw_execute(plan[1]); - memmove(waterfall_tex + FFT_SIZE, waterfall_tex, (NUM_WATERFALL_LINES - 1) * FFT_SIZE); - for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) { float v = log10(fft_result_maa[i]) / log10(fft_ceil_maa); - - float wv = v; - if (wv<0.0) wv = 0.0; - if (wv>1.0) wv = 1.0; - waterfall_tex[i] = (unsigned char) floor(wv * 255.0); - spectrum_points[i * 2] = ((float) i / (float) iMax); spectrum_points[i * 2 + 1] = v; } diff --git a/src/PrimaryGLContext.h b/src/PrimaryGLContext.h index 8e0aac0..813c459 100644 --- a/src/PrimaryGLContext.h +++ b/src/PrimaryGLContext.h @@ -18,13 +18,14 @@ class PrimaryGLContext: public wxGLContext { public: PrimaryGLContext(wxGLCanvas *canvas); - void Plot(std::vector &points, std::vector &points2, unsigned char *waterfall_tex); + void Plot(std::vector &points, std::vector &points2); private: Gradient grad; GLuint waterfall; + unsigned char waterfall_tex[FFT_SIZE * NUM_WATERFALL_LINES]; }; class TestGLCanvas: public wxGLCanvas { @@ -52,10 +53,6 @@ private: std::vector fft_result_ma; std::vector fft_result_maa; - - unsigned char waterfall_tex[FFT_SIZE * NUM_WATERFALL_LINES]; - - Demodulator test_demod; wxDECLARE_EVENT_TABLE(); };