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.
This commit is contained in:
Charles J. Cliffe 2014-11-11 21:42:18 -05:00
parent 86dadb8f2c
commit 810533750f
4 changed files with 64 additions and 28 deletions

View File

@ -41,10 +41,12 @@ static int patestCallback(const void *inputBuffer, void *outputBuffer, unsigned
Demodulator::Demodulator() { Demodulator::Demodulator() {
bandwidth = 800000; bandwidth = 300000;
resample_ratio = (float) (bandwidth) / (float) SRATE; resample_ratio = (float) (bandwidth) / (float) SRATE;
audio_frequency = 44100; wbfm_frequency = 32000;
audio_resample_ratio = (float) (audio_frequency) / (float) bandwidth; wbfm_resample_ratio = (float) (wbfm_frequency) / (float) bandwidth;
audio_frequency = 48000;
audio_resample_ratio = (float) (audio_frequency) / (float) wbfm_frequency;
PaError err; PaError err;
err = Pa_Initialize(); err = Pa_Initialize();
@ -83,7 +85,7 @@ Demodulator::Demodulator() {
stream = NULL; 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); err = Pa_StartStream(stream);
if (err != paNoError) { if (err != paNoError) {
@ -103,14 +105,22 @@ Demodulator::Demodulator() {
fir_filter = firfilt_crcf_create(h, h_len); 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 // create multi-stage arbitrary resampler object
resampler = msresamp_crcf_create(resample_ratio, As); resampler = msresamp_crcf_create(resample_ratio, As);
msresamp_crcf_print(resampler); 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); audio_resampler = msresamp_crcf_create(audio_resample_ratio, As);
msresamp_crcf_print(audio_resampler); msresamp_crcf_print(audio_resampler);
float kf = 0.1f; // modulation factor float kf = 0.5f; // modulation factor
fdem = freqdem_create(kf); fdem = freqdem_create(kf);
freqdem_print(fdem); freqdem_print(fdem);
@ -166,17 +176,32 @@ void Demodulator::writeBuffer(std::vector<signed char> *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]; liquid_float_complex resampled_audio_output[audio_out_size];
unsigned int num_audio_written; // number of values written to buffer unsigned int num_audio_written;
msresamp_crcf_execute(audio_resampler, resampled_output, num_written, resampled_audio_output, &num_audio_written); msresamp_crcf_execute(audio_resampler, resampled_wbfm_output, num_wbfm_written, resampled_audio_output, &num_audio_written);
std::vector<float> *newBuffer = new std::vector<float>; std::vector<float> *newBuffer = new std::vector<float>;
newBuffer->resize(num_audio_written * 2); newBuffer->resize(num_audio_written * 2);
for (int i = 0; i < num_audio_written; i++) { for (int i = 0; i < num_audio_written; i++) {
(*newBuffer)[i * 2] = resampled_audio_output[i].real; liquid_float_complex y = resampled_audio_output[i];
(*newBuffer)[i * 2 + 1] = resampled_audio_output[i].real;
(*newBuffer)[i * 2] = y.real;
(*newBuffer)[i * 2 + 1] = y.real;
} }
audio_queue.push(newBuffer); audio_queue.push(newBuffer);

View File

@ -31,14 +31,22 @@ public:
private: private:
firfilt_crcf fir_filter; firfilt_crcf fir_filter;
firfilt_crcf fir_audio_filter;
unsigned int bandwidth;
msresamp_crcf resampler; msresamp_crcf resampler;
msresamp_crcf audio_resampler;
float resample_ratio; 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; float audio_resample_ratio;
unsigned int audio_frequency;
PaStreamParameters outputParameters; PaStreamParameters outputParameters;
PaStream *stream; PaStream *stream;
freqdem fdem; freqdem fdem;

View File

@ -95,12 +95,25 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas) :
CheckGLError(); CheckGLError();
} }
void PrimaryGLContext::Plot(std::vector<float> &points, std::vector<float> &points2, unsigned char *waterfall_tex) { void PrimaryGLContext::Plot(std::vector<float> &points, std::vector<float> &points2) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 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); 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_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); 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<float> &points, std::vector<float> &poin
glPopMatrix(); glPopMatrix();
} }
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
// glEnable(GL_COLOR_TABLE); // glEnable(GL_COLOR_TABLE);
glBindTexture(GL_TEXTURE_2D, waterfall); glBindTexture(GL_TEXTURE_2D, waterfall);
@ -184,7 +198,7 @@ void TestGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
PrimaryGLContext& canvas = wxGetApp().GetContext(this); PrimaryGLContext& canvas = wxGetApp().GetContext(this);
glViewport(0, 0, ClientSize.x, ClientSize.y); 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(); SwapBuffers();
} }
@ -281,16 +295,8 @@ void TestGLCanvas::setData(std::vector<signed char> *data) {
// fftw_execute(plan[1]); // 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++) { for (int i = 0, iMax = FFT_SIZE; i < iMax; i++) {
float v = log10(fft_result_maa[i]) / log10(fft_ceil_maa); 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] = ((float) i / (float) iMax);
spectrum_points[i * 2 + 1] = v; spectrum_points[i * 2 + 1] = v;
} }

View File

@ -18,13 +18,14 @@ class PrimaryGLContext: public wxGLContext {
public: public:
PrimaryGLContext(wxGLCanvas *canvas); PrimaryGLContext(wxGLCanvas *canvas);
void Plot(std::vector<float> &points, std::vector<float> &points2, unsigned char *waterfall_tex); void Plot(std::vector<float> &points, std::vector<float> &points2);
private: private:
Gradient grad; Gradient grad;
GLuint waterfall; GLuint waterfall;
unsigned char waterfall_tex[FFT_SIZE * NUM_WATERFALL_LINES];
}; };
class TestGLCanvas: public wxGLCanvas { class TestGLCanvas: public wxGLCanvas {
@ -52,10 +53,6 @@ private:
std::vector<float> fft_result_ma; std::vector<float> fft_result_ma;
std::vector<float> fft_result_maa; std::vector<float> fft_result_maa;
unsigned char waterfall_tex[FFT_SIZE * NUM_WATERFALL_LINES];
Demodulator test_demod; Demodulator test_demod;
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };