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.
This commit is contained in:
Charles J. Cliffe 2014-11-29 13:58:20 -05:00
parent 93b20454d3
commit 499e411048
10 changed files with 184 additions and 66 deletions

View File

@ -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

View File

@ -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();

View File

@ -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)

View File

@ -1,6 +1,6 @@
#pragma once
#define BUF_SIZE (16 * 32 * 128)
#define BUF_SIZE (16384*6)
#define SRATE 2000000
#define FFT_SIZE 2048

78
src/sdr/SDRPostThread.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "SDRPostThread.h"
#include "CubicSDRDefs.h"
#include <vector>
#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;
}

43
src/sdr/SDRPostThread.h Normal file
View File

@ -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<SDRThreadIQDataQueue*> iqDataOutQueue;
std::atomic<SDRThreadIQDataQueue*> iqDataInQueue;
std::atomic<SDRThreadIQDataQueue*> iqVisualQueue;
std::vector<DemodulatorInstance *> demodulators;
std::atomic<bool> terminated;
iirfilt_crcf dcFilter;
};

View File

@ -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);
}
}
}
}

View File

@ -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<SDRThreadCommandQueue*> m_pQueue;
std::atomic<SDRThreadIQDataQueue*> iqDataOutQueue;
std::vector<DemodulatorInstance *> demodulators;
std::atomic<bool> terminated;
};

View File

@ -117,19 +117,20 @@ void SpectrumCanvas::setData(std::vector<signed char> *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);

View File

@ -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<signed char> *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;