Remove now-unused M17 components.

master
Rob Riggs 2021-06-20 20:43:34 -05:00
rodzic f43d6d5441
commit b622d2b13b
6 zmienionych plików z 0 dodań i 441 usunięć

Wyświetl plik

@ -1,40 +0,0 @@
// Copyright 2020 Mobilinkd LLC.
#pragma once
#include "IirFilter.hpp"
#include <array>
#include <algorithm>
#include <numeric>
#include <cmath>
namespace mobilinkd
{
template <typename FloatType>
struct CarrierDetect
{
using result_t = std::tuple<bool, FloatType>;
tnc::IirFilter<3> filter_;
FloatType lock_;
FloatType unlock_;
bool locked_ = false;
CarrierDetect(std::array<FloatType, 3> const& b, std::array<FloatType, 3> const& a, FloatType lock_level, FloatType unlock_level)
: filter_(b, a), lock_(lock_level), unlock_(unlock_level)
{
}
result_t operator()(FloatType value)
{
auto filtered = filter_(std::abs(value));
if (locked_ && (filtered > unlock_)) locked_ = false;
else if (!locked_ && (filtered < lock_)) locked_ = true;
return std::make_tuple(locked_, filtered);
}
};
} // mobilinkd

Wyświetl plik

@ -1,96 +0,0 @@
// Copyright 2020 Mobilinkd LLC.
#pragma once
#include <array>
#include <algorithm>
#include <numeric>
namespace mobilinkd
{
template <typename T, size_t N = 10>
struct DeviationError
{
using float_type = T;
using array_t = std::array<float_type, N>;
array_t minima_{0};
array_t maxima_{0};
size_t min_index_ = 0;
size_t max_index_ = 0;
bool min_rolled_ = false;
bool max_rolled_ = false;
size_t min_count_ = 0;
size_t max_count_ = 0;
float_type min_estimate_ = 0.0;
float_type max_estimate_ = 0.0;
const float_type ZERO = 0.0;
DeviationError()
{
minima_.fill(0.0);
maxima_.fill(0.0);
}
float_type operator()(float_type sample)
{
if (sample > ZERO)
{
if (sample > max_estimate_ * 0.67 or max_count_ == 5)
{
max_count_ = 0;
maxima_[max_index_++] = sample;
if (max_index_ == N)
{
max_rolled_ = true;
max_index_ = 0;
}
if (max_rolled_)
{
max_estimate_ = std::accumulate(std::begin(maxima_), std::end(maxima_), ZERO) / N;
}
else
{
max_estimate_ = std::accumulate(std::begin(maxima_), std::begin(maxima_) + max_index_, ZERO) / max_index_;
}
}
else
{
++max_count_;
}
}
else if (sample < 0)
{
if (sample < min_estimate_ * 0.67 or min_count_ == 5)
{
min_count_ = 0;
minima_[min_index_++] = sample;
if (min_index_ == N)
{
min_rolled_ = true;
min_index_ = 0;
}
if (min_rolled_)
{
min_estimate_ = std::accumulate(std::begin(minima_), std::end(minima_), ZERO) / N;
}
else
{
min_estimate_ = std::accumulate(std::begin(minima_), std::begin(minima_) + min_index_, ZERO) / min_index_;
}
}
else
{
++min_count_;
}
}
auto deviation = max_estimate_ - min_estimate_;
auto deviation_error = std::min(6.0 / deviation, 100.0);
return deviation_error;
}
};
} // mobilinkd

Wyświetl plik

