WIP DSP Stuff

This commit is contained in:
Aang23 2026-05-18 18:47:10 +01:00
parent 5c7a7edb1a
commit 7bc49436b9
7 changed files with 147 additions and 6 deletions

View file

@ -0,0 +1,67 @@
#include "simple_gardner_recovery.h"
namespace satdump
{
namespace ndsp
{
SimpleGardnerRecoveryBlock::SimpleGardnerRecoveryBlock() : BlockSimple<complex_t, complex_t>("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

View file

@ -0,0 +1,68 @@
#pragma once
#include "common/dsp/complex.h"
#include "dsp/block_simple.h"
namespace satdump
{
namespace ndsp
{
class SimpleGardnerRecoveryBlock : public BlockSimple<complex_t, complex_t>
{
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

View file

@ -5,7 +5,7 @@ namespace satdump
{
namespace ndsp
{
SimpleZeroCrossingRecoveryBlock::SimpleZeroCrossingRecoveryBlock() : BlockSimple<float, float>("simple_zc_recovery", {{"in", DSP_SAMPLE_TYPE_F32}}, {{"out", DSP_SAMPLE_TYPE_F32}}) {}
SimpleZeroCrossingRecoveryBlock::SimpleZeroCrossingRecoveryBlock() : BlockSimple<float, float>("simple_zc_recovery_f", {{"in", DSP_SAMPLE_TYPE_F32}}, {{"out", DSP_SAMPLE_TYPE_F32}}) {}
SimpleZeroCrossingRecoveryBlock::~SimpleZeroCrossingRecoveryBlock() {}

View file

@ -116,6 +116,7 @@ namespace satdump
oblk.size = i->filter.process(oblk.getSamples<complex_t>(), iblk.size, oblk.getSamples<complex_t>());
#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);
}

View file

@ -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 <memory>
#include <mutex>
@ -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<complex_t> filter;
DecimatingFIRBlock<complex_t> 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) {}
};

View file

@ -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<ndsp::PLLCarrierTrackingBlock>(flowgraph, "PLL/PLL Carrier Tracking");
registerNodeSimple<ndsp::SimpleZeroCrossingRecoveryBlock>(flowgraph, "Timing/Simple Zero-Crossing Clock Recovery FF");
registerNodeSimple<ndsp::SimpleGardnerRecoveryBlock>(flowgraph, "Timing/Simple Gardner Clock Recovery CC");
registerNodeSimple<ndsp::MMClockRecoveryBlock<complex_t>>(flowgraph, "Timing/Clock Recovery MM CC");
registerNodeSimple<ndsp::MMClockRecoveryBlock<float>>(flowgraph, "Timing/Clock Recovery MM FF");

View file

@ -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()