Added decimation

This commit is contained in:
Ryzerth 2021-07-26 21:18:06 +02:00
parent ffed602246
commit e62351c206
5 changed files with 195 additions and 8 deletions

View File

@ -47,13 +47,15 @@ namespace core {
GLFWwindow* window; GLFWwindow* window;
void setInputSampleRate(double samplerate) { void setInputSampleRate(double samplerate) {
sigpath::signalPath.sourceSampleRate = samplerate;
double effectiveSr = samplerate / ((double)(1 << sigpath::signalPath.decimation));
// NOTE: Zoom controls won't work // NOTE: Zoom controls won't work
spdlog::info("New DSP samplerate: {0}", samplerate); spdlog::info("New DSP samplerate: {0} (source samplerate is {1})", effectiveSr, samplerate);
gui::waterfall.setBandwidth(samplerate); gui::waterfall.setBandwidth(effectiveSr);
gui::waterfall.setViewOffset(0); gui::waterfall.setViewOffset(0);
gui::waterfall.setViewBandwidth(samplerate); gui::waterfall.setViewBandwidth(effectiveSr);
sigpath::signalPath.setSampleRate(samplerate); sigpath::signalPath.setSampleRate(effectiveSr);
gui::mainWindow.setViewBandwidthSlider(samplerate); gui::mainWindow.setViewBandwidthSlider(effectiveSr);
} }
}; };
@ -202,6 +204,7 @@ int sdrpp_main(int argc, char *argv[]) {
defConfig["showMenu"] = true; defConfig["showMenu"] = true;
defConfig["showWaterfall"] = true; defConfig["showWaterfall"] = true;
defConfig["source"] = ""; defConfig["source"] = "";
defConfig["decimationPower"] = 0;
defConfig["streams"]["Radio"]["muted"] = false; defConfig["streams"]["Radio"]["muted"] = false;
defConfig["streams"]["Radio"]["sink"] = "Audio"; defConfig["streams"]["Radio"]["sink"] = "Audio";

108
core/src/dsp/decimation.h Normal file
View File

@ -0,0 +1,108 @@
#pragma once
#include <dsp/block.h>
#include <dsp/stream.h>
#include <dsp/types.h>
#include <dsp/window.h>
namespace dsp {
template <class T>
class HalfDecimator : public generic_block<HalfDecimator<T>> {
public:
HalfDecimator() {}
HalfDecimator(stream<T>* in, dsp::filter_window::generic_window* window) { init(in, window); }
~HalfDecimator() {
if (!generic_block<HalfDecimator<T>>::_block_init) { return; }
generic_block<HalfDecimator<T>>::stop();
volk_free(buffer);
volk_free(taps);
generic_block<HalfDecimator<T>>::_block_init = false;
}
void init(stream<T>* in, dsp::filter_window::generic_window* window) {
_in = in;
tapCount = window->getTapCount();
taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment());
window->createTaps(taps, tapCount);
buffer = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T) * 2, volk_get_alignment());
bufStart = &buffer[tapCount];
generic_block<HalfDecimator<T>>::registerInput(_in);
generic_block<HalfDecimator<T>>::registerOutput(&out);
generic_block<HalfDecimator<T>>::_block_init = true;
}
void setInput(stream<T>* in) {
assert(generic_block<HalfDecimator<T>>::_block_init);
std::lock_guard<std::mutex> lck(generic_block<HalfDecimator<T>>::ctrlMtx);
generic_block<HalfDecimator<T>>::tempStop();
generic_block<HalfDecimator<T>>::unregisterInput(_in);
_in = in;
generic_block<HalfDecimator<T>>::registerInput(_in);
generic_block<HalfDecimator<T>>::tempStart();
}
void updateWindow(dsp::filter_window::generic_window* window) {
assert(generic_block<HalfDecimator<T>>::_block_init);
std::lock_guard<std::mutex> lck(generic_block<HalfDecimator<T>>::ctrlMtx);
_window = window;
volk_free(taps);
tapCount = window->getTapCount();
taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment());
bufStart = &buffer[tapCount];
window->createTaps(taps, tapCount);
}
int run() {
int count = _in->read();
if (count < 0) { return -1; }
generic_block<HalfDecimator<T>>::ctrlMtx.lock();
memcpy(bufStart, _in->readBuf, count * sizeof(T));
_in->flush();
int inIndex = _inIndex;
int outIndex = 0;
if constexpr (std::is_same_v<T, float>) {
while (inIndex < count) {
volk_32f_x2_dot_prod_32f((float*)&out.writeBuf[outIndex], (float*)&buffer[inIndex+1], taps, tapCount);
inIndex += 2;
outIndex++;
}
}
if constexpr (std::is_same_v<T, complex_t>) {
while (inIndex < count) {
volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&out.writeBuf[outIndex], (lv_32fc_t*)&buffer[inIndex+1], taps, tapCount);
inIndex += 2;
outIndex++;
}
}
_inIndex = inIndex - count;
if (!out.swap(outIndex)) { return -1; }
memmove(buffer, &buffer[count], tapCount * sizeof(T));
generic_block<HalfDecimator<T>>::ctrlMtx.unlock();
return count;
}
stream<T> out;
private:
stream<T>* _in;
dsp::filter_window::generic_window* _window;
T* bufStart;
T* buffer;
int tapCount;
float* taps;
int _inIndex = 0;
};
}

