Wefax warning fix modulation fix (#2543)

* changed order of modulations, changed case to avoid capture
* added missing AMAudioFMApt mode to dump pmem
* reorder demod, adding missing ones, fix warnings
* removed uneeded 'previous_modulation', renamed WFAX to AMFM to match other places
* removing uneeded 'previous_modulation' uneeded check in change_modulation
* move capture at the end so AMAUdioFMApt is matching the other arrays for position 4
* added AMFM to Recon Level and Scanner

* clang + more details in some comments

---------

Co-authored-by: gullradriel <gullradriel@no-mail.com>
This commit is contained in:
gullradriel 2025-03-07 17:28:11 +01:00 committed by GitHub
parent a17995fd2b
commit 1df318355b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 64 additions and 31 deletions

View File

@ -116,8 +116,8 @@ AMFMAptOptionsView::AMFMAptOptionsView(
}); });
freqman_set_bandwidth_option(AMFM_MODULATION, options_config); // adding the common message from freqman.cpp to the options_config freqman_set_bandwidth_option(AMFM_MODULATION, options_config); // adding the common message from freqman.cpp to the options_config
receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal.
options_config.set_by_value(receiver_model.amfm_configuration()); options_config.set_by_value(receiver_model.amfm_configuration());
receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal.
} }
/* SPECOptionsView *******************************************************/ /* SPECOptionsView *******************************************************/
@ -193,9 +193,10 @@ AnalogAudioView::AnalogAudioView(
}; };
auto modulation = receiver_model.modulation(); auto modulation = receiver_model.modulation();
// This app doesn't handle "Capture" mode. // This app doesn't handle "Capture" mode.
if (modulation > ReceiverModel::Mode::SpectrumAnalysis) // This two should be together in the last index position : SpectrumAnalysis = 4, and Capture = 5 if (modulation == ReceiverModel::Mode::Capture)
modulation = ReceiverModel::Mode::SpectrumAnalysis; // For sw simplicity , Wefax_mode, should NOT be added between. modulation = ReceiverModel::Mode::SpectrumAnalysis;
options_modulation.set_by_value(toUType(modulation)); options_modulation.set_by_value(toUType(modulation));
options_modulation.on_change = [this](size_t, OptionsField::value_t v) { options_modulation.on_change = [this](size_t, OptionsField::value_t v) {
@ -285,10 +286,6 @@ void AnalogAudioView::on_baseband_bandwidth_changed(uint32_t bandwidth_hz) {
} }
void AnalogAudioView::on_modulation_changed(ReceiverModel::Mode modulation) { void AnalogAudioView::on_modulation_changed(ReceiverModel::Mode modulation) {
// This app doesn't know what to do with "Capture" mode.
if (modulation > ReceiverModel::Mode::SpectrumAnalysis)
modulation = ReceiverModel::Mode::SpectrumAnalysis;
baseband::spectrum_streaming_stop(); baseband::spectrum_streaming_stop();
update_modulation(modulation); update_modulation(modulation);
on_show_options_modulation(); on_show_options_modulation();

View File

@ -224,11 +224,13 @@ class AnalogAudioView : public View {
OptionsField options_modulation{ OptionsField options_modulation{
{0 * 8, 0 * 16}, {0 * 8, 0 * 16},
4, 4,
{{" AM ", toUType(ReceiverModel::Mode::AMAudio)}, {
{"NFM ", toUType(ReceiverModel::Mode::NarrowbandFMAudio)}, {" AM ", toUType(ReceiverModel::Mode::AMAudio)},
{"WFM ", toUType(ReceiverModel::Mode::WidebandFMAudio)}, {"NFM ", toUType(ReceiverModel::Mode::NarrowbandFMAudio)},
{"WFAX", toUType(ReceiverModel::Mode::AMAudioFMApt)}, // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod {"WFM ", toUType(ReceiverModel::Mode::WidebandFMAudio)},
{"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)}}}; {"SPEC", toUType(ReceiverModel::Mode::SpectrumAnalysis)},
{"AMFM", toUType(ReceiverModel::Mode::AMAudioFMApt)} // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod
}};
AudioVolumeField field_volume{ AudioVolumeField field_volume{
{28 * 8, 0 * 16}}; {28 * 8, 0 * 16}};

View File

@ -45,7 +45,7 @@ using option_db_t = std::pair<std::string_view, int32_t>;
using options_db_t = std::vector<option_db_t>; using options_db_t = std::vector<option_db_t>;
extern options_db_t freqman_modulations; extern options_db_t freqman_modulations;
extern options_db_t freqman_bandwidths[4]; extern options_db_t freqman_bandwidths[5];
extern options_db_t freqman_steps; extern options_db_t freqman_steps;
extern options_db_t freqman_steps_short; extern options_db_t freqman_steps_short;

View File

@ -277,6 +277,15 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
field_bw.set_by_value(0); field_bw.set_by_value(0);
field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_wfm_configuration(n); }; field_bw.on_change = [this](size_t index, OptionsField::value_t n) { radio_bw = index ; receiver_model.set_wfm_configuration(n); };
break; break;
case AMFM_MODULATION:
audio_sampling_rate = audio::Rate::Hz_12000;
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt);
receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal.
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; };
break;
case SPEC_MODULATION: case SPEC_MODULATION:
audio_sampling_rate = audio::Rate::Hz_24000; audio_sampling_rate = audio::Rate::Hz_24000;
freqman_set_bandwidth_option(new_mod, field_bw); freqman_set_bandwidth_option(new_mod, field_bw);

View File

@ -1227,6 +1227,16 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
text_ctcss.set(" "); text_ctcss.set(" ");
recording_sampling_rate = 48000; recording_sampling_rate = 48000;
break; break;
case AMFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt);
receiver_model.set_amfm_configuration(5); // Fix index 5 manually, not from freqman: set to RX AM (USB+FM) mode to demod audio tone, and get Wefax_APT signal.
field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; };
field_bw.set_by_value(0);
text_ctcss.set(" ");
recording_sampling_rate = 12000;
break;
case SPEC_MODULATION: case SPEC_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw); freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_capture); baseband::run_image(portapack::spi_flash::image_tag_capture);

