mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
70 lines
No EOL
2.4 KiB
C++
70 lines
No EOL
2.4 KiB
C++
#include "costas_loop.h"
|
|
|
|
namespace dsp
|
|
{
|
|
CostasLoopBlock::CostasLoopBlock(std::shared_ptr<dsp::stream<complex_t>> input, float loop_bw, unsigned int order, float freq_limit)
|
|
: Block(input), order(order), loop_bw(loop_bw), freq_limit_min(-freq_limit), freq_limit_max(freq_limit)
|
|
{
|
|
float damping = sqrtf(2.0f) / 2.0f;
|
|
float denom = (1.0 + 2.0 * damping * loop_bw + loop_bw * loop_bw);
|
|
alpha = (4 * damping * loop_bw) / denom;
|
|
beta = (4 * loop_bw * loop_bw) / denom;
|
|
}
|
|
|
|
void CostasLoopBlock::work()
|
|
{
|
|
int nsamples = input_stream->read();
|
|
if (nsamples <= 0)
|
|
{
|
|
input_stream->flush();
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < nsamples; i++)
|
|
{
|
|
// Mix input & VCO
|
|
tmp_val = input_stream->readBuf[i] * complex_t(cosf(-phase), sinf(-phase));
|
|
output_stream->writeBuf[i] = tmp_val;
|
|
|
|
// Calculate error
|
|
switch (order)
|
|
{
|
|
case 2: // Order 2, BPSK
|
|
error = tmp_val.real * tmp_val.imag;
|
|
break;
|
|
case 4: // Order 4, QPSK
|
|
error = (tmp_val.real > 0.0f ? 1.0f : -1.0f) * tmp_val.imag - (tmp_val.imag > 0.0f ? 1.0f : -1.0f) * tmp_val.real;
|
|
break;
|
|
case 8: // Order 8, 8-PSK
|
|
const float K = (sqrtf(2.0) - 1);
|
|
if (fabsf(tmp_val.real) >= fabsf(tmp_val.imag))
|
|
error = ((tmp_val.real > 0.0f ? 1.0f : -1.0f) * tmp_val.imag - (tmp_val.imag > 0.0f ? 1.0f : -1.0f) * tmp_val.real * K);
|
|
else
|
|
error = ((tmp_val.real > 0.0f ? 1.0f : -1.0f) * tmp_val.imag * K - (tmp_val.imag > 0.0f ? 1.0f : -1.0f) * tmp_val.real);
|
|
break;
|
|
}
|
|
|
|
// Clip error
|
|
error = branchless_clip(error, 1.0);
|
|
|
|
// Compute new freq and phase.
|
|
freq += beta * error;
|
|
phase += freq + alpha * error;
|
|
|
|
// Wrap phase
|
|
while (phase > (2 * M_PI))
|
|
phase -= 2 * M_PI;
|
|
while (phase < (-2 * M_PI))
|
|
phase += 2 * M_PI;
|
|
|
|
// Clamp freq
|
|
if (freq > freq_limit_max)
|
|
freq = freq_limit_max;
|
|
if (freq < freq_limit_min)
|
|
freq = freq_limit_min;
|
|
}
|
|
|
|
input_stream->flush();
|
|
output_stream->swap(nsamples);
|
|
}
|
|
} |