View File

@ -11,6 +11,7 @@ namespace sourecmenu {
int sourceId = 0; int sourceId = 0;
double customOffset = 0.0; double customOffset = 0.0;
double effectiveOffset = 0.0; double effectiveOffset = 0.0;
int decimationPower = 0;
EventHandler<std::string> sourceRegisteredHandler; EventHandler<std::string> sourceRegisteredHandler;
EventHandler<std::string> sourceUnregisterHandler; EventHandler<std::string> sourceUnregisterHandler;
@ -39,6 +40,14 @@ namespace sourecmenu {
"Ku LNB (9750MHz)\0" "Ku LNB (9750MHz)\0"
"Ku LNB (10700MHz)\0"; "Ku LNB (10700MHz)\0";
const char* decimationStages = "None\0"
"2\0"
"4\0"
"8\0"
"16\0"
"32\0"
"64\0";
void updateOffset() { void updateOffset() {
if (offsetMode == OFFSET_MODE_CUSTOM) { effectiveOffset = customOffset; } if (offsetMode == OFFSET_MODE_CUSTOM) { effectiveOffset = customOffset; }
else if (offsetMode == OFFSET_MODE_SPYVERTER) { effectiveOffset = 120000000; } // 120MHz Up-conversion else if (offsetMode == OFFSET_MODE_SPYVERTER) { effectiveOffset = 120000000; } // 120MHz Up-conversion
@ -113,10 +122,12 @@ namespace sourecmenu {
std::string selected = core::configManager.conf["source"]; std::string selected = core::configManager.conf["source"];
customOffset = core::configManager.conf["offset"]; customOffset = core::configManager.conf["offset"];
offsetMode = core::configManager.conf["offsetMode"]; offsetMode = core::configManager.conf["offsetMode"];
decimationPower = core::configManager.conf["decimationPower"];
updateOffset(); updateOffset();
refreshSources(); refreshSources();
selectSource(selected); selectSource(selected);
sigpath::signalPath.setDecimation(decimationPower);
sourceRegisteredHandler.handler = onSourceRegistered; sourceRegisteredHandler.handler = onSourceRegistered;
sourceUnregisterHandler.handler = onSourceUnregister; sourceUnregisterHandler.handler = onSourceUnregister;
@ -130,8 +141,9 @@ namespace sourecmenu {
void draw(void* ctx) { void draw(void* ctx) {
float itemWidth = ImGui::GetContentRegionAvailWidth(); float itemWidth = ImGui::GetContentRegionAvailWidth();
bool running = gui::mainWindow.sdrIsRunning();
if (gui::mainWindow.sdrIsRunning()) { style::beginDisabled(); } if (running) { style::beginDisabled(); }
ImGui::SetNextItemWidth(itemWidth); ImGui::SetNextItemWidth(itemWidth);
if (ImGui::Combo("##source", &sourceId, sourceNamesTxt.c_str())) { if (ImGui::Combo("##source", &sourceId, sourceNamesTxt.c_str())) {
@ -141,7 +153,7 @@ namespace sourecmenu {
core::configManager.release(true); core::configManager.release(true);
} }
if (gui::mainWindow.sdrIsRunning()) { style::endDisabled(); } if (running) { style::endDisabled(); }
sigpath::sourceManager.showSelectedMenu(); sigpath::sourceManager.showSelectedMenu();
@ -171,5 +183,17 @@ namespace sourecmenu {
ImGui::InputDouble("##freq_offset", &effectiveOffset, 1.0, 100.0); ImGui::InputDouble("##freq_offset", &effectiveOffset, 1.0, 100.0);
style::endDisabled(); style::endDisabled();
} }
if (running) { style::beginDisabled(); }
ImGui::Text("Decimation");
ImGui::SameLine();
ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX());
if (ImGui::Combo("##source_decim", &decimationPower, decimationStages)) {
sigpath::signalPath.setDecimation(decimationPower);
core::configManager.acquire();
core::configManager.conf["decimationPower"] = decimationPower;
core::configManager.release(true);
}
if (running) { style::endDisabled(); }
} }
} }

View File

@ -1,4 +1,5 @@
#include <signal_path/dsp.h> #include <signal_path/dsp.h>
#include <core.h>
SignalPath::SignalPath() { SignalPath::SignalPath() {
@ -6,10 +7,13 @@ SignalPath::SignalPath() {
void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream<dsp::complex_t>* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*,int,void*), void* fftHandlerCtx) { void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream<dsp::complex_t>* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*,int,void*), void* fftHandlerCtx) {
this->sampleRate = sampleRate; this->sampleRate = sampleRate;
this->sourceSampleRate = sampleRate;
this->fftRate = fftRate; this->fftRate = fftRate;
this->fftSize = fftSize; this->fftSize = fftSize;
inputBlockSize = sampleRate / 200.0f; inputBlockSize = sampleRate / 200.0f;
halfBandWindow.init(1000000, 200000, 4000000);
// split.init(input); // split.init(input);
inputBuffer.init(input); inputBuffer.init(input);
split.init(&inputBuffer.out); split.init(&inputBuffer.out);
@ -47,17 +51,25 @@ double SignalPath::getSampleRate() {
} }
void SignalPath::start() { void SignalPath::start() {
for (auto& decimator : decimators) {
decimator->start();
}
inputBuffer.start(); inputBuffer.start();
split.start(); split.start();
reshape.start(); reshape.start();
fftHandlerSink.start(); fftHandlerSink.start();
running = true;
} }
void SignalPath::stop() { void SignalPath::stop() {
for (auto& decimator : decimators) {
decimator->stop();
}
inputBuffer.stop(); inputBuffer.stop();
split.stop(); split.stop();
reshape.stop(); reshape.stop();
fftHandlerSink.stop(); fftHandlerSink.stop();
running = false;
} }
dsp::VFO* SignalPath::addVFO(std::string name, double outSampleRate, double bandwidth, double offset) { dsp::VFO* SignalPath::addVFO(std::string name, double outSampleRate, double bandwidth, double offset) {
@ -87,7 +99,6 @@ void SignalPath::removeVFO(std::string name) {
} }
void SignalPath::setInput(dsp::stream<dsp::complex_t>* input) { void SignalPath::setInput(dsp::stream<dsp::complex_t>* input) {
// split.setInput(input);
inputBuffer.setInput(input); inputBuffer.setInput(input);
} }
@ -121,3 +132,37 @@ void SignalPath::stopFFT() {
void SignalPath::setBuffering(bool enabled) { void SignalPath::setBuffering(bool enabled) {
inputBuffer.bypass = !enabled; inputBuffer.bypass = !enabled;
} }
void SignalPath::setDecimation(int dec) {
decimation = dec;
// Stop existing decimators
if (!decimators.empty()) {
for (auto& decimator : decimators) {
decimator->stop();
delete decimator;
}
}
decimators.clear();
// If no decimation, reconnect
if (!dec) {
split.setInput(&inputBuffer.out);
core::setInputSampleRate(sourceSampleRate);
return;
}
// Create new decimators
if (running) { split.stop(); }
for (int i = 0; i < dec; i++) {
dsp::HalfDecimator<dsp::complex_t>* decimator = new dsp::HalfDecimator<dsp::complex_t>((i == 0) ? &inputBuffer.out : &decimators[i-1]->out, &halfBandWindow);
if (running) { decimator->start(); }
// TODO: ONLY start if running
decimators.push_back(decimator);
}
split.setInput(&decimators[decimators.size()-1]->out);
if (running) { split.start(); }
// Update the DSP sample rate
core::setInputSampleRate(sourceSampleRate);
}

View File

@ -3,6 +3,7 @@
#include <dsp/vfo.h> #include <dsp/vfo.h>
#include <map> #include <map>
#include <dsp/sink.h> #include <dsp/sink.h>
#include <dsp/decimation.h>
class SignalPath { class SignalPath {
public: public:
@ -21,8 +22,11 @@ public:
void startFFT(); void startFFT();
void stopFFT(); void stopFFT();
void setBuffering(bool enabled); void setBuffering(bool enabled);
void setDecimation(int dec);
dsp::SampleFrameBuffer<dsp::complex_t> inputBuffer; dsp::SampleFrameBuffer<dsp::complex_t> inputBuffer;
double sourceSampleRate = 0;
int decimation = 0;
private: private:
struct VFO_t { struct VFO_t {
@ -39,10 +43,13 @@ private:
// VFO // VFO
std::map<std::string, VFO_t> vfos; std::map<std::string, VFO_t> vfos;
std::vector<dsp::HalfDecimator<dsp::complex_t>*> decimators;
dsp::filter_window::BlackmanWindow halfBandWindow;
double sampleRate; double sampleRate;
double fftRate; double fftRate;
int fftSize; int fftSize;
int inputBlockSize; int inputBlockSize;
bool bufferingEnabled = false; bool bufferingEnabled = false;
bool running = false;
}; };