From 25dfa962572928946ec532545ca03bb27ad83b53 Mon Sep 17 00:00:00 2001 From: Brumi-2021 Date: Mon, 14 Nov 2022 00:32:29 +0100 Subject: [PATCH 1/2] Adding FIR_taps for EU AM broadcasting 9K00A3E --- firmware/common/dsp_fir_taps.hpp | 49 +++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/firmware/common/dsp_fir_taps.hpp b/firmware/common/dsp_fir_taps.hpp index 5df9f515..c6d37660 100644 --- a/firmware/common/dsp_fir_taps.hpp +++ b/firmware/common/dsp_fir_taps.hpp @@ -245,12 +245,29 @@ constexpr fir_taps_real<32> taps_6k0_decim_2 { 11815, 10413, 7946, 4978, 2134, -83, -1411, -1857, -1640, -1080, -474, -21, 208, 247, 178, 95, } }, +}; + +// IFIR prototype filter fs=48000 ; pass=4500 , stop=7800, decim=4, fout=12000 +// For Europe AM commercial broadcasting stations in LF/MF/HF, Emissions Designator 9K00A3E Bandwidth: 9.00 kHz (derivated from taps_6k0_decim_2 ): +// Pre-decimate LPF FIR filter design Created by SciPy Python with the "window method", num_taps = 32, cut_off = 4950. sample_rate = 48000 # Hz, +// Created with h = signal.firwin(num_taps, cut_off, nyq=sample_rate/2, window=('chebwin',49)) , achieving good STOP band plot < -60 dB's with some ripple. +// post-escaled h taps to avoid decimals , targetting <= similar int values as previous taps_6k0_dsb_channel peak < 32.767 (2 exp 15) and similar H(f)gain +constexpr fir_taps_real<32> taps_9k0_decim_2 { + .low_frequency_normalized = -4500.0f / 48000.0f, // Negative -cutt off freq -3dB (real achieved data ,in the plot and measurements) + .high_frequency_normalized = 4500.0f / 48000.0f, // Positive +cutt off freq -3dB (idem) + .transition_normalized = 3300.0f / 48000.0f, // 3300 Hz = (7800 Hz - 4500 Hz) (both from plot H(f) curve plot) + .taps = { { + -40, 3, 98, 239, 340, 266, -96, -726, + -1391, -1659, -1041, 772, 3691, 7156, 10271, 12118, + 12118, 10271, 7156, 3691, 772, -1041, -1659, -1391, + -726, -96, 266, 340, 239, 98, 3, -40 + } }, }; // Channel filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000 /* NOTE: Slightly less than 1.0 gain (normalized to 65536) due to max(taps) being * slightly larger than 32767 (33312). - */ +*/ constexpr fir_taps_complex<64> taps_6k0_dsb_channel { .low_frequency_normalized = -3000.0f / 12000.0f, .high_frequency_normalized = 3000.0f / 12000.0f, @@ -275,6 +292,36 @@ constexpr fir_taps_complex<64> taps_6k0_dsb_channel { } }, }; +// Channel filter: fs=12000, pass=4450, stop=4800, decim=1, fout=12000 (4k45 selected = aprox 4k5, after several iterative plot H(f) test, best trade off curve) +// For Europe AM commercial broadcasting stations in LF/MF/HF, Emissions Designator 9K00A3E Bandwidth: 9.00 kHz (derivative from taps_6k0_dsb_channel) +// FIR filter design created by SciPy Python with the "window method"; num_taps = 64, cut_off = 4450. sample_rate = 12000 # Hz, +// Created with : h=signal.firwin(num_taps, cut_off, nyq=sample_rate/2, window=('chebwin',50)), achieving good STOP band plot < -60 dB's with some ripple. +// post-escaled h taps to avoid decimals , targetting <= similar int values as previous taps_6k0_dsb_channel peak < 32.767 (2 exp 15), (29253) and similar H(f)gain +constexpr fir_taps_complex<64> taps_9k0_dsb_channel { + .low_frequency_normalized = -4500.0f / 12000.0f, // Negative -cutt off freq -3dB (in the H(f) curve plot) + .high_frequency_normalized = 4500.0f / 12000.0f, // Positive +cutt off freq -3dB (in the H(f) curve plot) + .transition_normalized = 350.0f / 12000.0f, // 350Hz = (4800 Hz -4450 Hz) cut-3dB's (both data comes from H(f) curve plot and confirmed by measurements ) + .taps = { { + { -34, 0 }, { 23, 0 }, { -13, 0 }, { -19, 0 }, + { 55, 0 }, { -65, 0 }, { 25, 0 }, { 59, 0 }, + { -137, 0 }, { 141, 0 }, { -35, 0 }, { -146, 0 }, + { 287, 0 }, { -262, 0 }, { 26, 0 }, { 317, 0 }, + { -544, 0 }, { 441, 0 }, { 29, 0 }, { -638, 0 }, + { 980, 0 }, { -707, 0 }, { -191, 0 }, { 1272, 0 }, + { -1805, 0 }, { 1175, 0 }, { 660, 0 }, { -2934, 0 }, + { 4214, 0 }, { -2774, 0 }, { -3655, 0 }, { 29253, 0 }, + { 29253, 0 }, { -3655, 0 }, { -2774, 0 }, { 4214, 0 }, + { -2934, 0 }, { 660, 0 }, { 1175, 0 }, { -1805, 0 }, + { 1272, 0 }, { -191, 0 }, { -707, 0 }, { 980, 0 }, + { -638, 0 }, { 29, 0 }, { 441, 0 }, { -544, 0 }, + { 317, 0 }, { 26, 0 }, { -262, 0 }, { 287, 0 }, + { -146, 0 }, { -35, 0 }, { 141, 0 }, { -137, 0 }, + { 59, 0 }, { 25, 0 }, { -65, 0 }, { 55, 0 }, + { -19, 0 }, { -13, 0 }, { 23, 0 }, { -34, 0 }, + } }, +}; + + // USB AM 2K80J3E emission type /////////////////////////////////////////// // IFIR prototype filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000 From 1e4c93b979f3ef34446a49ec4deee60d00925872 Mon Sep 17 00:00:00 2001 From: Brumi-2021 Date: Sat, 19 Nov 2022 18:17:54 +0100 Subject: [PATCH 2/2] Final opt. AM-9K, applied to Audio_RX and Mic App. --- .../application/apps/analog_audio_app.hpp | 11 ++-- firmware/application/apps/ui_mictx.cpp | 23 ++++--- firmware/application/baseband_api.cpp | 10 +-- firmware/application/baseband_api.hpp | 1 + firmware/application/receiver_model.cpp | 11 ++-- firmware/common/dsp_fir_taps.hpp | 62 +++++++++---------- 6 files changed, 63 insertions(+), 55 deletions(-) diff --git a/firmware/application/apps/analog_audio_app.hpp b/firmware/application/apps/analog_audio_app.hpp index fd6f5bc1..36815079 100644 --- a/firmware/application/apps/analog_audio_app.hpp +++ b/firmware/application/apps/analog_audio_app.hpp @@ -53,12 +53,13 @@ private: OptionsField options_config { { 3 * 8, 0 * 16 }, - 4, + 5, { - { "DSB ", 0 }, - { "USB ", 0 }, - { "LSB ", 0 }, - { "CW ", 0 }, + { "DSB 9k ", 0 }, + { "DSB 6k ", 0 }, + { "USB+3k ", 0 }, + { "LSB-3k ", 0 }, + { "CW ", 0 }, } }; }; diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index f164aec1..d7a13a7e 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -163,7 +163,7 @@ void MicTXView::rxaudio(bool is_on) { baseband::run_image(portapack::spi_flash::image_tag_am_audio); receiver_model.set_modulation(ReceiverModel::Mode::AMAudio); // that AM demodulation engine is common to all Amplitude mod : AM/USB/LSB/DSB (2,3,4,5) if (options_mode.selected_index() < 5) // We will be called here with 2,3,4,5 . We treat here demod. filter 2,3,4; (excluding DSB-C case (5) it is treated more down). - receiver_model.set_am_configuration(options_mode.selected_index() - 2); // selecting proper filter(2,3,4). 2-2=0=>6k-AM(0) , 3-2=1=>+3k-USB(1), 4-2=2=>-3K-LSB(2), + receiver_model.set_am_configuration(options_mode.selected_index() - 1); // selecting proper filter(2,3,4). 2-1=1=>6k-AM(1) , 3-1=2=>+3k-USB(2), 4-1=3=>-3K-LSB(3), } else { // We are in NFM/FM or WFM (NFM BW:8k5 or 11k / FM BW 16k / WFM BW:200k) @@ -423,7 +423,8 @@ MicTXView::MicTXView( set_dirty(); // Refresh display options_tone_key.hidden(1); // we hide that Key-tones & CTCSS input selecction, (no meaning in AM/DSB/SSB). - rxbw.emplace_back(" 6k-AM ", 0); // locked a fixed option , to display it . + rxbw.emplace_back(" DSB1-9k ", 0); // we offer in AM DSB two audio BW 9k / 6k . + rxbw.emplace_back(" DSB2-6k ", 1); field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. field_rxbw.hidden(0); // we show fixed RX AM BW 6Khz @@ -436,7 +437,7 @@ MicTXView::MicTXView( check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. check_rogerbeep.hidden(1); // hide that roger beep selection. - rxbw.emplace_back(" 3k-USB ", 0); // locked a fixed option , to display it . + rxbw.emplace_back(" USB+3k ", 0); // locked a fixed option , to display it . field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. set_dirty(); // Refresh display @@ -447,7 +448,7 @@ MicTXView::MicTXView( check_rogerbeep.set_value(false); // reset the possible activation of roger beep, because it is not compatible with SSB , by now. check_rogerbeep.hidden(1); // hide that roger beep selection. - rxbw.emplace_back(" 3k-LSB ", 0); // locked a fixed option , to display it . + rxbw.emplace_back(" LSB-3k ", 0); // locked a fixed option , to display it . field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. set_dirty(); // Refresh display @@ -457,8 +458,8 @@ MicTXView::MicTXView( rxaudio(rx_enabled); //Update now if we have RX audio on check_rogerbeep.hidden(0); // make visible again the "rogerbeep" selection. - rxbw.emplace_back("SSB1:3k-USB", 0); // added dynamically two options (index 0,1) to that DSB-C case to the field_rxbw value. - rxbw.emplace_back("SSB2:3k-LSB", 1); + rxbw.emplace_back("SSB1:USB+3k", 0); // added dynamically two options (index 0,1) to that DSB-C case to the field_rxbw value. + rxbw.emplace_back("SSB2:LSB-3k", 1); field_rxbw.set_options(rxbw); // store that aux GUI option to the field_rxbw. @@ -542,9 +543,13 @@ MicTXView::MicTXView( // In Previous fw versions, that nbfm_configuration(n) was done in any mode (FM/AM/SSB/DSB)...strictly speaking only need it in (NFM/FM) receiver_model.set_nbfm_configuration(v ); // we are in NFM/FM case, we need to select proper NFM/FM RX channel filter , NFM BW 8K5(0), NFM BW 11K(1) , FM BW 16K (2) } - else { // we are not in NFM/FM mode .(we could be in any of the rest : AM /USB/LSB/DSB-C) - if (enable_dsb) { // we are in DSB-SC in TX mode , we will allow both independent RX SSB demodulation (USB / LSB side band) - receiver_model.set_am_configuration(v +1 ); // we are in DSB-C TX mode , we need to select proper SSB filter. 0+1 =>usb(1), 1+1=2 =>lsb(2), + else { // we are not in NFM/FM mode .(we could be in any of the rest : AM /USB/LSB/DSB-SC) + if (enable_am) { // we are in AM TX mode , we will allow both independent RX audio BW : AM 9K (9K00AE3 / AM 6K (6K00AE3). (In AM option v can be 0 (9k) , 1 (6k) + receiver_model.set_am_configuration(v ); // we are in AM TX mode , we need to select proper AM full path config AM-9K filter. 0+0 =>AM-9K(0), 0+1=1 =>AM-6K(1), + } + + if (enable_dsb) { // we are in DSB-SC in TX mode , we will allow both independent RX SSB demodulation (USB / LSB side band). in that submenu, v is 0 (SSB1 USB) or 1 (SSB2 LSB) + receiver_model.set_am_configuration(v +2 ); // we are in DSB-SC TX mode , we need to select proper SSB filter. 0+2 =>usb(2), 1+2=3 =>lsb(3), } } }; diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index ec7ba1a6..3f7fe12d 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -45,11 +45,11 @@ static void send_message(const Message* const message) { void AMConfig::apply() const { const AMConfigureMessage message { - taps_6k0_decim_0, - taps_6k0_decim_1, - taps_6k0_decim_2, - channel, - modulation, + taps_6k0_decim_0, // common FIR filter taps pre-decim_0 to all 5 x AM mod types.(AM-9K, AM-6K, USB, LSB, CW) + taps_6k0_decim_1, // common FIR filter taps pre-decim_1 to all 5 x AM mod. types. + decim_2, // var decim_2 FIR taps filter , variable values, depending selected AM mod(AM 9k / 6k 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) + modulation, // var parameter . audio_12k_hpf_300hz_config }; send_message(&message); diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 5c9b3c95..e28a49e7 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -36,6 +36,7 @@ namespace baseband { struct AMConfig { + const fir_taps_real<32> decim_2; // added to handle two types decim_2 9k, 6k const fir_taps_complex<64> channel; const AMConfigureMessage::Modulation modulation; diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index bef08025..c62d56d2 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -38,11 +38,12 @@ using namespace portapack; namespace { -static constexpr std::array am_configs { { - { taps_6k0_dsb_channel, AMConfigureMessage::Modulation::DSB }, - { taps_2k8_usb_channel, AMConfigureMessage::Modulation::SSB }, - { taps_2k8_lsb_channel, AMConfigureMessage::Modulation::SSB }, - { taps_0k7_usb_channel, AMConfigureMessage::Modulation::SSB }, +static constexpr std::array am_configs { { // we config here all the non COMMON parameters to each AM modulation type in RX. + { taps_9k0_decim_2, taps_9k0_dsb_channel, AMConfigureMessage::Modulation::DSB }, // AM DSB-C BW 9khz (+-4k5) commercial EU bandwidth . + { taps_6k0_decim_2, taps_6k0_dsb_channel, AMConfigureMessage::Modulation::DSB }, // AM DSB-C BW 6khz (+-3k0) narrow AM , ham equipments. + { taps_6k0_decim_2, taps_2k8_usb_channel, AMConfigureMessage::Modulation::SSB }, // SSB USB BW 2K8 (+ 2K8) + { taps_6k0_decim_2, taps_2k8_lsb_channel, AMConfigureMessage::Modulation::SSB }, // SSB LSB BW 2K8 (- 2K8) + { taps_6k0_decim_2, taps_0k7_usb_channel, AMConfigureMessage::Modulation::SSB }, // SSB USB BW 0K7 (+ 0K7) used to get audio tone from CW Morse, assuming tx shifted +700hz aprox } }; static constexpr std::array nbfm_configs { { diff --git a/firmware/common/dsp_fir_taps.hpp b/firmware/common/dsp_fir_taps.hpp index c6d37660..3b9f474a 100644 --- a/firmware/common/dsp_fir_taps.hpp +++ b/firmware/common/dsp_fir_taps.hpp @@ -247,20 +247,20 @@ constexpr fir_taps_real<32> taps_6k0_decim_2 { } }, }; -// IFIR prototype filter fs=48000 ; pass=4500 , stop=7800, decim=4, fout=12000 -// For Europe AM commercial broadcasting stations in LF/MF/HF, Emissions Designator 9K00A3E Bandwidth: 9.00 kHz (derivated from taps_6k0_decim_2 ): -// Pre-decimate LPF FIR filter design Created by SciPy Python with the "window method", num_taps = 32, cut_off = 4950. sample_rate = 48000 # Hz, -// Created with h = signal.firwin(num_taps, cut_off, nyq=sample_rate/2, window=('chebwin',49)) , achieving good STOP band plot < -60 dB's with some ripple. -// post-escaled h taps to avoid decimals , targetting <= similar int values as previous taps_6k0_dsb_channel peak < 32.767 (2 exp 15) and similar H(f)gain +// IFIR prototype filter fs=48000 ; pass=4500 (cutt off -3dBs) , stop=8000 (<-60dBs), decim=4, fout=12000 +// For Europe AM commercial broadcasting stations in LF/MF/HF, Emissions Designator 9K00A3E Bandwidth: 9.00 kHz (derivated from taps_6k0_decim_2 ) +// Pre-decimate LPF FIR filter design Created with SciPy Python with the "window method", num_taps = 32, cut_off = 5150. sample_rate = 48000 # Hz, +// Created with h = signal.firwin(num_taps, cut_off, nyq=sample_rate/2, window=('chebwin',50)) , achieving good STOP band plot < -60 dB's with some ripple. +// post-scaled h taps to avoid decimals , targeting <= similar int values as previous taps_6k0_dsb_channel peak < 32.767 (2 exp 15) and similar H(f)gain constexpr fir_taps_real<32> taps_9k0_decim_2 { .low_frequency_normalized = -4500.0f / 48000.0f, // Negative -cutt off freq -3dB (real achieved data ,in the plot and measurements) .high_frequency_normalized = 4500.0f / 48000.0f, // Positive +cutt off freq -3dB (idem) - .transition_normalized = 3300.0f / 48000.0f, // 3300 Hz = (7800 Hz - 4500 Hz) (both from plot H(f) curve plot) + .transition_normalized = 3500.0f / 48000.0f, // 3500 Hz = (8000 Hz - 4500 Hz) (both from plot H(f) curve plot) .taps = { { - -40, 3, 98, 239, 340, 266, -96, -726, - -1391, -1659, -1041, 772, 3691, 7156, 10271, 12118, - 12118, 10271, 7156, 3691, 772, -1041, -1659, -1391, - -726, -96, 266, 340, 239, 98, 3, -40 + -53, -30, 47, 198, 355, 372, 89, -535, + -1307, -1771, -1353, 370, 3384, 7109, 10535, 12591, + 12591, 10535, 7109, 3384, 370, -1353, -1771, -1307, + -535, 89, 372, 355, 198, 47, -30, -53 } }, }; @@ -292,32 +292,32 @@ constexpr fir_taps_complex<64> taps_6k0_dsb_channel { } }, }; -// Channel filter: fs=12000, pass=4450, stop=4800, decim=1, fout=12000 (4k45 selected = aprox 4k5, after several iterative plot H(f) test, best trade off curve) +// Channel filter: fs=12000, pass=4500 (cutt off -3dBs), stop=4940 (<-60dBs), decim=1, fout=12000 (*1) real frec pass / stop , based on plotted H(f) curve) // For Europe AM commercial broadcasting stations in LF/MF/HF, Emissions Designator 9K00A3E Bandwidth: 9.00 kHz (derivative from taps_6k0_dsb_channel) -// FIR filter design created by SciPy Python with the "window method"; num_taps = 64, cut_off = 4450. sample_rate = 12000 # Hz, -// Created with : h=signal.firwin(num_taps, cut_off, nyq=sample_rate/2, window=('chebwin',50)), achieving good STOP band plot < -60 dB's with some ripple. -// post-escaled h taps to avoid decimals , targetting <= similar int values as previous taps_6k0_dsb_channel peak < 32.767 (2 exp 15), (29253) and similar H(f)gain +// FIR filter design created with SciPy Python using "window method"; selected design parameters: num_taps = 64, cut_off = 4575. sample_rate = 12000 # Hz, +// Created with : h = signal.firwin(num_taps, cut_off, nyq=sample_rate/2, window=('chebwin',50)) , achieving real plot curve (*1) with peak stop band ripple -60dBs. +// post-scaled h taps to avoid decimals , targeting <= similar int values as previous taps_6k0_dsb_channel peak < 32.767 (2 exp 15), (29625) and similar H(f)gain constexpr fir_taps_complex<64> taps_9k0_dsb_channel { .low_frequency_normalized = -4500.0f / 12000.0f, // Negative -cutt off freq -3dB (in the H(f) curve plot) .high_frequency_normalized = 4500.0f / 12000.0f, // Positive +cutt off freq -3dB (in the H(f) curve plot) - .transition_normalized = 350.0f / 12000.0f, // 350Hz = (4800 Hz -4450 Hz) cut-3dB's (both data comes from H(f) curve plot and confirmed by measurements ) + .transition_normalized = 440.0f / 12000.0f, // 440Hz = (4940 Hz -4500 Hz) cut-3dB's (both data comes from H(f) curve plot and confirmed by measurements ) .taps = { { - { -34, 0 }, { 23, 0 }, { -13, 0 }, { -19, 0 }, - { 55, 0 }, { -65, 0 }, { 25, 0 }, { 59, 0 }, - { -137, 0 }, { 141, 0 }, { -35, 0 }, { -146, 0 }, - { 287, 0 }, { -262, 0 }, { 26, 0 }, { 317, 0 }, - { -544, 0 }, { 441, 0 }, { 29, 0 }, { -638, 0 }, - { 980, 0 }, { -707, 0 }, { -191, 0 }, { 1272, 0 }, - { -1805, 0 }, { 1175, 0 }, { 660, 0 }, { -2934, 0 }, - { 4214, 0 }, { -2774, 0 }, { -3655, 0 }, { 29253, 0 }, - { 29253, 0 }, { -3655, 0 }, { -2774, 0 }, { 4214, 0 }, - { -2934, 0 }, { 660, 0 }, { 1175, 0 }, { -1805, 0 }, - { 1272, 0 }, { -191, 0 }, { -707, 0 }, { 980, 0 }, - { -638, 0 }, { 29, 0 }, { 441, 0 }, { -544, 0 }, - { 317, 0 }, { 26, 0 }, { -262, 0 }, { 287, 0 }, - { -146, 0 }, { -35, 0 }, { 141, 0 }, { -137, 0 }, - { 59, 0 }, { 25, 0 }, { -65, 0 }, { 55, 0 }, - { -19, 0 }, { -13, 0 }, { 23, 0 }, { -34, 0 }, + { 2, 0 }, { -18, 0 }, { 34, 0 }, { -33, 0 }, + { 6, 0 }, { 44, 0 }, { -91, 0 }, { 96, 0 }, + { -35, 0 }, { -80, 0 }, { 193, 0 }, { -223, 0 }, + { 116, 0 }, { 112, 0 }, { -353, 0 }, { 452, 0 }, + { -293, 0 }, { -111, 0 }, { 584, 0 }, { -844, 0 }, + { 653, 0 }, { 22, 0 }, { -921, 0 }, { 1554, 0 }, + { -1422, 0 }, { 301, 0 }, { 1533, 0 }, { -3282, 0 }, + { 3804, 0 }, { -1819, 0 }, { -4605, 0 }, { 29625, 0 }, + { 29625, 0 }, { -4605, 0 }, { -1819, 0 }, { 3804, 0 }, + { -3282, 0 }, { 1533, 0 }, { 301, 0 }, { -1422, 0 }, + { 1554, 0 }, { -921, 0 }, { 22, 0 }, { 653, 0 }, + { -844, 0 }, { 584, 0 }, { -111, 0 }, { -293, 0 }, + { 452, 0 }, { -353, 0 }, { 112, 0 }, { 116, 0 }, + { -223, 0 }, { 193, 0 }, { -80, 0 }, { -35, 0 }, + { 96, 0 }, { -91, 0 }, { 44, 0 }, { 6, 0 }, + { -33, 0 }, { 34, 0 }, { -18, 0 }, { 2, 0 }, } }, };