@ -1,63 +0,0 @@
// Copyright 2020 Mobilinkd LLC.
#pragma once
#include "IirFilter.hpp"
#include <array>
#include <algorithm>
#include <numeric>
namespace mobilinkd
{
template <typename FloatType, size_t N = 32>
struct FrequencyError
{
using float_type = FloatType;
using array_t = std::array<FloatType, N>;
using filter_type = tnc::IirFilter<3>;
array_t samples_{0};
size_t index_ = 0;
float_type accum_ = 0.0;
filter_type filter_;
const float_type ZERO = 0.0;
FrequencyError(const std::array<float, 3>& b, const std::array<float, 3>& a)
: filter_(b, a)
{
samples_.fill(0.0);
}
auto operator()(float_type sample)
{
FloatType evm = 0;
bool use = true;
if (sample > 2)
{
evm = sample - 3;
}
else if (sample >= -2)
{
use = false;
}
else
{
evm = sample + 3;
}
if (use)
{
accum_ = accum_ - samples_[index_] + evm;
samples_[index_++] = evm;
if (index_ == N) index_ = 0;
}
return filter_(accum_ / N);
}
};
} // mobilinkd

Wyświetl plik

@ -1,122 +0,0 @@
// Copyright 2020 Mobilinkd LLC.
#pragma once
#include "FirFilter.h"
#include "PhaseEstimator.h"
#include "DeviationError.h"
#include "FrequencyError.h"
#include "SymbolEvm.h"
#include <array>
#include <experimental/array>
#include <optional>
#include <tuple>
namespace mobilinkd
{
namespace detail
{
inline const auto rrc_taps = std::experimental::make_array<int16_t>(
-151, -100, -18, 80, 175, 246, 275, 249, 170, 49, -90, -219,
-304, -318, -245, -88, 131, 373, 581, 695, 659, 437, 22, -556,
-1229, -1890, -2409, -2641, -2452, -1738, -441, 1434, 3816, 6563,
9480, 12334, 14880, 16891, 18179, 18622, 18179, 16891, 14880, 12334,
9480, 6563, 3816, 1434, -441, -1738, -2452, -2641, -2409, -1890,
-1229, -556, 22, 437, 659, 695, 581, 373, 131, -88, -245, -318, -304,
-219, -90, 49, 170, 249, 275, 246, 175, 80, -18, -100, -151);
inline const auto evm_b = std::experimental::make_array<float>(0.02008337, 0.04016673, 0.02008337);
inline const auto evm_a = std::experimental::make_array<float>(1.0, -1.56101808, 0.64135154);
} // detail
struct Fsk4Demod
{
using demod_result_t = std::tuple<float, float, int, float>;
using result_t = std::optional<std::tuple<float, float, int, float, float, float, float>>;
tnc::Q15FirFilter<320, std::tuple_size<decltype(detail::rrc_taps)>::value> rrc;
PhaseEstimator<float> phase = PhaseEstimator<double>(48000, 4800);
DeviationError<float> deviation;
FrequencyError<float, 32> frequency;
SymbolEvm<float, std::tuple_size<decltype(detail::evm_b)>::value> symbol_evm = makeSymbolEvm(makeIirFilter(detail::evm_b, detail::evm_a));
double sample_rate = 48000;
double symbol_rate = 4800;
double gain = 0.04;
std::array<double, 3> samples{0};
double t = 0;
double dt = symbol_rate / sample_rate;
double ideal_dt = dt;
bool sample_now = false;
double estimated_deviation = 1.0;
double estimated_frequency_offset = 0.0;
double evm_average = 0.0;
Fsk4Demod(double sample_rate, double symbol_rate, double gain = 0.04)
: sample_rate(sample_rate)
, symbol_rate(symbol_rate)
, gain(gain * symbol_rate / sample_rate)
, dt(symbol_rate / sample_rate)
, ideal_dt(dt)
{
samples.fill(0.0);
}
demod_result_t demod()
{
estimated_deviation = deviation(samples[1]);
for (auto& sample : samples) sample *= estimated_deviation;
estimated_frequency_offset = frequency(samples[1]);
for (auto& sample : samples) sample -= estimated_frequency_offset;
auto phase_estimate = phase(samples);
if (samples[1] < 0) phase_estimate *= -1;
dt = ideal_dt - (phase_estimate * gain);
t += dt;
auto [symbol, evm] = symbol_evm(samples[1]);
evm_average = symbol_evm.evm();
samples[0] = samples[2];
return std::make_tuple(samples[1], phase_estimate, symbol, evm);
}
/**
* Process the sample. If a symbol is ready, return a tuple
* containing the sample used, the estimated phase, the decoded
* symbol, the EVM, the deviation error and the frequency error
* (sample, phase, symbol, evm, ed, ef), otherwise None.
*/
result_t operator()(double sample)
{
auto filtered_sample = rrc(sample);
if (sample_now)
{
samples[2] = filtered_sample;
sample_now = false;
auto [prev_sample, phase_estimate, symbol, evm] = demod();
return std::make_tuple(prev_sample, phase_estimate, symbol, evm, estimated_deviation, estimated_frequency_offset, evm_average);
}
t += dt;
if (t < 1.0)
{
samples[0] = filtered_sample;
}
else
{
t -= 1.0;
samples[1] = filtered_sample;
sample_now = true;
}
return std::nullopt;
}
};
} // mobilinkd