View File

@ -725,6 +725,14 @@ void ScannerView::change_mode(freqman_index_t new_mod) {
field_bw.set_by_value(receiver_model.wfm_configuration()); field_bw.set_by_value(receiver_model.wfm_configuration());
field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); }; field_bw.on_change = [this](size_t, OptionsField::value_t n) { receiver_model.set_wfm_configuration(n); };
break; break;
case AMFM_MODULATION:
freqman_set_bandwidth_option(new_mod, field_bw);
baseband::run_image(portapack::spi_flash::image_tag_am_audio);
receiver_model.set_modulation(ReceiverModel::Mode::AMAudioFMApt);
receiver_model.set_amfm_configuration(5);
field_bw.set_by_value(0);
field_bw.on_change = [this](size_t, OptionsField::value_t n) { (void)n; };
break;
default: default:
break; break;
} }

View File

@ -66,10 +66,10 @@ static void send_message(const Message* const message) {
void AMConfig::apply() const { void AMConfig::apply() const {
const AMConfigureMessage message{ const AMConfigureMessage message{
taps_6k0_decim_0, // common FIR filter taps pre-decim_0 to all 6 x AM mod types.(AM-9K, AM-6K, USB, LSB, CW, WFAX) taps_6k0_decim_0, // common FIR filter taps pre-decim_0 to all 6 x AM mod types.(AM-9K, AM-6K, USB, LSB, CW, AMFM-WFAX)
taps_6k0_decim_1, // common FIR filter taps pre-decim_1 to all 6 x AM mod. types. (") taps_6k0_decim_1, // common FIR filter taps pre-decim_1 to all 6 x AM mod. types. (")
decim_2, // var decim_2 FIR taps filter , variable values, depending selected AM mod(AM 9k / 6k and all rest AM modes) decim_2, // var decim_2 FIR taps filter , variable values, depending selected AM mod(AM 9k / 6k and all rest AM modes)
channel, // var channel FIR taps filter , variable values, depending selected AM mode, each one different (DSB-9K, DSB-6K, USB-3K, LSB-3K,CW,WFAX) channel, // var channel FIR taps filter , variable values, depending selected AM mode, each one different (DSB-9K, DSB-6K, USB-3K, LSB-3K,CW,AMFM-WFAX)
modulation, // var parameter . enum class Modulation : int32_t {DSB = 0, SSB = 1, SSB_FM = 2} modulation, // var parameter . enum class Modulation : int32_t {DSB = 0, SSB = 1, SSB_FM = 2}
audio_12k_iir_filter_config}; // var parameter , 300 Hz hpf all except Wefax (1.500Hz lpf) audio_12k_iir_filter_config}; // var parameter , 300 Hz hpf all except Wefax (1.500Hz lpf)
send_message(&message); send_message(&message);

View File

@ -41,8 +41,8 @@ enum freqman_entry_modulation : uint8_t {
AM_MODULATION = 0, AM_MODULATION = 0,
NFM_MODULATION, NFM_MODULATION,
WFM_MODULATION, WFM_MODULATION,
AMFM_MODULATION, // Added for Wefax. SPEC_MODULATION,
SPEC_MODULATION AMFM_MODULATION // Added for Wefax.
}; };
// TODO: Can these be removed after Recon is migrated to FreqmanDB? // TODO: Can these be removed after Recon is migrated to FreqmanDB?

View File

@ -49,6 +49,7 @@ options_t freqman_modulations = {
{"NFM", 1}, {"NFM", 1},
{"WFM", 2}, {"WFM", 2},
{"SPEC", 3}, {"SPEC", 3},
{"AMFM", 4},
}; };
options_t freqman_bandwidths[5] = { options_t freqman_bandwidths[5] = {
@ -72,10 +73,6 @@ options_t freqman_bandwidths[5] = {
{"180k", 1}, {"180k", 1},
{"200k", 0}, {"200k", 0},
}, },
{
// AMFM for Wefax-
{"USB+FM", 5}, // Fixed RX demodul AM config Index 5 : USB+FM for Audio Weather fax (Wfax) tones.
},
{ {
// SPEC -- TODO: these should be indexes. // SPEC -- TODO: these should be indexes.
{"12k5", 12500}, {"12k5", 12500},
@ -103,7 +100,12 @@ options_t freqman_bandwidths[5] = {
{"4500k", 4500000}, {"4500k", 4500000},
{"5000k", 5500000}, {"5000k", 5500000},
{"5500k", 5500000}, // Max capture, needs /4 decimation, (22Mhz sampling ADC). {"5500k", 5500000}, // Max capture, needs /4 decimation, (22Mhz sampling ADC).
}}; },
{
// AMFM for Wefax-
{"USB+FM", 5}, // Fixed RX demodul AM config Index 5 : USB+FM for Audio Weather fax (WFAX) tones.
},
};
// TODO: these should be indexes. // TODO: these should be indexes.
options_t freqman_steps = { options_t freqman_steps = {

View File

@ -40,9 +40,9 @@ class ReceiverModel {
AMAudio = 0, AMAudio = 0,
NarrowbandFMAudio = 1, NarrowbandFMAudio = 1,
WidebandFMAudio = 2, WidebandFMAudio = 2,
AMAudioFMApt = 3, // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod SpectrumAnalysis = 3,
SpectrumAnalysis = 4, AMAudioFMApt = 4, // Added to handle HF WeatherFax , SSB (USB demod) + Tone_Subcarrier FM demod
Capture = 5 Capture = 5,
}; };
struct settings_t { struct settings_t {

View File

@ -72,7 +72,7 @@ void AudioOutput::on_block(const buffer_f32_t& audio) {
if (do_processing) { if (do_processing) {
const auto audio_present_now = squelch.execute(audio); const auto audio_present_now = squelch.execute(audio);
hpf.execute_in_place(audio); // IIRBiquadFilter name is "hpf", but we will call with "hpf-coef" for all except WFAX with "lpf-coef". hpf.execute_in_place(audio); // IIRBiquadFilter name is "hpf", but we will call with "hpf-coef" for all except AMFM (WFAX) with "lpf-coef"
deemph.execute_in_place(audio); deemph.execute_in_place(audio);
audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0); audio_present_history = (audio_present_history << 1) | (audio_present_now ? 1 : 0);

View File

@ -79,7 +79,7 @@ static inline float angle_precise(const complex32_t t) {
return atan2f(t.imag(), t.real()); return atan2f(t.imag(), t.real());
} }
buffer_f32_t SSB_FM::execute( // Added to handle WFAX (HF weather map )- buffer_f32_t SSB_FM::execute( // Added to handle AMFM (WFAX, HF weather map )
const buffer_c16_t& src, // input arg , pointer Complex c16 i,q buffer. const buffer_c16_t& src, // input arg , pointer Complex c16 i,q buffer.
const buffer_f32_t& dst) { // input arg , pointer f32 buffer audio demodulated const buffer_f32_t& dst) { // input arg , pointer f32 buffer audio demodulated
complex16_t* src_p = src.p; // removed const ; init src_p pointer with the mem address pointed by src.p. complex16_t* src_p = src.p; // removed const ; init src_p pointer with the mem address pointed by src.p.

View File

@ -48,7 +48,7 @@ class SSB {
static constexpr float k = 1.0f / 32768.0f; static constexpr float k = 1.0f / 32768.0f;
}; };
class SSB_FM { // Added to handle WFAX- class SSB_FM { // Added to handle AMFM for WFAX
public: public:
buffer_f32_t execute( buffer_f32_t execute(
const buffer_c16_t& src, const buffer_c16_t& src,
@ -56,7 +56,7 @@ class SSB_FM { // Added to handle WFAX-
private: private:
static constexpr float k = 1.0f / 32768.0f; static constexpr float k = 1.0f / 32768.0f;
dsp::Real_to_Complex real_to_complex; // It is a member variable of SSB_FM. dsp::Real_to_Complex real_to_complex{}; // It is a member variable of SSB_FM.
}; };
class FM { class FM {

View File

@ -65,7 +65,9 @@ buffer_f32_t NarrowbandAMAudio::demodulate(const buffer_c16_t& channel) {
return demod_ssb_fm.execute(channel, audio_buffer); // Calling a derivative of demod_ssb (USB) , but with different FIR taps + FM audio tones demod. return demod_ssb_fm.execute(channel, audio_buffer); // Calling a derivative of demod_ssb (USB) , but with different FIR taps + FM audio tones demod.
break; break;
// return demod am as a default
default: default:
return demod_am.execute(channel, audio_buffer);
break; break;
} }
} }

View File

@ -34,7 +34,7 @@ constexpr iir_biquad_df2_config_t half_band_lpf_config[5] = {
{1.0f, 0.08720754, 1.0f, 1.0f, 0.00220944f, 0.98743139f}}; {1.0f, 0.08720754, 1.0f, 1.0f, 0.00220944f, 0.98743139f}};
// scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5, rs = 60.0, Wn = 0.99, btype = 'lowpass', output="sos") // scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5, rs = 60.0, Wn = 0.99, btype = 'lowpass', output="sos")
// 6khz cutofff @fs:12Khz , used in WFAX demod. // 6khz cutofff @fs:12Khz , used in AMFM demod for WFAX
constexpr iir_biquad_df2_config_t full_band_lpf_config[5] = { constexpr iir_biquad_df2_config_t full_band_lpf_config[5] = {
{0.88095275f, 1.76184993f, 0.88095275f, 1.0f, 1.89055677f, 0.89616378f}, {0.88095275f, 1.76184993f, 0.88095275f, 1.0f, 1.89055677f, 0.89616378f},
{1.0f, 1.99958798f, 1.0f, 1.0f, 1.9781807f, 0.98002549f}, {1.0f, 1.99958798f, 1.0f, 1.0f, 1.9781807f, 0.98002549f},
@ -43,7 +43,7 @@ constexpr iir_biquad_df2_config_t full_band_lpf_config[5] = {
{1.0f, 1.99909558f, 1.0f, 1.0f, 1.9986187f, 0.99960319f}}; {1.0f, 1.99909558f, 1.0f, 1.0f, 1.9986187f, 0.99960319f}};
// scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5 , rs = 60.0, Wn = 0.25, btype = 'lowpass', output="sos") // scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5 , rs = 60.0, Wn = 0.25, btype = 'lowpass', output="sos")
// 1.5khz cutofff @fs:12Khz, used in WFAX demod. // 1.5khz cutofff @fs:12Khz, used in AMFM demod for WFAX
constexpr iir_biquad_df2_config_t quarter_band_lpf_config[5] = { constexpr iir_biquad_df2_config_t quarter_band_lpf_config[5] = {
{0.00349312f, 0.00319397f, 0.00349312f, 1.0f, -1.53025211f, 0.6203438f}, {0.00349312f, 0.00319397f, 0.00349312f, 1.0f, -1.53025211f, 0.6203438f},
{1.0f, -0.83483341f, 1.0f, 1.0f, -1.47619047f, 0.77120659f}, {1.0f, -0.83483341f, 1.0f, 1.0f, -1.47619047f, 0.77120659f},

View File

@ -1329,6 +1329,9 @@ bool debug_dump() {
case ReceiverModel::Mode::Capture: case ReceiverModel::Mode::Capture:
pmem_dump_file.write_line("modulation: Mode::Capture"); pmem_dump_file.write_line("modulation: Mode::Capture");
break; break;
case ReceiverModel::Mode::AMAudioFMApt:
pmem_dump_file.write_line("modulation: Mode::AMAudioFMApt");
break;
default: default:
pmem_dump_file.write_line("modulation: !!unknown mode!!"); pmem_dump_file.write_line("modulation: !!unknown mode!!");
break; break;