mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-21 15:09:03 +00:00
Morse rx further development (#2959)
* filters OK, radio configurations set * all modes are working, noise still needs work, especially in FM. A baseband enum is also needed * audio and decoding fixed, clipping and the baseband enum are still missing
This commit is contained in:
@@ -17,6 +17,7 @@ MorseRadioView::MorseRadioView(ui::NavigationView& nav)
|
||||
&txt_last,
|
||||
&txt_speed,
|
||||
&txt_freq,
|
||||
&txt_clip,
|
||||
&options_mode,
|
||||
&btn_clear,
|
||||
&console_text,
|
||||
@@ -39,9 +40,9 @@ MorseRadioView::MorseRadioView(ui::NavigationView& nav)
|
||||
receiver_model.enable();
|
||||
|
||||
options_mode.on_change = [this](size_t, int32_t value) {
|
||||
current_mode = (uint8_t)value;
|
||||
current_mode = static_cast<ModulationMode>((uint8_t)value);
|
||||
morse_decoder_.resetLearning();
|
||||
if (current_mode == 0) {
|
||||
if (current_mode == ModulationMode::FM) {
|
||||
receiver_model.set_am_configuration(4);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::NarrowbandFMAudio);
|
||||
field_squelch.set_style(Theme::getInstance()->option_active);
|
||||
@@ -49,21 +50,26 @@ MorseRadioView::MorseRadioView(ui::NavigationView& nav)
|
||||
receiver_model.set_squelch_level(field_squelch.value());
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
} else {
|
||||
audio::set_rate(audio::Rate::Hz_12000);
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::AMAudio);
|
||||
receiver_model.set_am_configuration(current_mode + 7);
|
||||
if (current_mode == ModulationMode::AM || current_mode == ModulationMode::DSB)
|
||||
receiver_model.set_am_configuration(7);
|
||||
else if (current_mode == ModulationMode::USB)
|
||||
receiver_model.set_am_configuration(9);
|
||||
else // LSB
|
||||
receiver_model.set_am_configuration(10);
|
||||
receiver_model.set_squelch_level(0);
|
||||
field_squelch.set_style(Theme::getInstance()->fg_dark);
|
||||
field_squelch.set_focusable(false);
|
||||
audio::set_rate(audio::Rate::Hz_12000);
|
||||
}
|
||||
baseband::set_moreserx_config(current_mode);
|
||||
baseband::set_moreserx_config(static_cast<uint8_t>(current_mode));
|
||||
};
|
||||
field_squelch.set_value(receiver_model.squelch_level(), false); // will be sent later, no need to send 2x
|
||||
field_squelch.on_change = [this](int32_t v) {
|
||||
if (current_mode == 0)
|
||||
if (current_mode == ModulationMode::FM)
|
||||
receiver_model.set_squelch_level(v);
|
||||
};
|
||||
options_mode.set_selected_index(current_mode, true);
|
||||
options_mode.set_selected_index(static_cast<int32_t>(current_mode), true);
|
||||
|
||||
auto vol = field_volume.value(); // audio volume fix
|
||||
field_volume.set_value(0);
|
||||
@@ -105,9 +111,30 @@ void MorseLogger::init_daily_log(const std::filesystem::path& log_dir) {
|
||||
|
||||
void MorseLogger::radio_set_log(uint8_t current_mode) {
|
||||
int64_t freq = receiver_model.target_frequency();
|
||||
std::string mode_str;
|
||||
switch (static_cast<MorseRadioView::ModulationMode>(current_mode)) {
|
||||
case MorseRadioView::ModulationMode::AM:
|
||||
mode_str = "AM";
|
||||
break;
|
||||
case MorseRadioView::ModulationMode::FM:
|
||||
mode_str = "FM";
|
||||
break;
|
||||
case MorseRadioView::ModulationMode::DSB:
|
||||
mode_str = "DSB";
|
||||
break;
|
||||
case MorseRadioView::ModulationMode::USB:
|
||||
mode_str = "USB";
|
||||
break;
|
||||
case MorseRadioView::ModulationMode::LSB:
|
||||
mode_str = "LSB";
|
||||
break;
|
||||
default:
|
||||
mode_str = "???";
|
||||
break;
|
||||
}
|
||||
std::string header = "Freq:" + to_string_rounded_freq(freq, 4);
|
||||
header += "MHz, ";
|
||||
header += "RX MODE:" + std::string(current_mode == 0 ? "CW/FM" : (current_mode == 1 ? "USB" : "LSB"));
|
||||
header += "RX MODE:" + mode_str;
|
||||
header += "\r\nMessage:";
|
||||
log_file.write_raw(header);
|
||||
}
|
||||
@@ -152,6 +179,8 @@ MorseRadioView::~MorseRadioView() {
|
||||
|
||||
void MorseRadioView::focus() {
|
||||
field_frequency.focus();
|
||||
txt_clip.set_style(Theme::getInstance()->fg_red);
|
||||
txt_clip.hidden(true);
|
||||
}
|
||||
|
||||
void MorseRadioView::check_for_timeout() {
|
||||
@@ -205,6 +234,8 @@ int32_t MorseRadioView::ProcessSignal(int32_t sig_time_us) {
|
||||
void MorseRadioView::on_data(const MorseRXDataMessage* message) {
|
||||
int32_t r;
|
||||
|
||||
txt_clip.hidden(!message->clipped);
|
||||
|
||||
for (uint8_t i = 0; i <= message->state_cnt; ++i) {
|
||||
r = ProcessSignal(message->state_durations[i]);
|
||||
auto result = morse_decoder_.handleInput((r != 0) ? r : 0);
|
||||
@@ -212,7 +243,7 @@ void MorseRadioView::on_data(const MorseRXDataMessage* message) {
|
||||
last_activity_time = chTimeNow(); // start reset timer on valid input
|
||||
writeCharToConsole(result.text, result.confidence);
|
||||
if (logger && save_log) {
|
||||
time_stamp = logger->on_packet(result.text, time_stamp, current_mode);
|
||||
time_stamp = logger->on_packet(result.text, time_stamp, static_cast<uint8_t>(current_mode));
|
||||
}
|
||||
float dah_time = morse_decoder_.getCurrentTimeUnit() * 3.0f;
|
||||
if (dah_time > 0) {
|
||||
|
||||
@@ -64,6 +64,14 @@ class MorseLogger {
|
||||
|
||||
class MorseRadioView : public ui::View {
|
||||
public:
|
||||
enum class ModulationMode : uint8_t {
|
||||
AM = 0,
|
||||
FM = 1,
|
||||
DSB = 2,
|
||||
USB = 3,
|
||||
LSB = 4
|
||||
};
|
||||
|
||||
MorseRadioView(ui::NavigationView& nav);
|
||||
~MorseRadioView();
|
||||
std::string title() const override {
|
||||
@@ -83,12 +91,12 @@ class MorseRadioView : public ui::View {
|
||||
RxRadioState radio_state_{};
|
||||
std::unique_ptr<MorseLogger> logger{};
|
||||
|
||||
uint8_t current_mode{0}; // 0=CW/FM, 1=USB, 2=LSB
|
||||
ModulationMode current_mode = ModulationMode::AM;
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
"rx_morese_radio",
|
||||
app_settings::Mode::RX,
|
||||
{{"cwmode"sv, ¤t_mode}}};
|
||||
{{"cwmode"sv, reinterpret_cast<uint8_t*>(¤t_mode)}}};
|
||||
|
||||
RxFrequencyField field_frequency{
|
||||
{UI_POS_X(0), UI_POS_Y(0)},
|
||||
@@ -115,6 +123,7 @@ class MorseRadioView : public ui::View {
|
||||
ui::Text txt_speed{{UI_POS_X(23), UI_POS_Y(1), UI_POS_WIDTH(3), UI_POS_HEIGHT(1)}, "??"};
|
||||
ui::Text txt_last{{UI_POS_X(12), UI_POS_Y(4), UI_POS_WIDTH_REMAINING(12), UI_POS_HEIGHT(1)}, ""};
|
||||
ui::Text txt_freq{{UI_POS_X(21), UI_POS_Y(2), UI_POS_WIDTH(5), UI_POS_HEIGHT(1)}, "??"};
|
||||
ui::Text txt_clip{{UI_POS_X(15), UI_POS_Y(3), UI_POS_WIDTH(5), UI_POS_HEIGHT(1)}, "clipping"};
|
||||
ui::Console console_text{{UI_POS_X(0), UI_POS_Y(5), UI_POS_MAXWIDTH, UI_POS_HEIGHT_REMAINING(7)}};
|
||||
ui::Labels labels{
|
||||
{{UI_POS_X(0), UI_POS_Y(1)}, "Squelch:", Theme::getInstance()->fg_light->foreground},
|
||||
@@ -127,7 +136,7 @@ class MorseRadioView : public ui::View {
|
||||
ui::OptionsField options_mode{
|
||||
{UI_POS_X(9), UI_POS_Y(2)},
|
||||
5,
|
||||
{{"CW/FM", 0}, {"USB", 1}, {"LSB", 2}}};
|
||||
{{"AM", 0}, {"FM", 1}, {"DSB", 2}, {"USB", 3}, {"LSB", 4}}};
|
||||
|
||||
Checkbox chk_log{{UI_POS_X(0), UI_POS_Y(2)}, 12, "Log", false};
|
||||
ui::Button btn_clear{{UI_POS_X(0), UI_POS_Y_BOTTOM(2), UI_POS_WIDTH(6), UI_POS_HEIGHT(1)}, "CLR"};
|
||||
|
||||
@@ -28,26 +28,32 @@
|
||||
void MorseProcessor::configure(uint8_t mode) {
|
||||
configured = false;
|
||||
|
||||
if (mode == 0) { // CW/FM
|
||||
modulation = static_cast<ModulationMode>((uint8_t)mode);
|
||||
|
||||
if (modulation == ModulationMode::FM) { // FM
|
||||
decim_0.configure(taps_11k0_decim_0.taps);
|
||||
decim_1.configure(taps_11k0_decim_1.taps);
|
||||
channel_filter.configure(taps_11k0_channel.taps, 2);
|
||||
demod_cw_fm.configure(24000, 5000);
|
||||
} else { // USB, LSB
|
||||
decim_0.configure(taps_6k0_decim_0.taps);
|
||||
decim_1.configure(taps_6k0_decim_1.taps);
|
||||
|
||||
if (mode == 1) // USB
|
||||
channel_filter.configure(taps_2k8_usb_channel.taps, 4);
|
||||
else // LSB
|
||||
channel_filter.configure(taps_2k8_lsb_channel.taps, 4);
|
||||
} else {
|
||||
decim_0.configure(taps_4k25_decim_0.taps);
|
||||
decim_1.configure(taps_4k25_decim_1.taps);
|
||||
if (modulation == ModulationMode::AM) { // AM
|
||||
channel_filter.configure(taps_2k0_am_lpf_channel.taps, 4);
|
||||
} else { // SSB, DSB
|
||||
if (modulation == ModulationMode::DSB) // DSB
|
||||
channel_filter.configure(taps_1k5_dsb_lpf.taps, 4);
|
||||
else if (modulation == ModulationMode::USB) // USB
|
||||
channel_filter.configure(taps_1k5_USB_channel.taps, 4);
|
||||
else // LSB
|
||||
channel_filter.configure(taps_1k5_LSB_channel.taps, 4);
|
||||
}
|
||||
}
|
||||
|
||||
modulation = mode;
|
||||
if (mode > 0)
|
||||
audio_output.configure(audio_12k_hpf_300hz_config);
|
||||
else
|
||||
if (modulation == ModulationMode::FM)
|
||||
audio_output.configure(iir_config_passthrough, iir_config_passthrough, (float)user_squelch_level / 100.0f);
|
||||
else
|
||||
audio_output.configure(audio_12k_hpf_300hz_config);
|
||||
|
||||
meas_samples_in_period = 0;
|
||||
meas_last_period_len = 0;
|
||||
@@ -70,6 +76,8 @@ void MorseProcessor::configure(uint8_t mode) {
|
||||
squelch_is_open = true;
|
||||
squelch_hold = 0;
|
||||
|
||||
dc_average = 0.0f;
|
||||
|
||||
current_freq = 700.0f;
|
||||
update_goertzel_coeff(current_freq);
|
||||
|
||||
@@ -77,10 +85,15 @@ void MorseProcessor::configure(uint8_t mode) {
|
||||
}
|
||||
|
||||
inline buffer_f32_t MorseProcessor::demodulate(const buffer_c16_t& channel) {
|
||||
if (modulation > 0) {
|
||||
// SSB always keeps squelch "technically" open for the demodulator
|
||||
// AM,SSB,DSB always keeps squelch "technically" open for the demodulator
|
||||
if (modulation == ModulationMode::AM || modulation == ModulationMode::DSB) {
|
||||
squelch_is_open = true;
|
||||
return demod_ssb.execute(channel, audio_buffer);
|
||||
return demod_AM.execute(channel, audio_buffer);
|
||||
} else {
|
||||
if (modulation == ModulationMode::USB || modulation == ModulationMode::LSB) {
|
||||
squelch_is_open = true;
|
||||
return demod_ssb.execute(channel, audio_buffer);
|
||||
}
|
||||
}
|
||||
return demod_cw_fm.execute(channel, audio_buffer);
|
||||
}
|
||||
@@ -90,7 +103,7 @@ void MorseProcessor::update_goertzel_coeff(float freq) {
|
||||
if (freq < 300.0f) freq = 300.0f;
|
||||
if (freq > 2300.0f) freq = 2300.0f;
|
||||
|
||||
float sample_rate = (modulation == 0) ? 24000.0f : 12000.0f;
|
||||
float sample_rate = (modulation == ModulationMode::FM) ? 24000.0f : 12000.0f;
|
||||
float omega = 2.0f * M_PI * freq / sample_rate;
|
||||
float omega_sq = omega * omega;
|
||||
float cos_approx = 1.0f - (omega_sq * 0.5f);
|
||||
@@ -100,7 +113,7 @@ void MorseProcessor::update_goertzel_coeff(float freq) {
|
||||
|
||||
void MorseProcessor::measure_frequency(int32_t sample) {
|
||||
// Noise gate threshold
|
||||
const int32_t gate_threshold = (modulation == 0) ? 4000 : 2000;
|
||||
const int32_t gate_threshold = (modulation == ModulationMode::FM) ? 4000 : 2000;
|
||||
|
||||
if (sample > gate_threshold || sample < -gate_threshold) {
|
||||
if (sample > 0 && !meas_signal_state_high) {
|
||||
@@ -111,7 +124,7 @@ void MorseProcessor::measure_frequency(int32_t sample) {
|
||||
bool period_is_stable = false;
|
||||
if (meas_last_period_len > 0) {
|
||||
int32_t diff = std::abs((int)meas_samples_in_period - (int)meas_last_period_len);
|
||||
if (diff <= 1) {
|
||||
if (diff <= 2) {
|
||||
meas_consistency_count++;
|
||||
period_is_stable = true;
|
||||
} else {
|
||||
@@ -121,10 +134,12 @@ void MorseProcessor::measure_frequency(int32_t sample) {
|
||||
meas_last_period_len = meas_samples_in_period;
|
||||
|
||||
// Wait for AT LEAST 3 STABLE CYCLES
|
||||
if (period_is_stable && meas_consistency_count > 3) {
|
||||
float base_rate = (modulation == 0) ? 24000.0f : 12000.0f;
|
||||
if (period_is_stable && meas_consistency_count > 5) {
|
||||
float base_rate = (modulation == ModulationMode::FM) ? 24000.0f : 12000.0f;
|
||||
float inst_freq = base_rate / (float)meas_samples_in_period;
|
||||
|
||||
if (modulation == ModulationMode::DSB) {
|
||||
inst_freq /= 2.0f;
|
||||
}
|
||||
// Check for overflows
|
||||
if (inst_freq > 250 && inst_freq < 3000) {
|
||||
meas_freq_accumulator += inst_freq;
|
||||
@@ -148,7 +163,7 @@ void MorseProcessor::measure_frequency(int32_t sample) {
|
||||
meas_samples_in_period++;
|
||||
|
||||
ui_update_timer++;
|
||||
uint32_t update_limit = (modulation == 0) ? 4800 : 2400; // ~200ms
|
||||
uint32_t update_limit = (modulation == ModulationMode::FM) ? 4800 : 2400; // ~200ms
|
||||
|
||||
if (ui_update_timer > update_limit) {
|
||||
if (meas_freq_count > 0) {
|
||||
@@ -202,7 +217,7 @@ void MorseProcessor::process_decoding(int32_t sample) {
|
||||
|
||||
// Tone Detection
|
||||
bool is_tone = squelch_is_open && (power > current_pwr_threshold) && (power > 150000);
|
||||
int32_t time_base = modulation == 0 ? 125 : 250;
|
||||
int32_t time_base = 250;
|
||||
// State Change Logic
|
||||
if (is_tone != was_signaling) {
|
||||
int32_t duration_us = (int32_t)((int64_t)duration_samples * time_base / 3);
|
||||
@@ -254,33 +269,43 @@ void MorseProcessor::execute(const buffer_c8_t& buffer) {
|
||||
|
||||
if (raw_int_abs > audio_threshold || user_squelch_level == 0) {
|
||||
squelch_is_open = true;
|
||||
squelch_hold = (modulation == 0) ? 2400 : 1200;
|
||||
squelch_hold = (modulation == ModulationMode::FM) ? 2400 : 1200;
|
||||
} else {
|
||||
if (squelch_hold > 0)
|
||||
squelch_hold--;
|
||||
else if (modulation == 0)
|
||||
else if (modulation == ModulationMode::FM)
|
||||
squelch_is_open = false;
|
||||
}
|
||||
|
||||
measure_frequency((int32_t)(raw_audio * 32768.0f));
|
||||
|
||||
float decode_audio = raw_audio;
|
||||
if (modulation > 0) {
|
||||
const float gain = 6.0f;
|
||||
if (modulation != ModulationMode::FM) {
|
||||
float gain = 16.0f;
|
||||
if (modulation == ModulationMode::USB || modulation == ModulationMode::LSB)
|
||||
gain = 5.0f;
|
||||
decode_audio *= gain;
|
||||
|
||||
// Hard Limiting / Clipping
|
||||
if (decode_audio > 1.0f)
|
||||
message.clipped = false;
|
||||
if (decode_audio > 1.0f) {
|
||||
decode_audio = 1.0f;
|
||||
else if (decode_audio < -1.0f)
|
||||
message.clipped = true;
|
||||
} else if (decode_audio < -1.0f) {
|
||||
decode_audio = -1.0f;
|
||||
|
||||
}
|
||||
audio_buf.p[i] = decode_audio;
|
||||
}
|
||||
|
||||
// DC BLOCKING
|
||||
if (modulation != ModulationMode::FM) {
|
||||
dc_average = (dc_average * 0.95f) + (decode_audio * 0.05f);
|
||||
measure_frequency((int32_t)((decode_audio - dc_average) * 32768.0f));
|
||||
} else {
|
||||
measure_frequency((int32_t)(raw_audio * 32768.0f));
|
||||
}
|
||||
|
||||
process_decoding((int32_t)(decode_audio * 32768.0f));
|
||||
|
||||
if (modulation == 0 && !squelch_is_open) {
|
||||
if (modulation == ModulationMode::FM && !squelch_is_open) {
|
||||
audio_buf.p[i] = 0.0f; // mute nfm on squelch
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,13 +60,22 @@ class MorseProcessor : public BasebandProcessor {
|
||||
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0{};
|
||||
dsp::decimate::FIRC16xR16x32Decim8 decim_1{};
|
||||
dsp::decimate::FIRAndDecimateComplex channel_filter{};
|
||||
dsp::demodulate::AM demod_AM{};
|
||||
dsp::demodulate::FM demod_cw_fm{};
|
||||
dsp::demodulate::SSB demod_ssb{};
|
||||
AudioOutput audio_output{};
|
||||
|
||||
bool configured{false};
|
||||
|
||||
uint8_t modulation{0}; // 0=CW/FM, 1=USB, 2=LSB
|
||||
enum class ModulationMode : uint8_t {
|
||||
AM = 0,
|
||||
FM = 1,
|
||||
DSB = 2,
|
||||
USB = 3,
|
||||
LSB = 4
|
||||
};
|
||||
|
||||
ModulationMode modulation = ModulationMode::AM;
|
||||
int32_t user_squelch_level{0};
|
||||
bool squelch_is_open{true};
|
||||
int32_t squelch_hold{0};
|
||||
@@ -79,7 +88,6 @@ class MorseProcessor : public BasebandProcessor {
|
||||
float meas_freq_accumulator{0.0f};
|
||||
uint32_t meas_freq_count{0};
|
||||
uint32_t ui_update_timer{0};
|
||||
|
||||
float current_freq{700.0f};
|
||||
|
||||
// --- Decoding variables (Goertzel) ---
|
||||
@@ -92,6 +100,9 @@ class MorseProcessor : public BasebandProcessor {
|
||||
int64_t noise_floor{5000};
|
||||
int32_t startup_delay{20};
|
||||
|
||||
float dc_average = 0.0f; // DC level tracking
|
||||
int32_t dc_average_int = 0;
|
||||
|
||||
MorseRXDataMessage message{};
|
||||
MorseRXfreqMessage freq_message{};
|
||||
};
|
||||
|
||||
@@ -1681,4 +1681,362 @@ static constexpr fir_taps_real<24> taps_BTLE_Dual_PHY = {
|
||||
3}},
|
||||
};
|
||||
|
||||
static constexpr fir_taps_real<63> taps_2k0_am_lpf_channel = {
|
||||
.low_frequency_normalized = -2000.0f / 48000.0f,
|
||||
.high_frequency_normalized = 2000.0f / 48000.0f,
|
||||
.transition_normalized = 1500.0f / 48000.0f,
|
||||
.taps = {{
|
||||
26,
|
||||
29,
|
||||
31,
|
||||
33,
|
||||
32,
|
||||
28,
|
||||
18,
|
||||
0,
|
||||
-26,
|
||||
-61,
|
||||
-104,
|
||||
-152,
|
||||
-202,
|
||||
-246,
|
||||
-279,
|
||||
-292,
|
||||
-277,
|
||||
-227,
|
||||
-136,
|
||||
0,
|
||||
182,
|
||||
409,
|
||||
673,
|
||||
968,
|
||||
1280,
|
||||
1595,
|
||||
1899,
|
||||
2174,
|
||||
2407,
|
||||
2583,
|
||||
2693,
|
||||
2731,
|
||||
2693,
|
||||
2583,
|
||||
2407,
|
||||
2174,
|
||||
1899,
|
||||
1595,
|
||||
1280,
|
||||
968,
|
||||
673,
|
||||
409,
|
||||
182,
|
||||
0,
|
||||
-136,
|
||||
-227,
|
||||
-277,
|
||||
-292,
|
||||
-279,
|
||||
-246,
|
||||
-202,
|
||||
-152,
|
||||
-104,
|
||||
-61,
|
||||
-26,
|
||||
0,
|
||||
18,
|
||||
28,
|
||||
32,
|
||||
33,
|
||||
31,
|
||||
29,
|
||||
26,
|
||||
}},
|
||||
};
|
||||
|
||||
static constexpr fir_taps_real<64> taps_1K5_FM_channel = {
|
||||
.low_frequency_normalized = 300.0f / 48000.0f,
|
||||
.high_frequency_normalized = 1800.0f / 48000.0f,
|
||||
.transition_normalized = 1000.0f / 48000.0f,
|
||||
.taps = {{
|
||||
24,
|
||||
22,
|
||||
20,
|
||||
15,
|
||||
9,
|
||||
-2,
|
||||
-18,
|
||||
-39,
|
||||
-66,
|
||||
-98,
|
||||
-132,
|
||||
-167,
|
||||
-198,
|
||||
-220,
|
||||
-228,
|
||||
-217,
|
||||
-181,
|
||||
-117,
|
||||
-19,
|
||||
112,
|
||||
277,
|
||||
474,
|
||||
697,
|
||||
941,
|
||||
1197,
|
||||
1454,
|
||||
1702,
|
||||
1930,
|
||||
2128,
|
||||
2285,
|
||||
2394,
|
||||
2451,
|
||||
2451,
|
||||
2394,
|
||||
2285,
|
||||
2128,
|
||||
1930,
|
||||
1702,
|
||||
1454,
|
||||
1197,
|
||||
941,
|
||||
697,
|
||||
474,
|
||||
277,
|
||||
112,
|
||||
-19,
|
||||
-117,
|
||||
-181,
|
||||
-217,
|
||||
-228,
|
||||
-220,
|
||||
-198,
|
||||
-167,
|
||||
-132,
|
||||
-98,
|
||||
-66,
|
||||
-39,
|
||||
-18,
|
||||
-2,
|
||||
9,
|
||||
15,
|
||||
20,
|
||||
22,
|
||||
24,
|
||||
}},
|
||||
};
|
||||
|
||||
static constexpr fir_taps_real<63> taps_1k5_dsb_lpf = {
|
||||
.low_frequency_normalized = -1500.0f / 48000.0f,
|
||||
.high_frequency_normalized = 1500.0f / 48000.0f,
|
||||
.transition_normalized = 1000.0f / 48000.0f,
|
||||
.taps = {{
|
||||
0,
|
||||
0,
|
||||
-1,
|
||||
-5,
|
||||
-10,
|
||||
-19,
|
||||
-31,
|
||||
-46,
|
||||
-64,
|
||||
-82,
|
||||
-99,
|
||||
-111,
|
||||
-113,
|
||||
-100,
|
||||
-64,
|
||||
0,
|
||||
99,
|
||||
239,
|
||||
424,
|
||||
655,
|
||||
932,
|
||||
1251,
|
||||
1605,
|
||||
1983,
|
||||
2372,
|
||||
2757,
|
||||
3120,
|
||||
3447,
|
||||
3719,
|
||||
3925,
|
||||
4053,
|
||||
4096,
|
||||
4053,
|
||||
3925,
|
||||
3719,
|
||||
3447,
|
||||
3120,
|
||||
2757,
|
||||
2372,
|
||||
1983,
|
||||
1605,
|
||||
1251,
|
||||
932,
|
||||
655,
|
||||
424,
|
||||
239,
|
||||
99,
|
||||
0,
|
||||
-64,
|
||||
-100,
|
||||
-113,
|
||||
-111,
|
||||
-99,
|
||||
-82,
|
||||
-64,
|
||||
-46,
|
||||
-31,
|
||||
-19,
|
||||
-10,
|
||||
-5,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
}},
|
||||
};
|
||||
|
||||
// GAIN: 4.0x
|
||||
static constexpr fir_taps_complex<63> taps_1k5_USB_channel = {
|
||||
.low_frequency_normalized = 300.0f / 48000.0f,
|
||||
.high_frequency_normalized = 1800.0f / 48000.0f,
|
||||
.transition_normalized = 300.0f / 48000.0f,
|
||||
.taps = {{
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
{2, 0},
|
||||
{4, 2},
|
||||
{10, 6},
|
||||
{17, 14},
|
||||
{27, 29},
|
||||
{37, 53},
|
||||
{45, 89},
|
||||
{49, 140},
|
||||
{41, 207},
|
||||
{17, 290},
|
||||
{-31, 389},
|
||||
{-109, 499},
|
||||
{-227, 614},
|
||||
{-387, 725},
|
||||
{-595, 819},
|
||||
{-850, 884},
|
||||
{-1147, 904},
|
||||
{-1477, 866},
|
||||
{-1827, 757},
|
||||
{-2179, 569},
|
||||
{-2512, 297},
|
||||
{-2804, -55},
|
||||
{-3031, -480},
|
||||
{-3173, -962},
|
||||
{-3213, -1481},
|
||||
{-3142, -2011},
|
||||
{-2955, -2524},
|
||||
{-2658, -2991},
|
||||
{-2262, -3386},
|
||||
{-1788, -3685},
|
||||
{-1258, -3873},
|
||||
{-703, -3939},
|
||||
{-153, -3884},
|
||||
{366, -3713},
|
||||
{826, -3440},
|
||||
{1208, -3087},
|
||||
{1499, -2677},
|
||||
{1693, -2236},
|
||||
{1789, -1789},
|
||||
{1796, -1359},
|
||||
{1726, -966},
|
||||
{1594, -624},
|
||||
{1420, -341},
|
||||
{1220, -120},
|
||||
{1012, 40},
|
||||
{809, 144},
|
||||
{622, 202},
|
||||
{460, 223},
|
||||
{324, 217},
|
||||
{217, 193},
|
||||
{137, 160},
|
||||
{80, 125},
|
||||
{42, 91},
|
||||
{19, 62},
|
||||
{6, 39},
|
||||
{0, 22},
|
||||
{-1, 11},
|
||||
{-1, 5},
|
||||
{-1, 1},
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
}},
|
||||
};
|
||||
|
||||
// GAIN: 4.0x
|
||||
static constexpr fir_taps_complex<63> taps_1k5_LSB_channel = {
|
||||
.low_frequency_normalized = 300.0f / 48000.0f,
|
||||
.high_frequency_normalized = 1800.0f / 48000.0f,
|
||||
.transition_normalized = 300.0f / 48000.0f,
|
||||
.taps = {{
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
{2, 0},
|
||||
{4, -2},
|
||||
{10, -6},
|
||||
{17, -14},
|
||||
{27, -29},
|
||||
{37, -53},
|
||||
{45, -89},
|
||||
{49, -140},
|
||||
{41, -207},
|
||||
{17, -290},
|
||||
{-31, -389},
|
||||
{-109, -499},
|
||||
{-227, -614},
|
||||
{-387, -725},
|
||||
{-595, -819},
|
||||
{-850, -884},
|
||||
{-1147, -904},
|
||||
{-1477, -866},
|
||||
{-1827, -757},
|
||||
{-2179, -569},
|
||||
{-2512, -297},
|
||||
{-2804, 55},
|
||||
{-3031, 480},
|
||||
{-3173, 962},
|
||||
{-3213, 1481},
|
||||
{-3142, 2011},
|
||||
{-2955, 2524},
|
||||
{-2658, 2991},
|
||||
{-2262, 3386},
|
||||
{-1788, 3685},
|
||||
{-1258, 3873},
|
||||
{-703, 3939},
|
||||
{-153, 3884},
|
||||
{366, 3713},
|
||||
{826, 3440},
|
||||
{1208, 3087},
|
||||
{1499, 2677},
|
||||
{1693, 2236},
|
||||
{1789, 1789},
|
||||
{1796, 1359},
|
||||
{1726, 966},
|
||||
{1594, 624},
|
||||
{1420, 341},
|
||||
{1220, 120},
|
||||
{1012, -40},
|
||||
{809, -144},
|
||||
{622, -202},
|
||||
{460, -223},
|
||||
{324, -217},
|
||||
{217, -193},
|
||||
{137, -160},
|
||||
{80, -125},
|
||||
{42, -91},
|
||||
{19, -62},
|
||||
{6, -39},
|
||||
{0, -22},
|
||||
{-1, -11},
|
||||
{-1, -5},
|
||||
{-1, -1},
|
||||
{0, 0},
|
||||
{0, 0},
|
||||
}},
|
||||
};
|
||||
|
||||
#endif /*__DSP_FIR_TAPS_H__*/
|
||||
|
||||
@@ -1711,6 +1711,7 @@ class MorseRXDataMessage : public Message {
|
||||
: Message{ID::MorseRXData} {}
|
||||
int32_t state_durations[5] = {0}; // positive: high, negative: low
|
||||
uint8_t state_cnt = 0;
|
||||
bool clipped = false;
|
||||
const uint8_t maxptr = 4;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user