Wyświetl plik

@ -1,50 +0,0 @@
// Copyright 2020 Mobilinkd LLC.
#pragma once
#include <array>
#include <algorithm>
#include <cassert>
namespace mobilinkd
{
/**
* Estimate the phase of a sample by estimating the
* tangent of the sample point. This is done by computing
* the magnitude difference of the previous and following
* samples. We do not correct for 0-crossing errors because
* these errors have not affected the performance of clock
* recovery.
*/
template <typename FloatType>
struct PhaseEstimator
{
using samples_t = std::array<FloatType, 3>; // 3 samples in length
FloatType dx_;
PhaseEstimator(FloatType sample_rate, FloatType symbol_rate)
: dx_(2.0 * symbol_rate / sample_rate)
{
assert(dx_ > 0.0);
}
/**
* This performs a rolling estimate of the phase.
*
* @param samples are three samples centered around the current sample point
* (t-1, t, t+1).
*/
FloatType operator()(const samples_t& samples)
{
auto ratio = ((samples.at(2) - samples.at(0)) / 3.0f) / dx_;
// Clamp +/-5.
ratio = std::min(FloatType(5.0), ratio);
ratio = std::max(FloatType(-5.0), ratio);
return ratio;
}
};
} // mobilinkd

Wyświetl plik

@ -1,70 +0,0 @@
// Copyright 2020 Mobilinkd LLC.
#pragma once
#include "IirFilter.hpp"
#include <array>
#include <algorithm>
#include <numeric>
namespace mobilinkd
{
template <typename FloatType, size_t N>
struct SymbolEvm
{
using filter_type = tnc::IirFilter<N>;
using symbol_t = int;
using result_type = std::tuple<symbol_t, FloatType>;
filter_type filter_;
FloatType evm_ = 0.0;
SymbolEvm(const std::array<FloatType, N>& b, const std::array<FloatType, N>& a)
: filter_(b, a)
{}
FloatType evm() const { return evm_; }
/**
* Decode a normalized sample into a symbol. Symbols
* are decoded into +3, +1, -1, -3. If an erasure limit
* is set, symbols outside this limit are 'erased' and
* returned as 0.
*/
result_type operator()(FloatType sample)
{
symbol_t symbol;
FloatType evm;
sample = std::min(3.0f, std::max(-3.0f, sample));
if (sample > 2)
{
symbol = 3;
evm = (sample - 3) * 0.333333f;
}
else if (sample > 0)
{
symbol = 1;
evm = sample - 1;
}
else if (sample >= -2)
{
symbol = -1;
evm = sample + 1;
}
else
{
symbol = -3;
evm = (sample + 3) * 0.333333f;
}
evm_ = filter_(evm);
return std::make_tuple(symbol, evm);
}
};
} // mobilinkd