From 7bc49436b9f678bd552ddc19b58059760f2ae02c Mon Sep 17 00:00:00 2001 From: Aang23 Date: Mon, 18 May 2026 18:47:10 +0100 Subject: [PATCH] WIP DSP Stuff --- .../simple_gardner_recovery.cpp | 67 ++++++++++++++++++ .../clock_recovery/simple_gardner_recovery.h | 68 +++++++++++++++++++ .../dsp/clock_recovery/simple_zc_recovery.cpp | 2 +- src-core/dsp/ddc/ddc.cpp | 2 + src-core/dsp/ddc/ddc.h | 6 +- .../dsp/flowgraph/dsp_flowgraph_register.cpp | 2 + src-core/dsp/hier/gfsk_mod.h | 6 +- 7 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 src-core/dsp/clock_recovery/simple_gardner_recovery.cpp create mode 100644 src-core/dsp/clock_recovery/simple_gardner_recovery.h diff --git a/src-core/dsp/clock_recovery/simple_gardner_recovery.cpp b/src-core/dsp/clock_recovery/simple_gardner_recovery.cpp new file mode 100644 index 000000000..99044c8a7 --- /dev/null +++ b/src-core/dsp/clock_recovery/simple_gardner_recovery.cpp @@ -0,0 +1,67 @@ +#include "simple_gardner_recovery.h" + +namespace satdump +{ + namespace ndsp + { + SimpleGardnerRecoveryBlock::SimpleGardnerRecoveryBlock() : BlockSimple("simple_gardner_recovery_c", {{"in", DSP_SAMPLE_TYPE_CF32}}, {{"out", DSP_SAMPLE_TYPE_CF32}}) {} + + SimpleGardnerRecoveryBlock::~SimpleGardnerRecoveryBlock() {} + + void SimpleGardnerRecoveryBlock::init() {} + + bool SimpleGardnerRecoveryBlock::clock_recovery(complex_t sample, complex_t *sym) + { + bool fired = 0; + + // Down to next half-symbol + phase -= 1.0f; + + if (phase <= 0.0f) + { + // Interpolation either midpoint or + float frac = 1.0f + phase; + complex_t samp = last_sample + (sample - last_sample) * frac; + + if (is_mid) + { + // Midpoint sample (between two symbols) + mid = samp; + is_mid = false; + phase += period / 2.0f; + } + else + { + // On-time symbol sample + complex_t curr = samp; + + complex_t diff = curr - prev_sym; + float err = diff.real * mid.real + diff.imag * mid.imag; + + // Advance to next midpoint with error + phase += period / 2.0f - alpha * err; + + prev_sym = curr; + is_mid = true; + + *sym = curr; + fired = 1; + } + } + + last_sample = sample; + + return fired; + } + + uint32_t SimpleGardnerRecoveryBlock::process(complex_t *in, uint32_t nsamples, complex_t *out) + { + uint32_t oo = 0; + complex_t sym; + for (uint32_t i = 0; i < nsamples; i++) + if (clock_recovery(in[i], &sym)) + out[oo++] = sym; + return oo; + } + } // namespace ndsp +} // namespace satdump \ No newline at end of file diff --git a/src-core/dsp/clock_recovery/simple_gardner_recovery.h b/src-core/dsp/clock_recovery/simple_gardner_recovery.h new file mode 100644 index 000000000..ba1c4eb1e --- /dev/null +++ b/src-core/dsp/clock_recovery/simple_gardner_recovery.h @@ -0,0 +1,68 @@ +#pragma once + +#include "common/dsp/complex.h" +#include "dsp/block_simple.h" + +namespace satdump +{ + namespace ndsp + { + class SimpleGardnerRecoveryBlock : public BlockSimple + { + private: + float period = 4; + float alpha = 0.02f; + + complex_t last_sample = 0.0f; + + // Gardner stuff, since we need a midpoint + complex_t prev_sym = 0.0f; + complex_t mid = 0.0f; + bool is_mid = true; + + // Samples until next half-symbol + float phase = 0.0f; + + private: + bool clock_recovery(complex_t sample, complex_t *sym); + + public: + uint32_t process(complex_t *input, uint32_t nsamples, complex_t *output); + + public: + SimpleGardnerRecoveryBlock(); + ~SimpleGardnerRecoveryBlock(); + + void init(); + + nlohmann::ordered_json get_cfg_list() + { + nlohmann::ordered_json p; + add_param_simple(p, "sps", "float"); + add_param_simple(p, "alpha", "float"); + return p; + } + + nlohmann::json get_cfg(std::string key) + { + if (key == "sps") + return period; + else if (key == "alpha") + return alpha; + else + throw satdump_exception(key); + } + + Block::cfg_res_t set_cfg(std::string key, nlohmann::json v) + { + if (key == "sps") + period = v; + else if (key == "alpha") + alpha = v; + else + throw satdump_exception(key); + return Block::RES_OK; + } + }; + } // namespace ndsp +} // namespace satdump \ No newline at end of file diff --git a/src-core/dsp/clock_recovery/simple_zc_recovery.cpp b/src-core/dsp/clock_recovery/simple_zc_recovery.cpp index 72d06c71c..d83875787 100644 --- a/src-core/dsp/clock_recovery/simple_zc_recovery.cpp +++ b/src-core/dsp/clock_recovery/simple_zc_recovery.cpp @@ -5,7 +5,7 @@ namespace satdump { namespace ndsp { - SimpleZeroCrossingRecoveryBlock::SimpleZeroCrossingRecoveryBlock() : BlockSimple("simple_zc_recovery", {{"in", DSP_SAMPLE_TYPE_F32}}, {{"out", DSP_SAMPLE_TYPE_F32}}) {} + SimpleZeroCrossingRecoveryBlock::SimpleZeroCrossingRecoveryBlock() : BlockSimple("simple_zc_recovery_f", {{"in", DSP_SAMPLE_TYPE_F32}}, {{"out", DSP_SAMPLE_TYPE_F32}}) {} SimpleZeroCrossingRecoveryBlock::~SimpleZeroCrossingRecoveryBlock() {} diff --git a/src-core/dsp/ddc/ddc.cpp b/src-core/dsp/ddc/ddc.cpp index 63f838bbc..1d5a550b0 100644 --- a/src-core/dsp/ddc/ddc.cpp +++ b/src-core/dsp/ddc/ddc.cpp @@ -116,6 +116,7 @@ namespace satdump oblk.size = i->filter.process(oblk.getSamples(), iblk.size, oblk.getSamples()); +#if 0 if (i->decimation > 1) { int size_out = 0; @@ -156,6 +157,7 @@ namespace satdump { oblk.size = iblk.size; } +#endif o.fifo->wait_enqueue(oblk); } diff --git a/src-core/dsp/ddc/ddc.h b/src-core/dsp/ddc/ddc.h index 5bfe07152..e82cfcc5b 100644 --- a/src-core/dsp/ddc/ddc.h +++ b/src-core/dsp/ddc/ddc.h @@ -4,6 +4,7 @@ #include "core/exception.h" #include "dsp/block.h" #include "dsp/block_helpers.h" +#include "dsp/filter/decimating_fir.h" #include "dsp/filter/fir.h" #include #include @@ -125,12 +126,13 @@ namespace satdump if (bandwidth == 0) return; - auto v = calc_filter(sr, 0, bandwidth / 2, 30, 80); + auto v = calc_filter(sr, 0, bandwidth / 2, 300, 80); filter.set_cfg("taps", v /*dsp::firdes::low_pass(1, sr, bandwidth / 2, 1e3)*/); + filter.set_cfg("decimation", decimation); } - FIRBlock filter; + DecimatingFIRBlock filter; IOInfo(std::string id, bool forward_terminator, double f = 0, double b = 0, double d = 0) : id(id), forward_terminator(forward_terminator), frequency(f), bandwidth(b), decimation(d) {} }; diff --git a/src-core/dsp/flowgraph/dsp_flowgraph_register.cpp b/src-core/dsp/flowgraph/dsp_flowgraph_register.cpp index 596855540..1ced88f53 100644 --- a/src-core/dsp/flowgraph/dsp_flowgraph_register.cpp +++ b/src-core/dsp/flowgraph/dsp_flowgraph_register.cpp @@ -11,6 +11,7 @@ #include "dsp/agc/agc_fast.h" #include "dsp/clock_recovery/clock_recovery_mm.h" #include "dsp/clock_recovery/clock_recovery_mm_fast.h" +#include "dsp/clock_recovery/simple_gardner_recovery.h" #include "dsp/clock_recovery/simple_zc_recovery.h" #include "dsp/conv/char_to_float.h" #include "dsp/conv/complex_to_float.h" @@ -288,6 +289,7 @@ namespace satdump registerNodeSimple(flowgraph, "PLL/PLL Carrier Tracking"); registerNodeSimple(flowgraph, "Timing/Simple Zero-Crossing Clock Recovery FF"); + registerNodeSimple(flowgraph, "Timing/Simple Gardner Clock Recovery CC"); registerNodeSimple>(flowgraph, "Timing/Clock Recovery MM CC"); registerNodeSimple>(flowgraph, "Timing/Clock Recovery MM FF"); diff --git a/src-core/dsp/hier/gfsk_mod.h b/src-core/dsp/hier/gfsk_mod.h index ce21afad3..f89ee5d28 100644 --- a/src-core/dsp/hier/gfsk_mod.h +++ b/src-core/dsp/hier/gfsk_mod.h @@ -53,10 +53,10 @@ namespace satdump vco_blk.start(); } - void stop(bool stop_snow, bool force) + void stop(bool stop_snow = false, bool force = false) { - fir_blk.stop(stop_snow); - vco_blk.stop(stop_snow); + fir_blk.stop(stop_snow, force); + vco_blk.stop(stop_snow, force); } nlohmann::ordered_json get_cfg_list()