diff --git a/AX25Demodulator.cpp b/AX25Demodulator.cpp index f1bcddf..71e61ee 100644 --- a/AX25Demodulator.cpp +++ b/AX25Demodulator.cpp @@ -30,9 +30,9 @@ const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE; const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F; // XXX This is for the wrong sample rate -const uint32_t LPF_FILTER_LEN = 96; +const uint32_t LPF_FILTER_LEN = 96U; -q15_t lpfCoeffs[] = { +q15_t LPF_FILTER_COEFFS[] = { 0, 1, 3, 5, 8, 11, 14, 17, 19, 20, 18, 14, 7, -2, -16, -33, -53, -76, -101, -126, -151, -174, -194, -208, -215, -212, -199, -173, -133, -79, -10, 74, 173, 287, 413, 549, @@ -48,7 +48,9 @@ q15_t lpfCoeffs[] = { // loop_coeffs = firwin(9, [64.0/(1200/2)], width = None, // pass_zero = True, scale = True, window='hann') // -float32_t pllLoopCoeffs[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; +const uint32_t PLL_FILTER_LEN = 7U; + +float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; CAX25Demodulator::CAX25Demodulator(float32_t* coeffs, uint16_t length) : m_audioFilter(), @@ -72,11 +74,11 @@ m_pllCount(0.0F) m_lpfFilter.numTaps = LPF_FILTER_LEN; m_lpfFilter.pState = m_lpfState; - m_lpfFilter.pCoeffs = lpfCoeffs; + m_lpfFilter.pCoeffs = LPF_FILTER_COEFFS; - m_pllFilter.numTaps = 7U; + m_pllFilter.numTaps = PLL_FILTER_LEN; m_pllFilter.pState = m_pllState; - m_pllFilter.pCoeffs = pllLoopCoeffs; + m_pllFilter.pCoeffs = PLL_FILTER_COEFFS; } bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame& frame) diff --git a/AX25RX.cpp b/AX25RX.cpp index 538e014..99aa1a5 100644 --- a/AX25RX.cpp +++ b/AX25RX.cpp @@ -20,19 +20,100 @@ #include "Globals.h" #include "AX25RX.h" +// XXX There are for the wrong sample rate + +// 1200Hz = -9dB, 2200Hz = 0dB; 3252Hz cutoff, 3.7 gain; cosine. +float32_t dB9[] = { + -0.00232554104135, + -0.142858725752, + -0.449053780255, + -0.770264863826, + 2.77651146344, + -0.770264863826, + -0.449053780255, + -0.142858725752, + -0.00232554104135}; + +// 1200Hz = -6dB, 2200Hz = 0dB; 2640Hz cutoff, 2.59 gain; cosine. +float32_t dB6[] = { + -0.0209448226653, + -0.130107651829, + -0.299004731072, + -0.45336946386, + 2.0629448761, + -0.45336946386, + -0.299004731072, + -0.130107651829, + -0.0209448226653}; + +// 1200Hz = -3dB, 2200Hz = 0dB; 1700Hz cutoff, 1.68 gain; cosine. +float32_t dB3[] = { + -0.0231416146776, + -0.0833375337803, + -0.147937602401, + -0.197411259519, + 1.46066084756, + -0.197411259519, + -0.147937602401, + -0.0833375337803, + -0.0231416146776}; + +/* + * Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass, + * Hann window, starting and ending 0 value coefficients removed. + * + * np.array( + * firwin2(152, + * [ + * 0.0, + * 1000.0/(sample_rate/2), + * 1100.0/(sample_rate/2), + * 2350.0/(sample_rate/2), + * 2500.0/(sample_rate/2), + * 1.0 + * ], + * [0,0,1,1,0,0], + * antisymmetric = False, + * window='hann') * 32768, + * dtype=int)[10:-10] + */ +const uint32_t FILTER_LEN = 132U; + +// XXX This is for the wrong sample rate +q15_t FILTER_COEFFS[] = { + 4, 0, -5, -10, -13, -12, -9, -4, -2, -4, -12, -26, + -41, -52, -51, -35, -3, 39, 83, 117, 131, 118, 83, 36, + -6, -32, -30, -3, 36, 67, 66, 19, -74, -199, -323, -408, + -421, -344, -187, 17, 218, 364, 417, 369, 247, 106, 14, 26, + 166, 407, 676, 865, 866, 605, 68, -675, -1484, -2171, -2547, -2471, +-1895, -882, 394, 1692, 2747, 3337, 3337, 2747, 1692, 394, -882, -1895, +-2471, -2547, -2171, -1484, -675, 68, 605, 866, 865, 676, 407, 166, + 26, 14, 106, 247, 369, 417, 364, 218, 17, -187, -344, -421, + -408, -323, -199, -74, 19, 66, 67, 36, -3, -30, -32, -6, + 36, 83, 118, 131, 117, 83, 39, -3, -35, -51, -52, -41, + -26, -12, -4, -2, -4, -9, -12, -13, -10, -5, 0, 4}; + CAX25RX::CAX25RX() : -m_demod1(), -m_demod2(), -m_demod3(), +m_filter(), +m_state(), +m_demod1(dB3, 9U), +m_demod2(dB6, 9U), +m_demod3(dB9, 9U), m_lastFCS(0U) { + m_filter.numTaps = FILTER_LEN; + m_filter.pState = m_state; + m_filter.pCoeffs = FILTER_COEFFS; } -void CAX25RX::samples(const q15_t* samples, uint8_t length) +void CAX25RX::samples(q15_t* samples, uint8_t length) { + q15_t output[RX_BLOCK_SIZE]; + ::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE); + CAX25Frame frame; - bool ret = m_demod1.process(samples, length, frame); + bool ret = m_demod1.process(output, length, frame); if (ret) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 1 reported"); @@ -41,7 +122,7 @@ void CAX25RX::samples(const q15_t* samples, uint8_t length) } } - ret = m_demod2.process(samples, length, frame); + ret = m_demod2.process(output, length, frame); if (ret) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 2 reported"); @@ -50,7 +131,7 @@ void CAX25RX::samples(const q15_t* samples, uint8_t length) } } - ret = m_demod3.process(samples, length, frame); + ret = m_demod3.process(output, length, frame); if (ret) { if (m_lastFCS != frame.m_fcs) { DEBUG1("Decoder 3 reported"); diff --git a/AX25RX.h b/AX25RX.h index 68f3532..6ab6d1c 100644 --- a/AX25RX.h +++ b/AX25RX.h @@ -27,13 +27,15 @@ class CAX25RX { public: CAX25RX(); - void samples(const q15_t* samples, uint8_t length); + void samples(q15_t* samples, uint8_t length); private: - CAX25Demodulator m_demod1; - CAX25Demodulator m_demod2; - CAX25Demodulator m_demod3; - uint16_t m_lastFCS; + arm_fir_instance_q15 m_filter; + q15_t m_state[160U]; // NoTaps + BlockSize - 1, 132 + 20 - 1 plus some spare + CAX25Demodulator m_demod1; + CAX25Demodulator m_demod2; + CAX25Demodulator m_demod3; + uint16_t m_lastFCS; }; #endif