Bugfixed + performance improvements to the waterfall

This commit is contained in:
Ryzerth 2020-12-12 05:34:58 +01:00
parent 774663d70d
commit e3db19b16a
20 changed files with 122 additions and 67 deletions

3
.gitignore vendored
View File

@ -6,4 +6,5 @@ build/
*.zip *.zip
*.wav *.wav
.DS_Store .DS_Store
sdrpp_v0.2.5_beta_x64 sdrpp_v0.2.5_beta_x64
sdrpp_v0.2.5_beta_x64_new_wf

View File

@ -16,7 +16,7 @@ add_subdirectory("plutosdr_source")
#add_subdirectory("demo") #add_subdirectory("demo")
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17") set(CMAKE_CXX_FLAGS "-O3 -std=c++17")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(audio_sink) project(audio_sink)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -3,7 +3,7 @@ project(sdrpp_core)
# Set compiler options # Set compiler options
if (MSVC) 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) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
else() else()
set(CMAKE_CXX_FLAGS "-g -O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-g -O3 -std=c++17 -fpermissive")

View File

@ -8,11 +8,8 @@ using nlohmann::json;
#define DEV_BUILD #define DEV_BUILD
#define SDRPP_RESOURCE_DIR "/usr/local/" #define SDRPP_RESOURCE_DIR "/usr/local/"
#ifndef ROOT_DIR #ifndef ROOT_DIR
#ifdef DEV_BUILD #ifdef DEV_BUILD
#define ROOT_DIR "../root_dev" #define ROOT_DIR "../root_dev"

View File

