diff --git a/openrtx/include/protocols/M17/M17Demodulator.h b/openrtx/include/protocols/M17/M17Demodulator.h index d52211b9..f2f16c41 100644 --- a/openrtx/include/protocols/M17/M17Demodulator.h +++ b/openrtx/include/protocols/M17/M17Demodulator.h @@ -100,36 +100,40 @@ public: */ bool update(); + /** + * @return true if a demodulator is locked on an M17 stream. + */ + bool isLocked(); + private: - /* - * We are sampling @ 24KHz so an M17 frame has half the samples, - * our input buffer contains half M17 frame. + /** + * M17 baseband signal sampled at 48kHz, half of an M17 frame is processed + * at each update of the demodulator. */ static constexpr size_t M17_SYMBOL_RATE = 4800; - static constexpr size_t M17_FRAME_SAMPLES_24K = 960; static constexpr size_t M17_FRAME_SYMBOLS = 192; static constexpr size_t M17_SYNCWORD_SYMBOLS = 8; - static constexpr size_t M17_CONV_THRESHOLD = 50000; static constexpr size_t M17_RX_SAMPLE_RATE = 48000; + static constexpr size_t M17_SAMPLES_PER_SYMBOL = M17_RX_SAMPLE_RATE / M17_SYMBOL_RATE; - static constexpr size_t M17_INPUT_BUF_SIZE = 2 * M17_FRAME_SAMPLES_24K; static constexpr size_t M17_FRAME_BYTES = M17_FRAME_SYMBOLS / 4; - static constexpr float conv_stats_alpha = 0.001f; - static constexpr float qnt_stats_alpha = 0.9f; - static constexpr float conv_threshold_factor = 3.40; - static constexpr size_t M17_BRIDGE_SIZE = M17_SAMPLES_PER_SYMBOL * - M17_SYNCWORD_SYMBOLS; + static constexpr size_t M17_FRAME_SAMPLES = M17_FRAME_SYMBOLS * M17_SAMPLES_PER_SYMBOL; + static constexpr size_t M17_SAMPLE_BUF_SIZE = M17_FRAME_SAMPLES / 2; + static constexpr size_t M17_BRIDGE_SIZE = M17_SAMPLES_PER_SYMBOL * M17_SYNCWORD_SYMBOLS; + + static constexpr size_t M17_CONV_THRESHOLD = 50000; + static constexpr float CONV_STATS_ALPHA = 0.001f; + static constexpr float QNT_STATS_ALPHA = 0.9f; + static constexpr float CONV_THRESHOLD_FACTOR = 3.40; /** * M17 syncwords; */ - int8_t lsf_syncword[M17_SYNCWORD_SYMBOLS] = { +3, +3, +3, +3, -3, -3, +3, -3 }; - int8_t stream_syncword[M17_SYNCWORD_SYMBOLS] = { -3, -3, -3, -3, +3, +3, -3, +3 }; - uint8_t lsf_syncword_bytes[2] = {0x55, 0xf7}; - uint8_t stream_syncword_bytes[2] = {0xff, 0x5d}; - - using dataBuffer_t = std::array< int16_t, M17_FRAME_SAMPLES_24K >; + int8_t lsf_syncword[M17_SYNCWORD_SYMBOLS] = { +3, +3, +3, +3, -3, -3, +3, -3 }; + int8_t stream_syncword[M17_SYNCWORD_SYMBOLS] = { -3, -3, -3, -3, +3, +3, -3, +3 }; + uint8_t lsf_syncword_bytes[2] = {0x55, 0xf7}; + uint8_t stream_syncword_bytes[2] = {0xff, 0x5d}; /* * Buffers diff --git a/openrtx/src/protocols/M17/M17Demodulator.cpp b/openrtx/src/protocols/M17/M17Demodulator.cpp index 850238d8..9c33baef 100644 --- a/openrtx/src/protocols/M17/M17Demodulator.cpp +++ b/openrtx/src/protocols/M17/M17Demodulator.cpp @@ -55,7 +55,7 @@ void M17Demodulator::init() * placement new. */ - baseband_buffer = new int16_t[2 * M17_INPUT_BUF_SIZE]; + baseband_buffer = new int16_t[2 * M17_SAMPLE_BUF_SIZE]; baseband = { nullptr, 0 }; activeFrame = new frame_t; rawFrame = new uint16_t[M17_FRAME_SYMBOLS]; @@ -88,7 +88,7 @@ void M17Demodulator::startBasebandSampling() { basebandId = inputStream_start(SOURCE_RTX, PRIO_RX, baseband_buffer, - M17_INPUT_BUF_SIZE, + 2 * M17_SAMPLE_BUF_SIZE, BUF_CIRC_DOUBLE, M17_RX_SAMPLE_RATE); // Clean start of the demodulation statistics @@ -113,9 +113,9 @@ void M17Demodulator::resetCorrelationStats() void M17Demodulator::updateCorrelationStats(int32_t value) { float delta = (float) value - conv_ema; - float incr = conv_stats_alpha * delta; + float incr = CONV_STATS_ALPHA * delta; conv_ema += incr; - conv_emvar = (1.0f - conv_stats_alpha) * (conv_emvar + delta * incr); + conv_emvar = (1.0f - CONV_STATS_ALPHA) * (conv_emvar + delta * incr); } float M17Demodulator::getCorrelationStddev() @@ -140,17 +140,17 @@ void M17Demodulator::updateQuantizationStats(int32_t offset) sample = baseband.data[offset]; // Compute symbols exponential moving average float delta = (float) sample - qnt_ema; - qnt_ema += conv_stats_alpha * delta; + qnt_ema += CONV_STATS_ALPHA * delta; // Remove DC offset int16_t s = sample - (int16_t) qnt_ema; if (s > qnt_max) qnt_max = s; else - qnt_max *= qnt_stats_alpha; + qnt_max *= QNT_STATS_ALPHA; if (s < qnt_min) qnt_min = s; else - qnt_min *= qnt_stats_alpha; + qnt_min *= QNT_STATS_ALPHA; } int32_t M17Demodulator::convolution(int32_t offset, @@ -202,20 +202,20 @@ sync_t M17Demodulator::nextFrameSync(int32_t offset) fprintf(csv_log, "%" PRId16 ",%d,%f,%d\n", sample, conv - static_cast< int32_t >(conv_ema), - conv_threshold_factor * getCorrelationStddev(), + CONV_THRESHOLD_FACTOR * getCorrelationStddev(), i); #endif // Positive correlation peak -> frame syncword if ((conv - static_cast< int32_t >(conv_ema)) > - (getCorrelationStddev() * conv_threshold_factor)) + (getCorrelationStddev() * CONV_THRESHOLD_FACTOR)) { syncword.lsf = false; syncword.index = i; } // Negative correlation peak -> LSF syncword else if ((conv - static_cast< int32_t >(conv_ema)) < - -(getCorrelationStddev() * conv_threshold_factor)) + -(getCorrelationStddev() * CONV_THRESHOLD_FACTOR)) { syncword.lsf = true; syncword.index = i; @@ -259,6 +259,11 @@ bool M17Demodulator::isFrameLSF() return isLSF; } +bool M17::M17Demodulator::isLocked() +{ + return locked; +} + uint8_t M17Demodulator::hammingDistance(uint8_t x, uint8_t y) { return __builtin_popcount(x ^ y); @@ -373,7 +378,7 @@ bool M17Demodulator::update() { // Compute phase of next buffer phase = (offset % M17_SAMPLES_PER_SYMBOL) + - (M17_INPUT_BUF_SIZE % M17_SAMPLES_PER_SYMBOL); + (baseband.len % M17_SAMPLES_PER_SYMBOL); } else {