2022-05-29 22:09:09 +00:00
|
|
|
// Copyright 2021-2022 Mobilinkd LLC.
|
2021-06-21 01:37:40 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2022-01-23 20:23:20 +00:00
|
|
|
#include "KalmanFilter.h"
|
|
|
|
#include "Log.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
2021-06-21 01:37:40 +00:00
|
|
|
#include <array>
|
2022-01-23 20:23:20 +00:00
|
|
|
#include <cassert>
|
2021-06-21 01:37:40 +00:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
2022-01-23 20:23:20 +00:00
|
|
|
#include <iterator>
|
2021-06-21 01:37:40 +00:00
|
|
|
#include <numeric>
|
|
|
|
|
|
|
|
namespace mobilinkd { namespace m17 {
|
|
|
|
|
|
|
|
|
2022-01-23 20:23:20 +00:00
|
|
|
template <typename FloatType = float, size_t SamplesPerSymbol = 10>
|
|
|
|
struct ClockRecovery
|
|
|
|
{
|
|
|
|
KalmanFilter<FloatType, SamplesPerSymbol> kf_;
|
|
|
|
size_t count_ = 0;
|
|
|
|
int8_t sample_index_ = 0;
|
|
|
|
FloatType clock_estimate_ = 0.;
|
|
|
|
FloatType sample_estimate_ = 0.;
|
2021-06-21 01:37:40 +00:00
|
|
|
|
2022-01-23 20:23:20 +00:00
|
|
|
void reset(FloatType z)
|
2021-06-21 01:37:40 +00:00
|
|
|
{
|
2022-01-23 20:23:20 +00:00
|
|
|
INFO("CR Reset");
|
|
|
|
kf_.reset(z);
|
|
|
|
count_ = 0;
|
|
|
|
sample_index_ = z;
|
|
|
|
clock_estimate_ = 0.;
|
2021-06-21 01:37:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 20:23:20 +00:00
|
|
|
void operator()(FloatType)
|
2021-06-21 01:37:40 +00:00
|
|
|
{
|
2022-01-23 20:23:20 +00:00
|
|
|
++count_;
|
2021-06-21 01:37:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 20:23:20 +00:00
|
|
|
bool update(uint8_t sw)
|
|
|
|
{
|
2022-05-29 22:09:09 +00:00
|
|
|
if (count_ < 8)
|
2021-06-21 01:37:40 +00:00
|
|
|
{
|
2022-01-23 20:23:20 +00:00
|
|
|
return false;
|
2021-06-21 01:37:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 20:23:20 +00:00
|
|
|
auto f = kf_.update(sw, count_);
|
2021-06-21 01:37:40 +00:00
|
|
|
|
2022-01-23 20:23:20 +00:00
|
|
|
// Constrain sample index to [0..SamplesPerSymbol), wrapping if needed.
|
|
|
|
sample_estimate_ = f[0];
|
|
|
|
sample_index_ = int8_t(round(sample_estimate_));
|
|
|
|
sample_index_ = sample_index_ < 0 ? sample_index_ + SamplesPerSymbol : sample_index_;
|
|
|
|
sample_index_ = sample_index_ >= int8_t(SamplesPerSymbol) ? sample_index_ - SamplesPerSymbol : sample_index_;
|
|
|
|
clock_estimate_ = f[1];
|
|
|
|
count_ = 0;
|
|
|
|
|
|
|
|
return true;
|
2021-06-21 01:37:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-01-23 20:23:20 +00:00
|
|
|
* This is used when no sync word is found. The sample index is updated
|
|
|
|
* based on the current clock estimate, the last known good sample
|
|
|
|
* estimate, and the number of samples processed.
|
|
|
|
*
|
|
|
|
* The sample and clock estimates from the filter remain unchanged.
|
2021-06-21 01:37:40 +00:00
|
|
|
*/
|
2022-01-23 20:23:20 +00:00
|
|
|
bool update()
|
2021-06-21 01:37:40 +00:00
|
|
|
{
|
2022-05-29 22:09:09 +00:00
|
|
|
auto csw = std::fmod((sample_estimate_ + clock_estimate_ * count_), SamplesPerSymbol);
|
2022-01-23 20:23:20 +00:00
|
|
|
if (csw < 0.) csw += SamplesPerSymbol;
|
|
|
|
else if (csw >= SamplesPerSymbol) csw -= SamplesPerSymbol;
|
|
|
|
|
|
|
|
// Constrain sample index to [0..SamplesPerSymbol), wrapping if needed.
|
|
|
|
sample_index_ = int8_t(round(csw));
|
|
|
|
sample_index_ = sample_index_ < 0 ? sample_index_ + SamplesPerSymbol : sample_index_;
|
|
|
|
sample_index_ = sample_index_ >= int8_t(SamplesPerSymbol) ? sample_index_ - SamplesPerSymbol : sample_index_;
|
|
|
|
|
|
|
|
return true;
|
2021-06-21 01:37:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the estimated sample clock increment based on the last update.
|
2022-01-23 20:23:20 +00:00
|
|
|
*
|
2021-06-21 01:37:40 +00:00
|
|
|
* The value is only valid after samples have been collected and update()
|
|
|
|
* has been called.
|
|
|
|
*/
|
|
|
|
FloatType clock_estimate() const
|
|
|
|
{
|
2022-01-23 20:23:20 +00:00
|
|
|
return clock_estimate_;
|
2021-06-21 01:37:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the estimated "best sample index" based on the last update.
|
2022-01-23 20:23:20 +00:00
|
|
|
*
|
2021-06-21 01:37:40 +00:00
|
|
|
* The value is only valid after samples have been collected and update()
|
|
|
|
* has been called.
|
|
|
|
*/
|
|
|
|
uint8_t sample_index() const
|
|
|
|
{
|
|
|
|
return sample_index_;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}} // mobilinkd::m17
|