mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-15 11:02:58 +00:00
Opt-in channel-power squelch for AM audio RX (#3315)
* AM: add opt-in channel-power squelch for AM audio RX Add an SDR++-style power squelch on the complex channel signal for the Analog Audio RX app in AM modes (DSB/SSB/CW). The squelch measures the mean channel power, converts it to dBFS, and mutes the demodulated audio when the signal is below a user-set threshold. Being carrier-based it keys on the AM carrier (e.g. airband/ATC) rather than on audio-band noise, which the existing FM squelch could not do for AM. A new 'SQ' field (0-99, 0 = off) is added to the AM options view and is persisted per app via app_settings. Default is 0, so existing AM behaviour is unchanged unless the user enables it. Threshold maps 1..99 to -80..-20 dBFS. Touches: message (AMConfigureMessage.squelch_level), baseband_api (AMConfig::apply), receiver_model (am_squelch_level get/set), app_settings (persistence), proc_am_audio (DSP), analog_audio_app (UI). * Refactor audio power calculation to use magnitude squared Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include "dsp_hilbert.hpp"
|
||||
|
||||
// Phase 2: Constructor to start threads AFTER object is fully initialized
|
||||
@@ -72,6 +73,32 @@ void NarrowbandAMAudio::execute(const buffer_c8_t& buffer) {
|
||||
feed_channel_stats(channel_out);
|
||||
|
||||
auto audio = demodulate(channel_out); // now 3 AM demodulation types : demod_am, demod_ssb, demod_ssb_fm (for Wefax)
|
||||
|
||||
// SDR++-style power squelch on the complex channel signal (opt-in; 0 = off).
|
||||
// Measures mean channel power, converts to dBFS, and mutes the audio when
|
||||
// the signal is below the user threshold. Carrier-based, so it keys on the
|
||||
// AM carrier (e.g. airband/ATC) rather than on audio-band noise.
|
||||
if (squelch_level > 0 && channel_out.count > 0) {
|
||||
uint64_t sum_mag_sq = 0;
|
||||
for (size_t i = 0; i < channel_out.count; i++) {
|
||||
const int32_t re = channel_out.p[i].real();
|
||||
const int32_t im = channel_out.p[i].imag();
|
||||
sum_mag_sq += static_cast<uint64_t>(re) * re + static_cast<uint64_t>(im) * im;
|
||||
}
|
||||
|
||||
constexpr float full_scale_mag2 = 32768.0f * 32768.0f;
|
||||
const float mean_mag2_norm =
|
||||
static_cast<float>(sum_mag_sq) / (static_cast<float>(channel_out.count) * full_scale_mag2);
|
||||
const float level_dbfs = (mean_mag2_norm > 0.0f) ? mag2_to_dbv_norm(mean_mag2_norm) : -200.0f;
|
||||
|
||||
// Map squelch_level 1..99 to a threshold of -80..-20 dBFS.
|
||||
const float threshold_dbfs = -80.0f + (squelch_level - 1) * (60.0f / 98.0f);
|
||||
if (level_dbfs < threshold_dbfs) {
|
||||
for (size_t i = 0; i < audio.count; i++)
|
||||
audio.p[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
audio_compressor.execute_in_place(audio);
|
||||
audio_output.write(audio);
|
||||
}
|
||||
@@ -151,6 +178,7 @@ void NarrowbandAMAudio::configure(const AMConfigureMessage& message) {
|
||||
spectrum_interval_samples =
|
||||
decim_0_output_fs / spectrum_rate_hz;
|
||||
audio_output.configure(message.audio_hpf_lpf_config); // hpf in all AM demod modes (AM-6K/9K, USB/LSB,DSB), except Wefax (lpf there).
|
||||
squelch_level = message.squelch_level;
|
||||
|
||||
configured = true;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ class NarrowbandAMAudio : public BasebandProcessor {
|
||||
int32_t channel_filter_high_f = 0;
|
||||
int32_t channel_filter_transition = 0;
|
||||
bool configured{false};
|
||||
uint8_t squelch_level{0}; // AM channel-power squelch threshold (0 = off), SDR++-style
|
||||
size_t spectrum_interval_samples{0};
|
||||
size_t spectrum_samples{0};
|
||||
bool spectrum_capture_active{false};
|
||||
|
||||
Reference in New Issue
Block a user