From e3db19b16ad17aa5b7e2b1e002c8df912888695f Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Sat, 12 Dec 2020 05:34:58 +0100 Subject: [PATCH] Bugfixed + performance improvements to the waterfall --- .gitignore | 3 +- CMakeLists.txt | 2 +- audio_sink/CMakeLists.txt | 2 +- core/CMakeLists.txt | 2 +- core/src/config.h | 3 - core/src/core.cpp | 2 +- core/src/gui/main_window.cpp | 36 +++++++----- core/src/gui/widgets/waterfall.cpp | 90 ++++++++++++++++++++++-------- core/src/gui/widgets/waterfall.h | 17 ++++-- demo/CMakeLists.txt | 2 +- file_source/CMakeLists.txt | 2 +- plutosdr_source/CMakeLists.txt | 2 +- radio/CMakeLists.txt | 2 +- recorder/CMakeLists.txt | 2 +- root_dev/config.json | 8 +-- root_dev/soapy_source_config.json | 6 +- rtl_tcp_source/CMakeLists.txt | 2 +- rx888_source/CMakeLists.txt | 2 +- soapy_source/CMakeLists.txt | 2 +- source_demo/CMakeLists.txt | 2 +- 20 files changed, 122 insertions(+), 67 deletions(-) diff --git a/.gitignore b/.gitignore index 114ee785..142816ce 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ build/ *.zip *.wav .DS_Store -sdrpp_v0.2.5_beta_x64 \ No newline at end of file +sdrpp_v0.2.5_beta_x64 +sdrpp_v0.2.5_beta_x64_new_wf \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index a55fbea5..34b3e419 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ add_subdirectory("plutosdr_source") #add_subdirectory("demo") if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17") endif (MSVC) diff --git a/audio_sink/CMakeLists.txt b/audio_sink/CMakeLists.txt index ce0091fb..ac75a4b9 100644 --- a/audio_sink/CMakeLists.txt +++ b/audio_sink/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(audio_sink) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index a3400a9f..290e8320 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -3,7 +3,7 @@ project(sdrpp_core) # Set compiler options if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) else() set(CMAKE_CXX_FLAGS "-g -O3 -std=c++17 -fpermissive") diff --git a/core/src/config.h b/core/src/config.h index 5db967f0..f6933eb9 100644 --- a/core/src/config.h +++ b/core/src/config.h @@ -8,11 +8,8 @@ using nlohmann::json; #define DEV_BUILD - #define SDRPP_RESOURCE_DIR "/usr/local/" - - #ifndef ROOT_DIR #ifdef DEV_BUILD #define ROOT_DIR "../root_dev" diff --git a/core/src/core.cpp b/core/src/core.cpp index d3997fa8..cc70054f 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -79,7 +79,7 @@ int sdrpp_main() { defConfig["bandColors"]["military"] = "#FFFF00FF"; defConfig["bandPlan"] = "General"; defConfig["bandPlanEnabled"] = true; - defConfig["centerTuning"] = true; + defConfig["centerTuning"] = false; defConfig["fftHeight"] = 300; defConfig["frequency"] = 100000000.0; defConfig["max"] = 0.0; diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index ad3db15d..1b4d66a8 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -35,12 +35,12 @@ std::thread worker; std::mutex fft_mtx; fftwf_complex *fft_in, *fft_out; fftwf_plan p; +float* tempFFT; +float* FFTdata; char buf[1024]; int fftSize = 8192 * 8; -std::vector _data; -std::vector fftTaps; void fftHandler(dsp::complex_t* samples, int count, void* ctx) { if (count < fftSize) { return; @@ -49,19 +49,24 @@ void fftHandler(dsp::complex_t* samples, int count, void* ctx) { fftwf_execute(p); int half = fftSize / 2; - for (int i = 0; i < half; i++) { - _data.push_back(log10(std::abs(std::complex(fft_out[half + i][0], fft_out[half + i][1])) / (float)fftSize) * 10.0); - } - for (int i = 0; i < half; i++) { - _data.push_back(log10(std::abs(std::complex(fft_out[i][0], fft_out[i][1])) / (float)fftSize) * 10.0); - } + volk_32fc_s32f_power_spectrum_32f(tempFFT, (lv_32fc_t*)fft_out, fftSize, fftSize); + volk_32f_s32f_multiply_32f(FFTdata, tempFFT, 0.5f, fftSize); - for (int i = 5; i < fftSize; i++) { - _data[i] = (_data[i - 4] + _data[i - 3] + _data[i - 2] + _data[i - 1] + _data[i]) / 5.0; - } + memcpy(tempFFT, &FFTdata[half], half * sizeof(float)); + memmove(&FFTdata[half], FFTdata, half * sizeof(float)); + memcpy(FFTdata, tempFFT, half * sizeof(float)); - gui::waterfall.pushFFT(_data, fftSize); - _data.clear(); + float* fftBuf = gui::waterfall.getFFTBuffer(); + if (fftBuf == NULL) { + gui::waterfall.pushFFT(); + return; + } + float last = FFTdata[0]; + for (int i = 0; i < fftSize; i++) { + last = (FFTdata[i] * 0.1f) + (last * 0.9f); + fftBuf[i] = last; + } + gui::waterfall.pushFFT(); } watcher freq((uint64_t)90500000); @@ -87,6 +92,10 @@ bool demoWindow = false; void windowInit() { LoadingScreen::show("Initializing UI"); gui::waterfall.init(); + gui::waterfall.setRawFFTSize(fftSize); + + tempFFT = new float[fftSize]; + FFTdata = new float[fftSize]; credits::init(); @@ -167,7 +176,6 @@ void windowInit() { // TODO for 0.2.6 // Add a module add/remove/change order menu - // Change the way fft samples are stored to make it less CPU intensive // Update UI settings LoadingScreen::show("Loading configuration"); diff --git a/core/src/gui/widgets/waterfall.cpp b/core/src/gui/widgets/waterfall.cpp index f668e9e0..3618a6f1 100644 --- a/core/src/gui/widgets/waterfall.cpp +++ b/core/src/gui/widgets/waterfall.cpp @@ -23,7 +23,7 @@ float COLOR_MAP[][3] = { {0x4A, 0x00, 0x00} }; -void doZoom(int offset, int width, int outWidth, std::vector data, float* out) { +void doZoom(int offset, int width, int outWidth, float* data, float* out) { // NOTE: REMOVE THAT SHIT, IT'S JUST A HACKY FIX if (offset < 0) { offset = 0; @@ -34,7 +34,7 @@ void doZoom(int offset, int width, int outWidth, std::vector data, float* float factor = (float)width / (float)outWidth; for (int i = 0; i < outWidth; i++) { - out[i] = data[offset + ((float)i * factor)]; + out[i] = data[(int)(offset + ((float)i * factor))]; } } @@ -281,7 +281,11 @@ namespace ImGui { lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0); upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0); - updateWaterfallFb(); + + if (viewBandwidth != wholeBandwidth) { + updateAllVFOs(); + updateWaterfallFb(); + } } else { lastDrag = 0; @@ -289,25 +293,26 @@ namespace ImGui { } void WaterFall::updateWaterfallFb() { - if (!waterfallVisible) { + if (!waterfallVisible || rawFFTs == NULL) { return; } double offsetRatio = viewOffset / (wholeBandwidth / 2.0); int drawDataSize; int drawDataStart; - int count = std::min(waterfallHeight, rawFFTs.size()); + // TODO: Maybe put on the stack for faster alloc? float* tempData = new float[dataWidth]; float pixel; float dataRange = waterfallMax - waterfallMin; - int size; - for (int i = 0; i < count; i++) { - size = rawFFTs[i].size(); - drawDataSize = (viewBandwidth / wholeBandwidth) * size; - drawDataStart = (((double)size / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2); - doZoom(drawDataStart, drawDataSize, dataWidth, rawFFTs[i], tempData); - for (int j = 0; j < dataWidth; j++) { - pixel = (std::clamp(tempData[j], waterfallMin, waterfallMax) - waterfallMin) / dataRange; - waterfallFb[(i * dataWidth) + j] = waterfallPallet[(int)(pixel * (WATERFALL_RESOLUTION - 1))]; + int count = std::min(waterfallHeight, fftLines); + if (rawFFTs != NULL) { + for (int i = 0; i < count; i++) { + drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize; + drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2); + doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[((i + currentFFTLine) % waterfallHeight) * rawFFTSize], tempData); + for (int j = 0; j < dataWidth; j++) { + pixel = (std::clamp(tempData[j], waterfallMin, waterfallMax) - waterfallMin) / dataRange; + waterfallFb[(i * dataWidth) + j] = waterfallPallet[(int)(pixel * (WATERFALL_RESOLUTION - 1))]; + } } } delete[] tempData; @@ -391,6 +396,8 @@ namespace ImGui { return; } + int lastWaterfallHeight = waterfallHeight; + if (waterfallVisible) { FFTAreaHeight = std::min(FFTAreaHeight, widgetSize.y - 50); fftHeight = FFTAreaHeight - 50; @@ -402,12 +409,28 @@ namespace ImGui { dataWidth = widgetSize.x - 60.0; delete[] latestFFT; - if (waterfallVisible) { - delete[] waterfallFb; + // Raw FFT resize + fftLines = std::min(fftLines, waterfallHeight); + if (rawFFTs != NULL) { + if (currentFFTLine != 0) { + float* tempWF = new float[currentFFTLine * rawFFTSize]; + int moveCount = lastWaterfallHeight - currentFFTLine; + memcpy(tempWF, rawFFTs, currentFFTLine * rawFFTSize * sizeof(float)); + memmove(rawFFTs, &rawFFTs[currentFFTLine * rawFFTSize], moveCount * rawFFTSize * sizeof(float)); + memcpy(&rawFFTs[moveCount * rawFFTSize], tempWF, currentFFTLine * rawFFTSize * sizeof(float)); + delete[] tempWF; + } + currentFFTLine = 0; + rawFFTs = (float*)realloc(rawFFTs, waterfallHeight * rawFFTSize * sizeof(float)); } + else { + rawFFTs = (float*)malloc(waterfallHeight * rawFFTSize * sizeof(float)); + } + // ============== latestFFT = new float[dataWidth]; if (waterfallVisible) { + delete[] waterfallFb; waterfallFb = new uint32_t[dataWidth * waterfallHeight]; memset(waterfallFb, 0, dataWidth * waterfallHeight * sizeof(uint32_t)); } @@ -504,17 +527,23 @@ namespace ImGui { buf_mtx.unlock(); } - void WaterFall::pushFFT(std::vector data, int n) { + float* WaterFall::getFFTBuffer() { + if (rawFFTs == NULL) { return NULL; } buf_mtx.lock(); + currentFFTLine--; + fftLines++; + currentFFTLine = ((currentFFTLine + waterfallHeight) % waterfallHeight); + fftLines = std::min(fftLines, waterfallHeight); + return &rawFFTs[currentFFTLine * rawFFTSize]; + } + + void WaterFall::pushFFT() { + if (rawFFTs == NULL) { return; } double offsetRatio = viewOffset / (wholeBandwidth / 2.0); - int drawDataSize = (viewBandwidth / wholeBandwidth) * data.size(); - int drawDataStart = (((double)data.size() / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2); + int drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize; + int drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2); - doZoom(drawDataStart, drawDataSize, dataWidth, data, latestFFT); - rawFFTs.insert(rawFFTs.begin(), data); - if (rawFFTs.size() > waterfallHeight + 300) { - rawFFTs.resize(waterfallHeight); - } + doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[currentFFTLine * rawFFTSize], latestFFT); if (waterfallVisible) { memmove(&waterfallFb[dataWidth], waterfallFb, dataWidth * (waterfallHeight - 1) * sizeof(uint32_t)); @@ -683,6 +712,19 @@ namespace ImGui { } } + void WaterFall::setRawFFTSize(int size, bool lock) { + if (lock) { buf_mtx.lock(); } + rawFFTSize = size; + if (rawFFTs != NULL) { + rawFFTs = (float*)realloc(rawFFTs, rawFFTSize * waterfallHeight * sizeof(float)); + } + else { + rawFFTs = (float*)malloc(rawFFTSize * waterfallHeight * sizeof(float)); + } + memset(rawFFTs, 0, rawFFTSize * waterfallHeight * sizeof(float)); + if (lock) { buf_mtx.unlock(); } + } + void WaterfallVFO::setOffset(double offset) { generalOffset = offset; if (reference == REF_CENTER) { diff --git a/core/src/gui/widgets/waterfall.h b/core/src/gui/widgets/waterfall.h index 11d27ef3..08edbf23 100644 --- a/core/src/gui/widgets/waterfall.h +++ b/core/src/gui/widgets/waterfall.h @@ -53,7 +53,8 @@ namespace ImGui { void init(); void draw(); - void pushFFT(std::vector data, int n); + float* getFFTBuffer(); + void pushFFT(); void updatePallette(float colors[][3], int colorCount); @@ -97,6 +98,8 @@ namespace ImGui { void setFFTHeight(int height); int getFFTHeight(); + void setRawFFTSize(int size, bool lock = true); + bool centerFreqMoved = false; bool vfoFreqChanged = false; bool bandplanEnabled = false; @@ -155,9 +158,9 @@ namespace ImGui { int maxVSteps; int maxHSteps; - int dataWidth; // Width of the FFT and waterfall - int fftHeight; // Height of the fft graph - int waterfallHeight; // Height of the waterfall + int dataWidth; // Width of the FFT and waterfall + int fftHeight; // Height of the fft graph + int waterfallHeight = 0; // Height of the waterfall double viewBandwidth; double viewOffset; @@ -180,8 +183,12 @@ namespace ImGui { float waterfallMin; float waterfallMax; - std::vector> rawFFTs; + //std::vector> rawFFTs; + int rawFFTSize; + float* rawFFTs = NULL; float* latestFFT; + int currentFFTLine = 0; + int fftLines = 0; uint32_t* waterfallFb; diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index 6c15e42d..aed95f1a 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(demo) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/file_source/CMakeLists.txt b/file_source/CMakeLists.txt index e6046129..a74403db 100644 --- a/file_source/CMakeLists.txt +++ b/file_source/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(file_source) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/plutosdr_source/CMakeLists.txt b/plutosdr_source/CMakeLists.txt index 291f7d7b..260ede75 100644 --- a/plutosdr_source/CMakeLists.txt +++ b/plutosdr_source/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(plutosdr_source) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/radio/CMakeLists.txt b/radio/CMakeLists.txt index 2a26d88c..9070abfb 100644 --- a/radio/CMakeLists.txt +++ b/radio/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(radio) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/recorder/CMakeLists.txt b/recorder/CMakeLists.txt index 9d6af4f2..9b4d2e20 100644 --- a/recorder/CMakeLists.txt +++ b/recorder/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(recorder) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/root_dev/config.json b/root_dev/config.json index 0a166c44..d8b11f03 100644 --- a/root_dev/config.json +++ b/root_dev/config.json @@ -3,7 +3,7 @@ "bandPlanEnabled": true, "centerTuning": false, "fftHeight": 300, - "frequency": 103600000, + "frequency": 99000000, "max": 0.0, "maximized": false, "menuOrder": [ @@ -17,7 +17,7 @@ "Display" ], "menuWidth": 300, - "min": -66.17647552490234, + "min": -55.147056579589844, "moduleInstances": { "Audio Sink": "audio_sink", "PlutoSDR Source": "plutosdr_source", @@ -36,12 +36,12 @@ ], "offset": 0.0, "showWaterfall": true, - "source": "PlutoSDR", + "source": "SoapySDR", "streams": { "Radio": { "muted": false, "sink": "Audio", - "volume": 0.6785714030265808 + "volume": 0.545918345451355 }, "Radio 1": { "muted": false, diff --git a/root_dev/soapy_source_config.json b/root_dev/soapy_source_config.json index 9bef9c32..6c9fbb52 100644 --- a/root_dev/soapy_source_config.json +++ b/root_dev/soapy_source_config.json @@ -1,5 +1,5 @@ { - "device": "AirSpy HF+ [c852435de0224af7]", + "device": "HackRF One #0 901868dc282c8f8b", "devices": { "": { "agc": false, @@ -32,10 +32,10 @@ "HackRF One #0 901868dc282c8f8b": { "gains": { "AMP": 0.0, - "LNA": 23.415000915527344, + "LNA": 24.503000259399414, "VGA": 16.332000732421875 }, - "sampleRate": 8000000.0 + "sampleRate": 2000000.0 }, "Microphone (Realtek High Definition Audio)": { "sampleRate": 96000.0 diff --git a/rtl_tcp_source/CMakeLists.txt b/rtl_tcp_source/CMakeLists.txt index 20796ec7..b7b5dc5f 100644 --- a/rtl_tcp_source/CMakeLists.txt +++ b/rtl_tcp_source/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(rtl_tcp_source) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/rx888_source/CMakeLists.txt b/rx888_source/CMakeLists.txt index 4922e29f..c017217e 100644 --- a/rx888_source/CMakeLists.txt +++ b/rx888_source/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(rx888_source) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/soapy_source/CMakeLists.txt b/soapy_source/CMakeLists.txt index 33281da7..5647f24d 100644 --- a/soapy_source/CMakeLists.txt +++ b/soapy_source/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(soapy_source) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC) diff --git a/source_demo/CMakeLists.txt b/source_demo/CMakeLists.txt index 7e4fcbfa..56147b8f 100644 --- a/source_demo/CMakeLists.txt +++ b/source_demo/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(soapy) if (MSVC) - set(CMAKE_CXX_FLAGS "-O2 /std:c++17") + set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc") else() set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") endif (MSVC)