From 7120e848ef66120b6c7ff8f73ddea9d49f1169a8 Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Wed, 10 Jun 2020 18:52:07 +0200 Subject: [PATCH] added stuff idk --- CMakeLists.txt | 6 +++- src/cdsp/demodulation.h | 12 +++++++ src/cdsp/file.h | 20 ++++++++++++ src/cdsp/filter.h | 71 +++++++++++++++++++++++++++++++++++++++++ src/cdsp/generator.h | 31 ++++++++++++++++++ src/cdsp/hackrf.h | 42 ++++++++++++++++++++++++ src/cdsp/math.h | 4 +++ src/cdsp/stream.h | 12 ++++++- src/main_window.cpp | 20 +++++++----- src/signal_path.cpp | 20 ++++++++++++ src/signal_path.h | 26 +++++++++++++++ src/waterfall.cpp | 46 ++++++++++++++++++++++---- src/waterfall.h | 7 ++++ 13 files changed, 300 insertions(+), 17 deletions(-) create mode 100644 src/signal_path.cpp create mode 100644 src/signal_path.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d6422224..a82cd5f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,4 +30,8 @@ target_link_libraries(sdrpp PRIVATE FFTW3::fftw3) find_package(FFTW3f CONFIG REQUIRED) target_link_libraries(sdrpp PRIVATE FFTW3::fftw3f) find_package(FFTW3l CONFIG REQUIRED) -target_link_libraries(sdrpp PRIVATE FFTW3::fftw3l) \ No newline at end of file +target_link_libraries(sdrpp PRIVATE FFTW3::fftw3l) + +# PortAudio +find_package(portaudio CONFIG REQUIRED) +target_link_libraries(sdrpp PRIVATE portaudio portaudio_static) \ No newline at end of file diff --git a/src/cdsp/demodulation.h b/src/cdsp/demodulation.h index 7090a902..284f89b4 100644 --- a/src/cdsp/demodulation.h +++ b/src/cdsp/demodulation.h @@ -7,6 +7,10 @@ namespace cdsp { class FMDemodulator { public: + FMDemodulator() { + + } + FMDemodulator(stream* in, float deviation, long sampleRate, int bufferSize) : output(bufferSize * 2) { _input = in; _bufferSize = bufferSize; @@ -14,6 +18,14 @@ namespace cdsp { _phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation); } + void init(stream* in, float deviation, long sampleRate, int bufferSize) { + output.init(bufferSize * 2); + _input = in; + _bufferSize = bufferSize; + _phase = 0.0f; + _phasorSpeed = (2 * 3.1415926535) / (sampleRate / deviation); + } + void start() { _workerThread = std::thread(_worker, this); } diff --git a/src/cdsp/file.h b/src/cdsp/file.h index 536d0717..ad57bd33 100644 --- a/src/cdsp/file.h +++ b/src/cdsp/file.h @@ -14,11 +14,21 @@ namespace cdsp { class RawFileSource { public: + RawFileSource() { + + } + RawFileSource(std::string path, int bufferSize) : output(bufferSize * 2) { _bufferSize = bufferSize; _file = std::ifstream(path.c_str(), std::ios::in | std::ios::binary); } + void init(std::string path, int bufferSize) { + output.init(bufferSize * 2); + _bufferSize = bufferSize; + _file = std::ifstream(path.c_str(), std::ios::in | std::ios::binary); + } + void start() { _workerThread = std::thread(_worker, this); } @@ -50,12 +60,22 @@ namespace cdsp { class RawFileSink { public: + RawFileSink() { + + } + RawFileSink(std::string path, stream* in, int bufferSize) { _bufferSize = bufferSize; _input = in; _file = std::ofstream(path.c_str(), std::ios::out | std::ios::binary); } + void init(std::string path, stream* in, int bufferSize) { + _bufferSize = bufferSize; + _input = in; + _file = std::ofstream(path.c_str(), std::ios::out | std::ios::binary); + } + void start() { _workerThread = std::thread(_worker, this); } diff --git a/src/cdsp/filter.h b/src/cdsp/filter.h index b446839a..fb81ee28 100644 --- a/src/cdsp/filter.h +++ b/src/cdsp/filter.h @@ -7,6 +7,10 @@ namespace cdsp { class FIRFilter { public: + FIRFilter() { + + } + FIRFilter(stream* input, std::vector taps, int bufferSize) : output(bufferSize * 2) { _in = input; _bufferSize = bufferSize; @@ -15,6 +19,15 @@ namespace cdsp { _taps = taps; } + void init(stream* input, std::vector taps, int bufferSize) { + output.init(bufferSize * 2); + _in = input; + _bufferSize = bufferSize; + _tapCount = taps.size(); + delayBuf = new complex_t[_tapCount]; + _taps = taps; + } + void start() { _workerThread = std::thread(_worker, this); } @@ -66,9 +79,21 @@ namespace cdsp { class DCBiasRemover { public: + DCBiasRemover() { + + } + DCBiasRemover(stream* input, int bufferSize) : output(bufferSize * 2) { _in = input; _bufferSize = bufferSize; + bypass = false; + } + + void init(stream* input, int bufferSize) { + output.init(bufferSize * 2); + _in = input; + _bufferSize = bufferSize; + bypass = false; } void start() { @@ -76,6 +101,7 @@ namespace cdsp { } stream output; + bool bypass; private: static void _worker(DCBiasRemover* _this) { @@ -84,6 +110,10 @@ namespace cdsp { float qbias = 0.0f; while (true) { _this->_in->read(buf, _this->_bufferSize); + if (_this->bypass) { + _this->output.write(buf, _this->_bufferSize); + continue; + } for (int i = 0; i < _this->_bufferSize; i++) { ibias += buf[i].i; qbias += buf[i].q; @@ -102,4 +132,45 @@ namespace cdsp { int _bufferSize; std::thread _workerThread; }; + + class HandlerSink { + public: + HandlerSink() { + + } + + HandlerSink(stream* input, complex_t* buffer, int bufferSize, void handler(complex_t*)) { + _in = input; + _bufferSize = bufferSize; + _buffer = buffer; + _handler = handler; + } + + void init(stream* input, complex_t* buffer, int bufferSize, void handler(complex_t*)) { + _in = input; + _bufferSize = bufferSize; + _buffer = buffer; + _handler = handler; + } + + void start() { + _workerThread = std::thread(_worker, this); + } + + bool bypass; + + private: + static void _worker(HandlerSink* _this) { + while (true) { + _this->_in->read(_this->_buffer, _this->_bufferSize); + _this->_handler(_this->_buffer); + } + } + + stream* _in; + int _bufferSize; + complex_t* _buffer; + std::thread _workerThread; + void (*_handler)(complex_t*); + }; }; \ No newline at end of file diff --git a/src/cdsp/generator.h b/src/cdsp/generator.h index a99c8c01..02d58b23 100644 --- a/src/cdsp/generator.h +++ b/src/cdsp/generator.h @@ -6,12 +6,23 @@ namespace cdsp { class SineSource { public: + SineSource() { + + } + SineSource(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) { _bufferSize = bufferSize; _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); _phase = 0; } + void init(float frequency, long sampleRate, int bufferSize) { + output.init(bufferSize * 2); + _bufferSize = bufferSize; + _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); + _phase = 0; + } + void start() { _workerThread = std::thread(_worker, this); } @@ -39,10 +50,19 @@ namespace cdsp { class RandomSource { public: + RandomSource() { + + } + RandomSource(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) { _bufferSize = bufferSize; } + void init(float frequency, long sampleRate, int bufferSize) { + output.init(bufferSize * 2); + _bufferSize = bufferSize; + } + void start() { _workerThread = std::thread(_worker, this); } @@ -66,12 +86,23 @@ namespace cdsp { class ComplexSineSource { public: + ComplexSineSource() { + + } + ComplexSineSource(float frequency, long sampleRate, int bufferSize) : output(bufferSize * 2) { _bufferSize = bufferSize; _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); _phase = 0; } + void init(float frequency, long sampleRate, int bufferSize) { + output.init(bufferSize * 2); + _bufferSize = bufferSize; + _phasorSpeed = (2 * 3.1415926535) / (sampleRate / frequency); + _phase = 0; + } + void start() { _workerThread = std::thread(_worker, this); } diff --git a/src/cdsp/hackrf.h b/src/cdsp/hackrf.h index 6e68fe04..329e1478 100644 --- a/src/cdsp/hackrf.h +++ b/src/cdsp/hackrf.h @@ -16,11 +16,21 @@ namespace cdsp { class Complex2HackRF { public: + Complex2HackRF() { + + } + Complex2HackRF(stream* in, int bufferSize) : output(bufferSize * 2) { _input = in; _bufferSize = bufferSize; } + void init(stream* in, int bufferSize) { + output.init(bufferSize * 2); + _input = in; + _bufferSize = bufferSize; + } + stream output; void start() { @@ -48,11 +58,21 @@ namespace cdsp { class HackRF2Complex { public: + HackRF2Complex() { + + } + HackRF2Complex(stream* out, int bufferSize) : input(bufferSize * 2) { _output = out; _bufferSize = bufferSize; } + void init(stream* out, int bufferSize) { + input.init(bufferSize * 2); + _output = out; + _bufferSize = bufferSize; + } + void start() { _workerThread = std::thread(_worker, this); } @@ -81,12 +101,23 @@ namespace cdsp { class HackRFSink { public: + HackRFSink() { + + } + HackRFSink(hackrf_device* dev, int bufferSize, stream* input) : gen(input, bufferSize) { _input = input; _dev = dev; gen.start(); } + void init(hackrf_device* dev, int bufferSize, stream* input) { + gen.init(input, bufferSize); + _input = input; + _dev = dev; + gen.start(); + } + void start() { streaming = true; hackrf_start_tx(_dev, _worker, this); @@ -116,11 +147,22 @@ namespace cdsp { class HackRFSource { public: + HackRFSource() { + + } + HackRFSource(hackrf_device* dev, int bufferSize) : output(bufferSize * 2), gen(&output, bufferSize) { _dev = dev; gen.start(); } + void init(hackrf_device* dev, int bufferSize) { + output.init(bufferSize * 2); + gen.init(&output, bufferSize); + _dev = dev; + gen.start(); + } + void start() { streaming = true; hackrf_start_rx(_dev, _worker, this); diff --git a/src/cdsp/math.h b/src/cdsp/math.h index ece6a986..3dd435d1 100644 --- a/src/cdsp/math.h +++ b/src/cdsp/math.h @@ -6,6 +6,10 @@ namespace cdsp { class Multiplier { public: + Multiplier() { + + } + Multiplier(stream* a, stream* b, int bufferSize) : output(bufferSize * 2) { _a = a; _b = b; diff --git a/src/cdsp/stream.h b/src/cdsp/stream.h index 76e24701..fbdc5843 100644 --- a/src/cdsp/stream.h +++ b/src/cdsp/stream.h @@ -7,12 +7,22 @@ namespace cdsp { template class stream { public: + stream() { + + } + stream(int size) { _buffer = new T[size]; this->size = size; writec = 0; readc = size - 1; - //printf("Stream init\n"); + } + + void init(int size) { + _buffer = new T[size]; + this->size = size; + writec = 0; + readc = size - 1; } void read(T* data, int len) { diff --git a/src/main_window.cpp b/src/main_window.cpp index acdbaeb1..b7ab5c93 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -11,20 +11,22 @@ #include #include #include +#include std::thread worker; - std::mutex fft_mtx; ImGui::WaterFall wtf; - hackrf_device* dev; +fftwf_complex *fft_in, *fft_out; +fftwf_plan p; + +bool dcbias = true; void windowInit() { int fftSize = 8192; - //cdsp::complex_t* iqdata = new cdsp::complex_t[fftSize * 2]; - - fftwf_complex *fft_in, *fft_out; - fftwf_plan p; + wtf.bandWidth = 8000000; + wtf.range = 500000; + fft_in = (fftwf_complex*) fftw_malloc(sizeof(fftw_complex) * fftSize); fft_out = (fftwf_complex*) fftw_malloc(sizeof(fftw_complex) * fftSize); p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE); @@ -60,8 +62,6 @@ void windowInit() { dec.start(); mul.start(); - float val_a, val_b, val_c; - while (true) { mul.output.read((cdsp::complex_t*)fft_in, fftSize); @@ -75,6 +75,8 @@ void windowInit() { data[i] = (data[i - 3] + data[i - 2] + data[i - 1] + data[i]) / 4.0f; } + bias.bypass = !dcbias; + wtf.pushFFT(data, fftSize); data.clear(); } @@ -90,6 +92,7 @@ int _freq = 98000; void drawWindow() { if (freq != _freq) { _freq = freq; + wtf.centerFrequency = freq * 1000; hackrf_set_freq(dev, freq * 1000); } @@ -148,6 +151,7 @@ void drawWindow() { ImGui::Columns(1, "EndRadioModeColumns", false); ImGui::InputInt("Frequency (kHz)", &freq); + ImGui::Checkbox("DC Bias Removal", &dcbias); ImGui::EndGroup(); } diff --git a/src/signal_path.cpp b/src/signal_path.cpp new file mode 100644 index 00000000..2581f693 --- /dev/null +++ b/src/signal_path.cpp @@ -0,0 +1,20 @@ +#include + +SignalPath::SignalPath(cdsp::stream* source, float sampleRate, float fftRate, int fftSize, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::complex_t*)) : + dcBiasRemover(source, 64000), + fftBlockDec(&dcBiasRemover.output, (sampleRate / fftRate) - fftSize, fftSize), + fftSineSource(sampleRate / 2.0f, sampleRate, fftSize), + fftMul(&fftBlockDec.output, &fftSineSource.output, fftSize), + fftHandler(&fftMul.output, fftBuffer, fftSize, fftHandler) { + this->sampleRate = sampleRate; + this->fftRate = fftRate; + this->fftSize = fftSize; +} + +void SignalPath::start() { + dcBiasRemover.start(); + fftBlockDec.start(); + fftSineSource.start(); + fftMul.start(); + fftHandler.start(); +} \ No newline at end of file diff --git a/src/signal_path.h b/src/signal_path.h new file mode 100644 index 00000000..159ea78c --- /dev/null +++ b/src/signal_path.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include +#include + +class SignalPath { +public: + SignalPath(); + SignalPath(cdsp::stream* source, float sampleRate, float fftRate, int fftSize, cdsp::complex_t* fftBuffer, void fftHandler(cdsp::complex_t*)); + void start(); + void setSampleRate(float sampleRate); + void setDCBiasCorrection(bool enabled); + void setFFTRate(float rate); + +private: + cdsp::DCBiasRemover dcBiasRemover; + cdsp::BlockDecimator fftBlockDec; + cdsp::ComplexSineSource fftSineSource; + cdsp::Multiplier fftMul; + cdsp::HandlerSink fftHandler; + + float sampleRate; + float fftRate; + int fftSize; +}; \ No newline at end of file diff --git a/src/waterfall.cpp b/src/waterfall.cpp index fe48050d..2dbf2c9a 100644 --- a/src/waterfall.cpp +++ b/src/waterfall.cpp @@ -30,13 +30,16 @@ namespace ImGui { glGenTextures(1, &textureId); } - void drawFFT(ImGuiWindow* window, int width, int height, ImVec2 pos, std::vector& data) { + void WaterFall::drawFFT(ImGuiWindow* window, int width, int height, ImVec2 pos) { float lineHeight = (float)(height - 20 - 30) / 7.0f; char buf[100]; + int fftWidth = width - 50; + // Vertical scale for (int i = 0; i < 8; i++) { sprintf(buf, "%d", -i * 10); - window->DrawList->AddText(ImVec2(pos.x + 7, pos.y + (i * lineHeight) + 2), IM_COL32( 255, 255, 255, 255 ), buf); + ImVec2 txtSz = ImGui::CalcTextSize(buf); + window->DrawList->AddText(ImVec2(pos.x + 30 - txtSz.x, pos.y + (i * lineHeight) + 2), IM_COL32( 255, 255, 255, 255 ), buf); if (i == 7) { window->DrawList->AddLine(ImVec2(pos.x + 40, pos.y + (i * lineHeight) + 10), ImVec2(pos.x + width - 10, pos.y + (i * lineHeight) + 10), @@ -48,13 +51,36 @@ namespace ImGui { IM_COL32( 70, 70, 70, 255 ), 1.0f); } - int fftWidth = width - 50; + // Horizontal scale + float start = ceilf((centerFrequency - (bandWidth / 2)) / range) * range; + float end = centerFrequency + (bandWidth / 2); + float offsetStart = start - (centerFrequency - (bandWidth / 2)); + float pixelOffset = (offsetStart * fftWidth) / bandWidth; + float pixelWidth = (range * fftWidth) / bandWidth; + int count = 0; + for (; start < end; start += range) { + window->DrawList->AddLine(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + 10), + ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (7 * lineHeight) + 10), + IM_COL32( 70, 70, 70, 255 ), 1.0f); - int dataCount = data.size(); + window->DrawList->AddLine(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (7 * lineHeight) + 10), + ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40, pos.y + (7 * lineHeight) + 20), + IM_COL32( 255, 255, 255, 255 ), 1.0f); + + sprintf(buf, "%.1fM", start / 1000000.0f); + + ImVec2 txtSz = ImGui::CalcTextSize(buf); + + window->DrawList->AddText(ImVec2(pos.x + pixelOffset + (pixelWidth * count) + 40 - (txtSz.x / 2.0f), pos.y + (7 * lineHeight) + 25), IM_COL32( 255, 255, 255, 255 ), buf); + + count++; + } + + int dataCount = fftBuffer[0].size(); float multiplier = (float)dataCount / (float)fftWidth; for (int i = 1; i < fftWidth; i++) { - float a = (data[(int)((float)(i - 1) * multiplier)] / 10.0f) * lineHeight; - float b = (data[(int)((float)i * multiplier)] / 10.0f) * lineHeight; + float a = (fftBuffer[0][(int)((float)(i - 1) * multiplier)] / 10.0f) * lineHeight; + float b = (fftBuffer[0][(int)((float)i * multiplier)] / 10.0f) * lineHeight; window->DrawList->AddLine(ImVec2(pos.x + i + 39, pos.y - a), ImVec2(pos.x + i + 40, pos.y - b), IM_COL32( 0, 255, 255, 255 ), 1.0f); @@ -69,6 +95,12 @@ namespace ImGui { // IM_COL32( 0, 255, 255, 255 ), 1.0f); window->DrawList->AddLine(ImVec2(pos.x + 40, pos.y + 10), ImVec2(pos.x + 40, pos.y + (7 * lineHeight) + 10), IM_COL32( 255, 255, 255, 255 ), 1.0f); + + ImVec2 mPos = ImGui::GetMousePos(); + window->DrawList->AddRectFilled(ImVec2(mPos.x - 20, pos.y + 1), ImVec2(mPos.x + 20, pos.y + (7 * lineHeight) + 10), IM_COL32( 255, 255, 255, 50 )); + window->DrawList->AddLine(ImVec2(mPos.x, pos.y + 1), ImVec2(mPos.x, pos.y + (7 * lineHeight) + 10), IM_COL32( 255, 0, 0, 255 ), 1.0f); + + } uint32_t mapColor(float val) { @@ -161,7 +193,7 @@ namespace ImGui { if (fftBuffer.size() > height - 302) { fftBuffer.resize(height - 302); } - drawFFT(window, width, 300, vMin, fftBuffer[0]); + drawFFT(window, width, 300, vMin); drawWaterfall(window, width - 2, height - 302, ImVec2(vMin.x + 1, vMin.y + 301)); buf_mtx.unlock(); } diff --git a/src/waterfall.h b/src/waterfall.h index d8d7e1d7..1c987e94 100644 --- a/src/waterfall.h +++ b/src/waterfall.h @@ -13,13 +13,20 @@ namespace ImGui { void draw(); void pushFFT(std::vector data, int n); + float centerFrequency; + float bandWidth; + float range; + private: void drawWaterfall(ImGuiWindow* window, int width, int height, ImVec2 pos); + void drawFFT(ImGuiWindow* window, int width, int height, ImVec2 pos); std::vector> fftBuffer; bool newSamples; std::mutex buf_mtx; GLuint textureId; uint8_t* pixelBuffer; + + }; }; \ No newline at end of file