@ -79,7 +79,7 @@ int sdrpp_main() {
defConfig["bandColors"]["military"] = "#FFFF00FF"; defConfig["bandColors"]["military"] = "#FFFF00FF";
defConfig["bandPlan"] = "General"; defConfig["bandPlan"] = "General";
defConfig["bandPlanEnabled"] = true; defConfig["bandPlanEnabled"] = true;
defConfig["centerTuning"] = true; defConfig["centerTuning"] = false;
defConfig["fftHeight"] = 300; defConfig["fftHeight"] = 300;
defConfig["frequency"] = 100000000.0; defConfig["frequency"] = 100000000.0;
defConfig["max"] = 0.0; defConfig["max"] = 0.0;

View File

@ -35,12 +35,12 @@ std::thread worker;
std::mutex fft_mtx; std::mutex fft_mtx;
fftwf_complex *fft_in, *fft_out; fftwf_complex *fft_in, *fft_out;
fftwf_plan p; fftwf_plan p;
float* tempFFT;
float* FFTdata;
char buf[1024]; char buf[1024];
int fftSize = 8192 * 8; int fftSize = 8192 * 8;
std::vector<float> _data;
std::vector<float> fftTaps;
void fftHandler(dsp::complex_t* samples, int count, void* ctx) { void fftHandler(dsp::complex_t* samples, int count, void* ctx) {
if (count < fftSize) { if (count < fftSize) {
return; return;
@ -49,19 +49,24 @@ void fftHandler(dsp::complex_t* samples, int count, void* ctx) {
fftwf_execute(p); fftwf_execute(p);
int half = fftSize / 2; int half = fftSize / 2;
for (int i = 0; i < half; i++) { volk_32fc_s32f_power_spectrum_32f(tempFFT, (lv_32fc_t*)fft_out, fftSize, fftSize);
_data.push_back(log10(std::abs(std::complex<float>(fft_out[half + i][0], fft_out[half + i][1])) / (float)fftSize) * 10.0); volk_32f_s32f_multiply_32f(FFTdata, tempFFT, 0.5f, fftSize);
}
for (int i = 0; i < half; i++) {
_data.push_back(log10(std::abs(std::complex<float>(fft_out[i][0], fft_out[i][1])) / (float)fftSize) * 10.0);
}
for (int i = 5; i < fftSize; i++) { memcpy(tempFFT, &FFTdata[half], half * sizeof(float));
_data[i] = (_data[i - 4] + _data[i - 3] + _data[i - 2] + _data[i - 1] + _data[i]) / 5.0; memmove(&FFTdata[half], FFTdata, half * sizeof(float));
} memcpy(FFTdata, tempFFT, half * sizeof(float));
gui::waterfall.pushFFT(_data, fftSize); float* fftBuf = gui::waterfall.getFFTBuffer();
_data.clear(); 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<uint64_t> freq((uint64_t)90500000); watcher<uint64_t> freq((uint64_t)90500000);
@ -87,6 +92,10 @@ bool demoWindow = false;
void windowInit() { void windowInit() {
LoadingScreen::show("Initializing UI"); LoadingScreen::show("Initializing UI");
gui::waterfall.init(); gui::waterfall.init();
gui::waterfall.setRawFFTSize(fftSize);
tempFFT = new float[fftSize];
FFTdata = new float[fftSize];
credits::init(); credits::init();
@ -167,7 +176,6 @@ void windowInit() {
// TODO for 0.2.6 // TODO for 0.2.6
// Add a module add/remove/change order menu // Add a module add/remove/change order menu
// Change the way fft samples are stored to make it less CPU intensive
// Update UI settings // Update UI settings
LoadingScreen::show("Loading configuration"); LoadingScreen::show("Loading configuration");

View File

@ -23,7 +23,7 @@ float COLOR_MAP[][3] = {
{0x4A, 0x00, 0x00} {0x4A, 0x00, 0x00}
}; };
void doZoom(int offset, int width, int outWidth, std::vector<float> 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 // NOTE: REMOVE THAT SHIT, IT'S JUST A HACKY FIX
if (offset < 0) { if (offset < 0) {
offset = 0; offset = 0;
@ -34,7 +34,7 @@ void doZoom(int offset, int width, int outWidth, std::vector<float> data, float*
float factor = (float)width / (float)outWidth; float factor = (float)width / (float)outWidth;
for (int i = 0; i < outWidth; i++) { 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); lowerFreq = (centerFreq + viewOffset) - (viewBandwidth / 2.0);
upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0); upperFreq = (centerFreq + viewOffset) + (viewBandwidth / 2.0);
updateWaterfallFb();
if (viewBandwidth != wholeBandwidth) {
updateAllVFOs();
updateWaterfallFb();
}
} }
else { else {
lastDrag = 0; lastDrag = 0;
@ -289,25 +293,26 @@ namespace ImGui {
} }
void WaterFall::updateWaterfallFb() { void WaterFall::updateWaterfallFb() {
if (!waterfallVisible) { if (!waterfallVisible || rawFFTs == NULL) {
return; return;
} }
double offsetRatio = viewOffset / (wholeBandwidth / 2.0); double offsetRatio = viewOffset / (wholeBandwidth / 2.0);
int drawDataSize; int drawDataSize;
int drawDataStart; int drawDataStart;
int count = std::min<int>(waterfallHeight, rawFFTs.size()); // TODO: Maybe put on the stack for faster alloc?
float* tempData = new float[dataWidth]; float* tempData = new float[dataWidth];
float pixel; float pixel;
float dataRange = waterfallMax - waterfallMin; float dataRange = waterfallMax - waterfallMin;
int size; int count = std::min<float>(waterfallHeight, fftLines);
for (int i = 0; i < count; i++) { if (rawFFTs != NULL) {
size = rawFFTs[i].size(); for (int i = 0; i < count; i++) {
drawDataSize = (viewBandwidth / wholeBandwidth) * size; drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize;
drawDataStart = (((double)size / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2); drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2);
doZoom(drawDataStart, drawDataSize, dataWidth, rawFFTs[i], tempData); doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[((i + currentFFTLine) % waterfallHeight) * rawFFTSize], tempData);
for (int j = 0; j < dataWidth; j++) { for (int j = 0; j < dataWidth; j++) {
pixel = (std::clamp<float>(tempData[j], waterfallMin, waterfallMax) - waterfallMin) / dataRange; pixel = (std::clamp<float>(tempData[j], waterfallMin, waterfallMax) - waterfallMin) / dataRange;
waterfallFb[(i * dataWidth) + j] = waterfallPallet[(int)(pixel * (WATERFALL_RESOLUTION - 1))]; waterfallFb[(i * dataWidth) + j] = waterfallPallet[(int)(pixel * (WATERFALL_RESOLUTION - 1))];
}
} }
} }
delete[] tempData; delete[] tempData;
@ -391,6 +396,8 @@ namespace ImGui {
return; return;
} }
int lastWaterfallHeight = waterfallHeight;
if (waterfallVisible) { if (waterfallVisible) {
FFTAreaHeight = std::min<int>(FFTAreaHeight, widgetSize.y - 50); FFTAreaHeight = std::min<int>(FFTAreaHeight, widgetSize.y - 50);
fftHeight = FFTAreaHeight - 50; fftHeight = FFTAreaHeight - 50;
@ -402,12 +409,28 @@ namespace ImGui {
dataWidth = widgetSize.x - 60.0; dataWidth = widgetSize.x - 60.0;
delete[] latestFFT; delete[] latestFFT;
if (waterfallVisible) { // Raw FFT resize
delete[] waterfallFb; fftLines = std::min<int>(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]; latestFFT = new float[dataWidth];
if (waterfallVisible) { if (waterfallVisible) {
delete[] waterfallFb;
waterfallFb = new uint32_t[dataWidth * waterfallHeight]; waterfallFb = new uint32_t[dataWidth * waterfallHeight];
memset(waterfallFb, 0, dataWidth * waterfallHeight * sizeof(uint32_t)); memset(waterfallFb, 0, dataWidth * waterfallHeight * sizeof(uint32_t));
} }
@ -504,17 +527,23 @@ namespace ImGui {
buf_mtx.unlock(); buf_mtx.unlock();
} }
void WaterFall::pushFFT(std::vector<float> data, int n) { float* WaterFall::getFFTBuffer() {
if (rawFFTs == NULL) { return NULL; }
buf_mtx.lock(); buf_mtx.lock();
currentFFTLine--;
fftLines++;
currentFFTLine = ((currentFFTLine + waterfallHeight) % waterfallHeight);
fftLines = std::min<float>(fftLines, waterfallHeight);
return &rawFFTs[currentFFTLine * rawFFTSize];
}
void WaterFall::pushFFT() {
if (rawFFTs == NULL) { return; }
double offsetRatio = viewOffset / (wholeBandwidth / 2.0); double offsetRatio = viewOffset / (wholeBandwidth / 2.0);
int drawDataSize = (viewBandwidth / wholeBandwidth) * data.size(); int drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize;
int drawDataStart = (((double)data.size() / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2); int drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2);
doZoom(drawDataStart, drawDataSize, dataWidth, data, latestFFT); doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[currentFFTLine * rawFFTSize], latestFFT);
rawFFTs.insert(rawFFTs.begin(), data);
if (rawFFTs.size() > waterfallHeight + 300) {
rawFFTs.resize(waterfallHeight);
}
if (waterfallVisible) { if (waterfallVisible) {
memmove(&waterfallFb[dataWidth], waterfallFb, dataWidth * (waterfallHeight - 1) * sizeof(uint32_t)); 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) { void WaterfallVFO::setOffset(double offset) {
generalOffset = offset; generalOffset = offset;
if (reference == REF_CENTER) { if (reference == REF_CENTER) {

View File

@ -53,7 +53,8 @@ namespace ImGui {
void init(); void init();
void draw(); void draw();
void pushFFT(std::vector<float> data, int n); float* getFFTBuffer();
void pushFFT();
void updatePallette(float colors[][3], int colorCount); void updatePallette(float colors[][3], int colorCount);
@ -97,6 +98,8 @@ namespace ImGui {
void setFFTHeight(int height); void setFFTHeight(int height);
int getFFTHeight(); int getFFTHeight();
void setRawFFTSize(int size, bool lock = true);
bool centerFreqMoved = false; bool centerFreqMoved = false;
bool vfoFreqChanged = false; bool vfoFreqChanged = false;
bool bandplanEnabled = false; bool bandplanEnabled = false;
@ -155,9 +158,9 @@ namespace ImGui {
int maxVSteps; int maxVSteps;
int maxHSteps; int maxHSteps;
int dataWidth; // Width of the FFT and waterfall int dataWidth; // Width of the FFT and waterfall
int fftHeight; // Height of the fft graph int fftHeight; // Height of the fft graph
int waterfallHeight; // Height of the waterfall int waterfallHeight = 0; // Height of the waterfall
double viewBandwidth; double viewBandwidth;
double viewOffset; double viewOffset;
@ -180,8 +183,12 @@ namespace ImGui {
float waterfallMin; float waterfallMin;
float waterfallMax; float waterfallMax;
std::vector<std::vector<float>> rawFFTs; //std::vector<std::vector<float>> rawFFTs;
int rawFFTSize;
float* rawFFTs = NULL;
float* latestFFT; float* latestFFT;
int currentFFTLine = 0;
int fftLines = 0;
uint32_t* waterfallFb; uint32_t* waterfallFb;

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(demo) project(demo)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(file_source) project(file_source)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(plutosdr_source) project(plutosdr_source)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(radio) project(radio)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(recorder) project(recorder)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -3,7 +3,7 @@
"bandPlanEnabled": true, "bandPlanEnabled": true,
"centerTuning": false, "centerTuning": false,
"fftHeight": 300, "fftHeight": 300,
"frequency": 103600000, "frequency": 99000000,
"max": 0.0, "max": 0.0,
"maximized": false, "maximized": false,
"menuOrder": [ "menuOrder": [
@ -17,7 +17,7 @@
"Display" "Display"
], ],
"menuWidth": 300, "menuWidth": 300,
"min": -66.17647552490234, "min": -55.147056579589844,
"moduleInstances": { "moduleInstances": {
"Audio Sink": "audio_sink", "Audio Sink": "audio_sink",
"PlutoSDR Source": "plutosdr_source", "PlutoSDR Source": "plutosdr_source",
@ -36,12 +36,12 @@
], ],
"offset": 0.0, "offset": 0.0,
"showWaterfall": true, "showWaterfall": true,
"source": "PlutoSDR", "source": "SoapySDR",
"streams": { "streams": {
"Radio": { "Radio": {
"muted": false, "muted": false,
"sink": "Audio", "sink": "Audio",
"volume": 0.6785714030265808 "volume": 0.545918345451355
}, },
"Radio 1": { "Radio 1": {
"muted": false, "muted": false,

View File

@ -1,5 +1,5 @@
{ {
"device": "AirSpy HF+ [c852435de0224af7]", "device": "HackRF One #0 901868dc282c8f8b",
"devices": { "devices": {
"": { "": {
"agc": false, "agc": false,
@ -32,10 +32,10 @@
"HackRF One #0 901868dc282c8f8b": { "HackRF One #0 901868dc282c8f8b": {
"gains": { "gains": {
"AMP": 0.0, "AMP": 0.0,
"LNA": 23.415000915527344, "LNA": 24.503000259399414,
"VGA": 16.332000732421875 "VGA": 16.332000732421875
}, },
"sampleRate": 8000000.0 "sampleRate": 2000000.0
}, },
"Microphone (Realtek High Definition Audio)": { "Microphone (Realtek High Definition Audio)": {
"sampleRate": 96000.0 "sampleRate": 96000.0

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(rtl_tcp_source) project(rtl_tcp_source)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(rx888_source) project(rx888_source)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(soapy_source) project(soapy_source)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(soapy) project(soapy)
if (MSVC) if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17") set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc")
else() else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive") set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -fpermissive")
endif (MSVC) endif (MSVC)