From 499e411048e0415bcb61b7851c231bb48535b275 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sat, 29 Nov 2014 13:58:20 -0500 Subject: [PATCH] Remove DC spike from IQ stream and visuals IQ post-process / distribution in separate thread, use of iirfilt_crcf_create_dc_blocker to reduce DC offset in IQ stream. --- CMakeLists.txt | 2 + src/CubicSDR.cpp | 20 ++++++++- src/CubicSDR.h | 4 ++ src/CubicSDRDefs.h | 2 +- src/sdr/SDRPostThread.cpp | 78 ++++++++++++++++++++++++++++++++++ src/sdr/SDRPostThread.h | 43 +++++++++++++++++++ src/sdr/SDRThread.cpp | 32 ++++---------- src/sdr/SDRThread.h | 15 +------ src/visual/SpectrumCanvas.cpp | 23 +++++----- src/visual/WaterfallCanvas.cpp | 31 +++++++------- 10 files changed, 184 insertions(+), 66 deletions(-) create mode 100644 src/sdr/SDRPostThread.cpp create mode 100644 src/sdr/SDRPostThread.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bade6af..f2390be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ SET (cubicsdr_sources src/CubicSDR.cpp src/AppFrame.cpp src/sdr/SDRThread.cpp + src/sdr/SDRPostThread.cpp src/demod/DemodulatorThread.cpp src/demod/DemodulatorMgr.cpp src/audio/AudioThread.cpp @@ -110,6 +111,7 @@ SET (cubicsdr_headers src/CubicSDR.h src/AppFrame.h src/sdr/SDRThread.h + src/sdr/SDRPostThread.h src/demod/DemodulatorThread.h src/demod/DemodulatorMgr.h src/audio/AudioThread.h diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index ac2f5d3..36c41a9 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -36,11 +36,19 @@ bool CubicSDR::OnInit() { threadCmdQueueSDR = new SDRThreadCommandQueue; sdrThread = new SDRThread(threadCmdQueueSDR); - sdrThread->bindDemodulator(demodulatorTest); + sdrPostThread = new SDRPostThread(); + + iqPostDataQueue = new SDRThreadIQDataQueue; iqVisualQueue = new SDRThreadIQDataQueue; - sdrThread->setIQVisualQueue(iqVisualQueue); + sdrThread->setIQDataOutQueue(iqPostDataQueue); + sdrPostThread->setIQDataInQueue(iqPostDataQueue); + sdrPostThread->setIQVisualQueue(iqVisualQueue); + + sdrPostThread->bindDemodulator(demodulatorTest); + + threadPostSDR = new std::thread(&SDRPostThread::threadMain, sdrPostThread); threadSDR = new std::thread(&SDRThread::threadMain, sdrThread); AppFrame *appframe = new AppFrame(); @@ -53,9 +61,15 @@ int CubicSDR::OnExit() { sdrThread->terminate(); threadSDR->join(); + sdrPostThread->terminate(); + threadPostSDR->join(); + delete sdrThread; delete threadSDR; + delete sdrPostThread; + delete threadPostSDR; + demodMgr.terminateAll(); audioThread->terminate(); @@ -69,6 +83,8 @@ int CubicSDR::OnExit() { delete iqVisualQueue; delete audioVisualQueue; + delete iqPostDataQueue; + delete m_glContext; return wxApp::OnExit(); diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 9f351d1..89164be 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -11,6 +11,7 @@ #include "ThreadQueue.h" #include "SDRThread.h" +#include "SDRPostThread.h" #include "AudioThread.h" #include "DemodulatorMgr.h" @@ -57,12 +58,15 @@ private: AudioThread *audioThread; SDRThread *sdrThread; + SDRPostThread *sdrPostThread; SDRThreadCommandQueue* threadCmdQueueSDR; SDRThreadIQDataQueue* iqVisualQueue; + SDRThreadIQDataQueue* iqPostDataQueue; DemodulatorThreadOutputQueue* audioVisualQueue; std::thread *threadAudio; std::thread *threadSDR; + std::thread *threadPostSDR; }; DECLARE_APP(CubicSDR) diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 6f60220..b538c3c 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -1,6 +1,6 @@ #pragma once -#define BUF_SIZE (16 * 32 * 128) +#define BUF_SIZE (16384*6) #define SRATE 2000000 #define FFT_SIZE 2048 diff --git a/src/sdr/SDRPostThread.cpp b/src/sdr/SDRPostThread.cpp new file mode 100644 index 0000000..df0ce38 --- /dev/null +++ b/src/sdr/SDRPostThread.cpp @@ -0,0 +1,78 @@ +#include "SDRPostThread.h" +#include "CubicSDRDefs.h" +#include +#include "CubicSDR.h" + +SDRPostThread::SDRPostThread() : + iqDataInQueue(NULL), iqDataOutQueue(NULL), iqVisualQueue(NULL), terminated(false) { + dev = NULL; + sample_rate = SRATE; +} + +SDRPostThread::~SDRPostThread() { + std::cout << std::endl << "SDR post-process thread done." << std::endl << std::endl; + rtlsdr_close(dev); +} + +void SDRPostThread::threadMain() { + + std::cout << "SDR post-process thread starting.." << std::endl; + + int n_read; + double seconds = 0.0; + + dcFilter = iirfilt_crcf_create_dc_blocker(0.0005); + + liquid_float_complex x, y; + + std::cout << "Sampling.."; + while (!terminated) { + SDRThreadIQData data_in; + + iqDataInQueue.load()->pop(data_in); + + if (data_in.data.size()) { + SDRThreadIQData dataOut; + + dataOut.frequency = data_in.frequency; + dataOut.bandwidth = data_in.bandwidth; + dataOut.data = data_in.data; + + for (int i = 0, iMax = dataOut.data.size() / 2; i < iMax; i++) { + x.real = (float) dataOut.data[i * 2] / 127.0; + x.imag = (float) dataOut.data[i * 2 + 1] / 127.0; + + iirfilt_crcf_execute(dcFilter, x, &y); + + dataOut.data[i * 2] = (signed char) floor(y.real * 127.0); + dataOut.data[i * 2 + 1] = (signed char) floor(y.imag * 127.0); + } + + if (iqDataOutQueue != NULL) { + iqDataOutQueue.load()->push(dataOut); + } + + if (iqVisualQueue != NULL) { + iqVisualQueue.load()->push(dataOut); + } + + if (demodulators.size()) { + DemodulatorThreadIQData demodDataOut; + demodDataOut.frequency = data_in.frequency; + demodDataOut.bandwidth = data_in.bandwidth; + demodDataOut.data = data_in.data; + + for (int i = 0, iMax = demodulators.size(); i < iMax; i++) { + DemodulatorInstance *demod = demodulators[i]; + DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod; + demodQueue->push(demodDataOut); + } + } + } + } + +} + +void SDRPostThread::terminate() { + terminated = true; +} diff --git a/src/sdr/SDRPostThread.h b/src/sdr/SDRPostThread.h new file mode 100644 index 0000000..4b3d737 --- /dev/null +++ b/src/sdr/SDRPostThread.h @@ -0,0 +1,43 @@ +#pragma once + +#include "SDRThread.h" + +class SDRPostThread { +public: + rtlsdr_dev_t *dev; + + SDRPostThread(); + ~SDRPostThread(); + + int enumerate_rtl(); + + void bindDemodulator(DemodulatorInstance *demod) { + demodulators.push_back(demod); + } + + void threadMain(); + + void setIQDataInQueue(SDRThreadIQDataQueue* iqDataQueue) { + iqDataInQueue = iqDataQueue; + } + void setIQDataOutQueue(SDRThreadIQDataQueue* iqDataQueue) { + iqDataOutQueue = iqDataQueue; + } + void setIQVisualQueue(SDRThreadIQDataQueue *iqVisQueue) { + iqVisualQueue = iqVisQueue; + iqVisualQueue.load()->set_max_num_items(1); + } + + void terminate(); +protected: + + uint32_t sample_rate; + + std::atomic iqDataOutQueue; + std::atomic iqDataInQueue; + std::atomic iqVisualQueue; + + std::vector demodulators; + std::atomic terminated; + iirfilt_crcf dcFilter; +}; diff --git a/src/sdr/SDRThread.cpp b/src/sdr/SDRThread.cpp index 7c8f515..46332ac 100644 --- a/src/sdr/SDRThread.cpp +++ b/src/sdr/SDRThread.cpp @@ -4,7 +4,7 @@ #include "CubicSDR.h" SDRThread::SDRThread(SDRThreadCommandQueue* pQueue) : - m_pQueue(pQueue), iqDataOutQueue(NULL), iqVisualQueue(NULL), terminated(false) { + m_pQueue(pQueue), iqDataOutQueue(NULL), terminated(false) { dev = NULL; sample_rate = SRATE; } @@ -110,7 +110,7 @@ void SDRThread::threadMain() { rtlsdr_set_sample_rate(dev, bandwidth); rtlsdr_set_center_freq(dev, frequency); rtlsdr_set_agc_mode(dev, 1); - rtlsdr_set_offset_tuning(dev, 1); + rtlsdr_set_offset_tuning(dev, 0); rtlsdr_reset_buffer(dev); sample_rate = rtlsdr_get_sample_rate(dev); @@ -122,13 +122,15 @@ void SDRThread::threadMain() { std::cout << "Sampling.."; while (!terminated) { - if (!m_pQueue->empty()) { + SDRThreadCommandQueue *cmdQueue = m_pQueue.load(); + + if (!cmdQueue->empty()) { bool freq_changed = false; float new_freq; - while (!m_pQueue->empty()) { + while (!cmdQueue->empty()) { SDRThreadCommand command; - m_pQueue->pop(command); + cmdQueue->pop(command); switch (command.cmd) { case SDRThreadCommand::SDR_THREAD_CMD_TUNE: @@ -162,26 +164,8 @@ void SDRThread::threadMain() { dataOut.data = new_buffer; if (iqDataOutQueue != NULL) { - iqDataOutQueue->push(dataOut); + iqDataOutQueue.load()->push(dataOut); } - - if (iqVisualQueue != NULL) { - iqVisualQueue->push(dataOut); - } - - if (demodulators.size()) { - DemodulatorThreadIQData demodDataOut; - demodDataOut.frequency = frequency; - demodDataOut.bandwidth = bandwidth; - demodDataOut.data = new_buffer; - - for (int i = 0, iMax = demodulators.size(); i < iMax; i++) { - DemodulatorInstance *demod = demodulators[i]; - DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod; - demodQueue->push(demodDataOut); - } - } - } } diff --git a/src/sdr/SDRThread.h b/src/sdr/SDRThread.h index 4f1dd51..bdec3cf 100644 --- a/src/sdr/SDRThread.h +++ b/src/sdr/SDRThread.h @@ -66,28 +66,17 @@ public: int enumerate_rtl(); - void bindDemodulator(DemodulatorInstance *demod) { - demodulators.push_back(demod); - } - void threadMain(); void setIQDataOutQueue(SDRThreadIQDataQueue* iqDataQueue) { iqDataOutQueue = iqDataQueue; } - void setIQVisualQueue(SDRThreadIQDataQueue *iqVisQueue) { - iqVisualQueue = iqVisQueue; - iqVisualQueue->set_max_num_items(1); - } void terminate(); protected: - uint32_t sample_rate; - SDRThreadCommandQueue* m_pQueue; - SDRThreadIQDataQueue* iqDataOutQueue; - SDRThreadIQDataQueue* iqVisualQueue; + std::atomic m_pQueue; + std::atomic iqDataOutQueue; - std::vector demodulators; std::atomic terminated; }; diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index 223abe1..d75c705 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -117,19 +117,20 @@ void SpectrumCanvas::setData(std::vector *data) { fft_result_maa.resize(FFT_SIZE); } - for (int j = 0; j < 2; j++) { - for (int i = 0, iMax = FFT_SIZE / 2; i < iMax; i++) { - double a = out[i][0]; - double b = out[i][1]; - double c = sqrt(a * a + b * b); + int n; + for (int i = 0, iMax = FFT_SIZE / 2; i < iMax; i++) { + n = (i == 0)?1:i; + double a = out[n][0]; + double b = out[n][1]; + double c = sqrt(a * a + b * b); - double x = out[FFT_SIZE / 2 + i][0]; - double y = out[FFT_SIZE / 2 + i][1]; - double z = sqrt(x * x + y * y); + n = (i == FFT_SIZE/2)?(FFT_SIZE/2+1):i; + double x = out[FFT_SIZE / 2 + n][0]; + double y = out[FFT_SIZE / 2 + n][1]; + double z = sqrt(x * x + y * y); - fft_result[i] = (z); - fft_result[FFT_SIZE / 2 + i] = (c); - } + fft_result[i] = (z); + fft_result[FFT_SIZE / 2 + i] = (c); } float time_slice = (float) SRATE / (float) (BUF_SIZE / 2); diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index a18f38b..971daa0 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -85,13 +85,13 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) { switch (event.GetKeyCode()) { case WXK_RIGHT: freq = wxGetApp().getFrequency(); - freq += SRATE/2; + freq += SRATE / 2; wxGetApp().setFrequency(freq); ((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq)); break; case WXK_LEFT: freq = wxGetApp().getFrequency(); - freq -= SRATE/2; + freq -= SRATE / 2; wxGetApp().setFrequency(freq); ((wxFrame*) parent)->GetStatusBar()->SetStatusText(wxString::Format(wxT("Set center frequency: %i"), freq)); break; @@ -129,19 +129,20 @@ void WaterfallCanvas::setData(std::vector *data) { fft_result_maa.resize(FFT_SIZE); } - for (int j = 0; j < 2; j++) { - for (int i = 0, iMax = FFT_SIZE / 2; i < iMax; i++) { - double a = out[i][0]; - double b = out[i][1]; - double c = sqrt(a * a + b * b); + int n; + for (int i = 0, iMax = FFT_SIZE / 2; i < iMax; i++) { + n = (i == 0) ? 1 : i; + double a = out[n][0]; + double b = out[n][1]; + double c = sqrt(a * a + b * b); - double x = out[FFT_SIZE / 2 + i][0]; - double y = out[FFT_SIZE / 2 + i][1]; - double z = sqrt(x * x + y * y); + n = (i == FFT_SIZE / 2) ? (FFT_SIZE / 2 + 1) : i; + double x = out[FFT_SIZE / 2 + n][0]; + double y = out[FFT_SIZE / 2 + n][1]; + double z = sqrt(x * x + y * y); - fft_result[i] = (z); - fft_result[FFT_SIZE / 2 + i] = (c); - } + fft_result[i] = (z); + fft_result[FFT_SIZE / 2 + i] = (c); } float time_slice = (float) SRATE / (float) (BUF_SIZE / 2); @@ -192,7 +193,7 @@ void WaterfallCanvas::mouseMoved(wxMouseEvent& event) { if (mTracker.mouseDown()) { if (demod && mTracker.getDeltaMouseY()) { - int bwDiff = (int)(mTracker.getDeltaMouseY() * 100000.0); + int bwDiff = (int) (mTracker.getDeltaMouseY() * 100000.0); if (!demodBW) { demodBW = demod->getParams().bandwidth; @@ -249,7 +250,7 @@ void WaterfallCanvas::mouseReleased(wxMouseEvent& event) { DemodulatorInstance *demod = wxGetApp().getDemodTest(); - int freq = center_freq - (int)(0.5 * (float)SRATE) + (int)((float)pos * (float)SRATE); + int freq = center_freq - (int) (0.5 * (float) SRATE) + (int) ((float) pos * (float) SRATE); DemodulatorThreadCommand command; command.cmd = DemodulatorThreadCommand::SDR_THREAD_CMD_SET_FREQUENCY;