Explain and clean up decimator scalars (#1422)

This commit is contained in:
Kyle Reed 2023-08-30 09:05:49 -07:00 committed by GitHub
parent 4bc752b7a8
commit f46e20c977
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 51 additions and 73 deletions

View file

@ -23,19 +23,26 @@
#define __DSP_DECIMATE_H__ #define __DSP_DECIMATE_H__
#include <cstdint> #include <cstdint>
#include <algorithm>
#include <array> #include <array>
#include <memory> #include <memory>
#include <algorithm>
#include "utility.hpp"
#include "dsp_types.hpp" #include "dsp_types.hpp"
#include "simd.hpp" #include "simd.hpp"
#include "utility.hpp"
namespace dsp { namespace dsp {
namespace decimate { namespace decimate {
/* "Saturating" scalars used by decimators to scale either
* 8 or 16 bit complex values into 32 bit complex values.
* Some of the decimators accept a scale factor as part of
* configuration, which is then passed to scale_round_and_pack. */
// c8_to_c32_sat_scalar == 2^25. 2^25 * 2^7 (signed C8 Max) == 2^32.
constexpr int32_t c8_to_c32_sat_scalar = 0x2000000;
// c16_to_c32_sat_scalar == 2^17. 2^17 * 2^15 (signed C16 Max) == 2^32.
constexpr int32_t c16_to_c32_sat_scalar = 0x20000;
class Complex8DecimateBy2CIC3 { class Complex8DecimateBy2CIC3 {
public: public:
buffer_c16_t execute( buffer_c16_t execute(
@ -100,7 +107,7 @@ class FIRC8xR16x24FS4Decim4 {
void configure( void configure(
const std::array<tap_t, taps_count>& taps, const std::array<tap_t, taps_count>& taps,
const int32_t scale, const int32_t scale = c8_to_c32_sat_scalar,
const Shift shift = Shift::Down); const Shift shift = Shift::Down);
buffer_c16_t execute( buffer_c16_t execute(
@ -128,7 +135,7 @@ class FIRC8xR16x24FS4Decim8 {
void configure( void configure(
const std::array<tap_t, taps_count>& taps, const std::array<tap_t, taps_count>& taps,
const int32_t scale, const int32_t scale = c8_to_c32_sat_scalar,
const Shift shift = Shift::Down); const Shift shift = Shift::Down);
buffer_c16_t execute( buffer_c16_t execute(
@ -151,7 +158,7 @@ class FIRC16xR16x16Decim2 {
void configure( void configure(
const std::array<tap_t, taps_count>& taps, const std::array<tap_t, taps_count>& taps,
const int32_t scale); const int32_t scale = c16_to_c32_sat_scalar);
buffer_c16_t execute( buffer_c16_t execute(
const buffer_c16_t& src, const buffer_c16_t& src,
@ -173,7 +180,7 @@ class FIRC16xR16x32Decim8 {
void configure( void configure(
const std::array<tap_t, taps_count>& taps, const std::array<tap_t, taps_count>& taps,
const int32_t scale); const int32_t scale = c16_to_c32_sat_scalar);
buffer_c16_t execute( buffer_c16_t execute(
const buffer_c16_t& src, const buffer_c16_t& src,

View file

@ -29,8 +29,8 @@
#include "event_m4.hpp" #include "event_m4.hpp"
ACARSProcessor::ACARSProcessor() { ACARSProcessor::ACARSProcessor() {
decim_0.configure(taps_11k0_decim_0.taps, 33554432); decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps, 131072); decim_1.configure(taps_11k0_decim_1.taps);
packet.clear(); packet.clear();
baseband_thread.start(); baseband_thread.start();
} }

View file

@ -154,8 +154,8 @@ void AFSKRxProcessor::configure(const AFSKRxConfigureMessage& message) {
const size_t demod_input_fs = channel_filter_output_fs;*/ const size_t demod_input_fs = channel_filter_output_fs;*/
decim_0.configure(taps_11k0_decim_0.taps, 33554432); decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps, 131072); decim_1.configure(taps_11k0_decim_1.taps);
channel_filter.configure(taps_11k0_channel.taps, 2); channel_filter.configure(taps_11k0_channel.taps, 2);
demod.configure(audio_fs, 5000); demod.configure(audio_fs, 5000);

View file

@ -28,8 +28,8 @@
#include "event_m4.hpp" #include "event_m4.hpp"
AISProcessor::AISProcessor() { AISProcessor::AISProcessor() {
decim_0.configure(taps_11k0_decim_0.taps, 33554432); decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps, 131072); decim_1.configure(taps_11k0_decim_1.taps);
baseband_thread.start(); baseband_thread.start();
} }

View file

@ -89,8 +89,8 @@ void NarrowbandAMAudio::configure(const AMConfigureMessage& message) {
constexpr size_t channel_filter_input_fs = decim_2_output_fs; constexpr size_t channel_filter_input_fs = decim_2_output_fs;
// const size_t channel_filter_output_fs = channel_filter_input_fs / channel_filter_decimation_factor; // const size_t channel_filter_output_fs = channel_filter_input_fs / channel_filter_decimation_factor;
decim_0.configure(message.decim_0_filter.taps, 33554432); decim_0.configure(message.decim_0_filter.taps);
decim_1.configure(message.decim_1_filter.taps, 131072); decim_1.configure(message.decim_1_filter.taps);
decim_2.configure(message.decim_2_filter.taps, decim_2_decimation_factor); decim_2.configure(message.decim_2_filter.taps, decim_2_decimation_factor);
channel_filter.configure(message.channel_filter.taps, channel_filter_decimation_factor); channel_filter.configure(message.channel_filter.taps, channel_filter_decimation_factor);
channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs; channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs;

View file

@ -223,8 +223,8 @@ void APRSRxProcessor::capture_config(const CaptureConfigMessage& message) {
} }
void APRSRxProcessor::configure(const APRSRxConfigureMessage& message) { void APRSRxProcessor::configure(const APRSRxConfigureMessage& message) {
decim_0.configure(taps_11k0_decim_0.taps, 33554432); decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps, 131072); decim_1.configure(taps_11k0_decim_1.taps);
channel_filter.configure(taps_11k0_channel.taps, 2); channel_filter.configure(taps_11k0_channel.taps, 2);
demod.configure(audio_fs, 5000); demod.configure(audio_fs, 5000);

View file

@ -276,8 +276,8 @@ void BTLERxProcessor::on_message(const Message* const message) {
void BTLERxProcessor::configure(const BTLERxConfigureMessage& message) { void BTLERxProcessor::configure(const BTLERxConfigureMessage& message) {
(void)message; // avoid warning (void)message; // avoid warning
decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432); decim_0.configure(taps_200k_wfm_decim_0.taps);
decim_1.configure(taps_200k_wfm_decim_1.taps, 131072); decim_1.configure(taps_200k_wfm_decim_1.taps);
demod.configure(audio_fs, 5000); demod.configure(audio_fs, 5000);
configured = true; configured = true;

View file

@ -104,43 +104,38 @@ void CaptureProcessor::sample_rate_config(const SampleRateConfigMessage& message
if (sample_rate >= 1'500'000) if (sample_rate >= 1'500'000)
spectrum_interval_samples /= (sample_rate / 750'000); spectrum_interval_samples /= (sample_rate / 750'000);
// Mystery scalars for decimator configuration.
// TODO: figure these out and add a real comment.
constexpr int decim_0_scale = 0x2000000;
constexpr int decim_1_scale = 0x20000;
switch (message.oversample_rate) { switch (message.oversample_rate) {
case OversampleRate::x4: case OversampleRate::x4:
// M4 can't handle 2 decimation passes for sample rates needing x4. // M4 can't handle 2 decimation passes for sample rates needing x4.
decim_0.set<FIRC8xR16x24FS4Decim4>().configure(taps_200k_decim_0.taps, decim_0_scale); decim_0.set<FIRC8xR16x24FS4Decim4>().configure(taps_200k_decim_0.taps);
decim_1.set<NoopDecim>(); decim_1.set<NoopDecim>();
break; break;
case OversampleRate::x8: case OversampleRate::x8:
// M4 can't handle 2 decimation passes for sample rates <= 600k. // M4 can't handle 2 decimation passes for sample rates <= 600k.
if (message.sample_rate < 600'000) { if (message.sample_rate < 600'000) {
decim_0.set<FIRC8xR16x24FS4Decim4>().configure(taps_200k_decim_0.taps, decim_0_scale); decim_0.set<FIRC8xR16x24FS4Decim4>().configure(taps_200k_decim_0.taps);
decim_1.set<FIRC16xR16x16Decim2>().configure(taps_200k_decim_1.taps, decim_1_scale); decim_1.set<FIRC16xR16x16Decim2>().configure(taps_200k_decim_1.taps);
} else { } else {
// Using 180k taps to provide better filtering with a single pass. // Using 180k taps to provide better filtering with a single pass.
decim_0.set<FIRC8xR16x24FS4Decim8>().configure(taps_180k_wfm_decim_0.taps, decim_0_scale); decim_0.set<FIRC8xR16x24FS4Decim8>().configure(taps_180k_wfm_decim_0.taps);
decim_1.set<NoopDecim>(); decim_1.set<NoopDecim>();
} }
break; break;
case OversampleRate::x16: case OversampleRate::x16:
decim_0.set<FIRC8xR16x24FS4Decim8>().configure(taps_200k_decim_0.taps, decim_0_scale); decim_0.set<FIRC8xR16x24FS4Decim8>().configure(taps_200k_decim_0.taps);
decim_1.set<FIRC16xR16x16Decim2>().configure(taps_200k_decim_1.taps, decim_1_scale); decim_1.set<FIRC16xR16x16Decim2>().configure(taps_200k_decim_1.taps);
break; break;
case OversampleRate::x32: case OversampleRate::x32:
decim_0.set<FIRC8xR16x24FS4Decim4>().configure(taps_200k_decim_0.taps, decim_0_scale); decim_0.set<FIRC8xR16x24FS4Decim4>().configure(taps_200k_decim_0.taps);
decim_1.set<FIRC16xR16x32Decim8>().configure(taps_16k0_decim_1.taps, decim_1_scale); decim_1.set<FIRC16xR16x32Decim8>().configure(taps_16k0_decim_1.taps);
break; break;
case OversampleRate::x64: case OversampleRate::x64:
decim_0.set<FIRC8xR16x24FS4Decim8>().configure(taps_200k_decim_0.taps, decim_0_scale); decim_0.set<FIRC8xR16x24FS4Decim8>().configure(taps_200k_decim_0.taps);
decim_1.set<FIRC16xR16x32Decim8>().configure(taps_16k0_decim_1.taps, decim_1_scale); decim_1.set<FIRC16xR16x32Decim8>().configure(taps_16k0_decim_1.taps);
break; break;
default: default:

View file

@ -144,8 +144,8 @@ void NarrowbandFMAudio::configure(const NBFMConfigureMessage& message) {
const size_t demod_input_fs = channel_filter_output_fs; const size_t demod_input_fs = channel_filter_output_fs;
decim_0.configure(message.decim_0_filter.taps, 33554432); decim_0.configure(message.decim_0_filter.taps);
decim_1.configure(message.decim_1_filter.taps, 131072); decim_1.configure(message.decim_1_filter.taps);
channel_filter.configure(message.channel_filter.taps, message.channel_decimation); channel_filter.configure(message.channel_filter.taps, message.channel_decimation);
demod.configure(demod_input_fs, message.deviation); demod.configure(demod_input_fs, message.deviation);
channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs; channel_filter_low_f = message.channel_filter.low_frequency_normalized * channel_filter_input_fs;

View file

@ -243,8 +243,8 @@ void NRFRxProcessor::on_message(const Message* const message) {
void NRFRxProcessor::configure(const NRFRxConfigureMessage& message) { void NRFRxProcessor::configure(const NRFRxConfigureMessage& message) {
(void)message; // avoir unused warning (void)message; // avoir unused warning
decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432); decim_0.configure(taps_200k_wfm_decim_0.taps);
decim_1.configure(taps_200k_wfm_decim_1.taps, 131072); decim_1.configure(taps_200k_wfm_decim_1.taps);
demod.configure(audio_fs, 5000); demod.configure(audio_fs, 5000);
configured = true; configured = true;

View file

@ -107,8 +107,8 @@ void POCSAGProcessor::configure() {
const size_t demod_input_fs = channel_filter_output_fs; const size_t demod_input_fs = channel_filter_output_fs;
decim_0.configure(taps_11k0_decim_0.taps, 33554432); decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps, 131072); decim_1.configure(taps_11k0_decim_1.taps);
channel_filter.configure(taps_11k0_channel.taps, 2); channel_filter.configure(taps_11k0_channel.taps, 2);
demod.configure(demod_input_fs, 4'500); // FSK +/- 4k5Hz. demod.configure(demod_input_fs, 4'500); // FSK +/- 4k5Hz.

View file

@ -29,8 +29,8 @@
#include "audio_output.hpp" #include "audio_output.hpp"
SondeProcessor::SondeProcessor() { SondeProcessor::SondeProcessor() {
decim_0.configure(taps_11k0_decim_0.taps, 33554432); decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps, 131072); decim_1.configure(taps_11k0_decim_1.taps);
audio_output.configure(false); audio_output.configure(false);

View file

@ -27,8 +27,8 @@
#include "event_m4.hpp" #include "event_m4.hpp"
TestProcessor::TestProcessor() { TestProcessor::TestProcessor() {
decim_0.configure(taps_11k0_decim_0.taps, 33554432); decim_0.configure(taps_11k0_decim_0.taps);
decim_1.configure(taps_11k0_decim_1.taps, 131072); decim_1.configure(taps_11k0_decim_1.taps);
baseband_thread.start(); baseband_thread.start();
} }

View file

@ -26,8 +26,8 @@
#include "event_m4.hpp" #include "event_m4.hpp"
TPMSProcessor::TPMSProcessor() { TPMSProcessor::TPMSProcessor() {
decim_0.configure(taps_200k_decim_0.taps, 33554432); decim_0.configure(taps_200k_decim_0.taps);
decim_1.configure(taps_200k_decim_1.taps, 131072); decim_1.configure(taps_200k_decim_1.taps);
baseband_thread.start(); baseband_thread.start();
} }

View file

@ -165,8 +165,8 @@ void WidebandFMAudio::configure(const WFMConfigureMessage& message) {
spectrum_interval_samples = decim_1_output_fs / spectrum_rate_hz; spectrum_interval_samples = decim_1_output_fs / spectrum_rate_hz;
spectrum_samples = 0; spectrum_samples = 0;
decim_0.configure(message.decim_0_filter.taps, 33554432); decim_0.configure(message.decim_0_filter.taps);
decim_1.configure(message.decim_1_filter.taps, 131072); decim_1.configure(message.decim_1_filter.taps);
channel_filter_low_f = message.decim_1_filter.low_frequency_normalized * decim_1_input_fs; channel_filter_low_f = message.decim_1_filter.low_frequency_normalized * decim_1_input_fs;
channel_filter_high_f = message.decim_1_filter.high_frequency_normalized * decim_1_input_fs; channel_filter_high_f = message.decim_1_filter.high_frequency_normalized * decim_1_input_fs;
channel_filter_transition = message.decim_1_filter.transition_normalized * decim_1_input_fs; channel_filter_transition = message.decim_1_filter.transition_normalized * decim_1_input_fs;

View file

@ -36,24 +36,12 @@ struct complex<int8_t> {
typedef int8_t value_type; typedef int8_t value_type;
typedef uint16_t rep_type; typedef uint16_t rep_type;
// constexpr complex(
// rep_type r
// ) : _rep { r }
// {
// }
constexpr complex( constexpr complex(
int8_t re = 0, int8_t re = 0,
int8_t im = 0) int8_t im = 0)
: _v{re, im} { : _v{re, im} {
} }
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
constexpr int8_t real() const { return _v[0]; } constexpr int8_t real() const { return _v[0]; }
constexpr int8_t imag() const { return _v[1]; } constexpr int8_t imag() const { return _v[1]; }
@ -77,24 +65,12 @@ struct complex<int16_t> {
typedef int16_t value_type; typedef int16_t value_type;
typedef uint32_t rep_type; typedef uint32_t rep_type;
// constexpr complex(
// rep_type r
// ) : _rep { r }
// {
// }
constexpr complex( constexpr complex(
int16_t re = 0, int16_t re = 0,
int16_t im = 0) int16_t im = 0)
: _v{re, im} { : _v{re, im} {
} }
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
constexpr int16_t real() const { return _v[0]; } constexpr int16_t real() const { return _v[0]; }
constexpr int16_t imag() const { return _v[1]; } constexpr int16_t imag() const { return _v[1]; }