mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-06 10:47:34 +01:00
Added decimation
This commit is contained in:
parent
ffed602246
commit
e62351c206
@ -47,13 +47,15 @@ namespace core {
|
||||
GLFWwindow* window;
|
||||
|
||||
void setInputSampleRate(double samplerate) {
|
||||
sigpath::signalPath.sourceSampleRate = samplerate;
|
||||
double effectiveSr = samplerate / ((double)(1 << sigpath::signalPath.decimation));
|
||||
// NOTE: Zoom controls won't work
|
||||
spdlog::info("New DSP samplerate: {0}", samplerate);
|
||||
gui::waterfall.setBandwidth(samplerate);
|
||||
spdlog::info("New DSP samplerate: {0} (source samplerate is {1})", effectiveSr, samplerate);
|
||||
gui::waterfall.setBandwidth(effectiveSr);
|
||||
gui::waterfall.setViewOffset(0);
|
||||
gui::waterfall.setViewBandwidth(samplerate);
|
||||
sigpath::signalPath.setSampleRate(samplerate);
|
||||
gui::mainWindow.setViewBandwidthSlider(samplerate);
|
||||
gui::waterfall.setViewBandwidth(effectiveSr);
|
||||
sigpath::signalPath.setSampleRate(effectiveSr);
|
||||
gui::mainWindow.setViewBandwidthSlider(effectiveSr);
|
||||
}
|
||||
};
|
||||
|
||||
@ -202,6 +204,7 @@ int sdrpp_main(int argc, char *argv[]) {
|
||||
defConfig["showMenu"] = true;
|
||||
defConfig["showWaterfall"] = true;
|
||||
defConfig["source"] = "";
|
||||
defConfig["decimationPower"] = 0;
|
||||
|
||||
defConfig["streams"]["Radio"]["muted"] = false;
|
||||
defConfig["streams"]["Radio"]["sink"] = "Audio";
|
||||
|
108
core/src/dsp/decimation.h
Normal file
108
core/src/dsp/decimation.h
Normal 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;
|
||||
|
||||
};
|
||||
}
|
@ -11,6 +11,7 @@ namespace sourecmenu {
|
||||
int sourceId = 0;
|
||||
double customOffset = 0.0;
|
||||
double effectiveOffset = 0.0;
|
||||
int decimationPower = 0;
|
||||
|
||||
EventHandler<std::string> sourceRegisteredHandler;
|
||||
EventHandler<std::string> sourceUnregisterHandler;
|
||||
@ -39,6 +40,14 @@ namespace sourecmenu {
|
||||
"Ku LNB (9750MHz)\0"
|
||||
"Ku LNB (10700MHz)\0";
|
||||
|
||||
const char* decimationStages = "None\0"
|
||||
"2\0"
|
||||
"4\0"
|
||||
"8\0"
|
||||
"16\0"
|
||||
"32\0"
|
||||
"64\0";
|
||||
|
||||
void updateOffset() {
|
||||
if (offsetMode == OFFSET_MODE_CUSTOM) { effectiveOffset = customOffset; }
|
||||
else if (offsetMode == OFFSET_MODE_SPYVERTER) { effectiveOffset = 120000000; } // 120MHz Up-conversion
|
||||
@ -113,10 +122,12 @@ namespace sourecmenu {
|
||||
std::string selected = core::configManager.conf["source"];
|
||||
customOffset = core::configManager.conf["offset"];
|
||||
offsetMode = core::configManager.conf["offsetMode"];
|
||||
decimationPower = core::configManager.conf["decimationPower"];
|
||||
updateOffset();
|
||||
|
||||
refreshSources();
|
||||
selectSource(selected);
|
||||
sigpath::signalPath.setDecimation(decimationPower);
|
||||
|
||||
sourceRegisteredHandler.handler = onSourceRegistered;
|
||||
sourceUnregisterHandler.handler = onSourceUnregister;
|
||||
@ -130,8 +141,9 @@ namespace sourecmenu {
|
||||
|
||||
void draw(void* ctx) {
|
||||
float itemWidth = ImGui::GetContentRegionAvailWidth();
|
||||
bool running = gui::mainWindow.sdrIsRunning();
|
||||
|
||||
if (gui::mainWindow.sdrIsRunning()) { style::beginDisabled(); }
|
||||
if (running) { style::beginDisabled(); }
|
||||
|
||||
ImGui::SetNextItemWidth(itemWidth);
|
||||
if (ImGui::Combo("##source", &sourceId, sourceNamesTxt.c_str())) {
|
||||
@ -141,7 +153,7 @@ namespace sourecmenu {
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
if (gui::mainWindow.sdrIsRunning()) { style::endDisabled(); }
|
||||
if (running) { style::endDisabled(); }
|
||||
|
||||
sigpath::sourceManager.showSelectedMenu();
|
||||
|
||||
@ -171,5 +183,17 @@ namespace sourecmenu {
|
||||
ImGui::InputDouble("##freq_offset", &effectiveOffset, 1.0, 100.0);
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <signal_path/dsp.h>
|
||||
#include <core.h>
|
||||
|
||||
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) {
|
||||
this->sampleRate = sampleRate;
|
||||
this->sourceSampleRate = sampleRate;
|
||||
this->fftRate = fftRate;
|
||||
this->fftSize = fftSize;
|
||||
inputBlockSize = sampleRate / 200.0f;
|
||||
|
||||
halfBandWindow.init(1000000, 200000, 4000000);
|
||||
|
||||
// split.init(input);
|
||||
inputBuffer.init(input);
|
||||
split.init(&inputBuffer.out);
|
||||
@ -47,17 +51,25 @@ double SignalPath::getSampleRate() {
|
||||
}
|
||||
|
||||
void SignalPath::start() {
|
||||
for (auto& decimator : decimators) {
|
||||
decimator->start();
|
||||
}
|
||||
inputBuffer.start();
|
||||
split.start();
|
||||
reshape.start();
|
||||
fftHandlerSink.start();
|
||||
running = true;
|
||||
}
|
||||
|
||||
void SignalPath::stop() {
|
||||
for (auto& decimator : decimators) {
|
||||
decimator->stop();
|
||||
}
|
||||
inputBuffer.stop();
|
||||
split.stop();
|
||||
reshape.stop();
|
||||
fftHandlerSink.stop();
|
||||
running = false;
|
||||
}
|
||||
|
||||
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) {
|
||||
// split.setInput(input);
|
||||
inputBuffer.setInput(input);
|
||||
}
|
||||
|
||||
@ -120,4 +131,38 @@ void SignalPath::stopFFT() {
|
||||
|
||||
void SignalPath::setBuffering(bool 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);
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
#include <dsp/vfo.h>
|
||||
#include <map>
|
||||
#include <dsp/sink.h>
|
||||
#include <dsp/decimation.h>
|
||||
|
||||
class SignalPath {
|
||||
public:
|
||||
@ -21,8 +22,11 @@ public:
|
||||
void startFFT();
|
||||
void stopFFT();
|
||||
void setBuffering(bool enabled);
|
||||
void setDecimation(int dec);
|
||||
|
||||
dsp::SampleFrameBuffer<dsp::complex_t> inputBuffer;
|
||||
double sourceSampleRate = 0;
|
||||
int decimation = 0;
|
||||
|
||||
private:
|
||||
struct VFO_t {
|
||||
@ -39,10 +43,13 @@ private:
|
||||
|
||||
// VFO
|
||||
std::map<std::string, VFO_t> vfos;
|
||||
std::vector<dsp::HalfDecimator<dsp::complex_t>*> decimators;
|
||||
dsp::filter_window::BlackmanWindow halfBandWindow;
|
||||
|
||||
double sampleRate;
|
||||
double fftRate;
|
||||
int fftSize;
|
||||
int inputBlockSize;
|
||||
bool bufferingEnabled = false;
|
||||
bool running = false;
|
||||
};
|
Loading…
Reference in New Issue
Block a user