Implement M17 demodulator logic
Implemented frame wrapping logic and demodulator loop.
This commit is contained in:
parent
963fbdc141
commit
1a9b3c4168
|
|
@ -110,12 +110,15 @@ private:
|
||||||
static constexpr float conv_stats_alpha = 0.0001f;
|
static constexpr float conv_stats_alpha = 0.0001f;
|
||||||
static constexpr float conv_threshold_factor = 3.70;
|
static constexpr float conv_threshold_factor = 3.70;
|
||||||
static constexpr float qnt_maxmin_alpha = 0.999f;
|
static constexpr float qnt_maxmin_alpha = 0.999f;
|
||||||
|
static constexpr size_t M17_BRIDGE_SIZE = M17_SAMPLES_PER_SYMBOL *
|
||||||
|
M17_SYNCWORD_SYMBOLS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* M17 syncwords;
|
* M17 syncwords;
|
||||||
*/
|
*/
|
||||||
int8_t lsf_syncword[M17_SYNCWORD_SYMBOLS] = { +3, +3, +3, +3, -3, -3, +3, -3 };
|
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 };
|
int8_t stream_syncword[M17_SYNCWORD_SYMBOLS] = { -3, -3, -3, -3, +3, +3, -3, +3 };
|
||||||
|
uint8_t stream_syncword_bytes[2] = {0xff, 0x5d};
|
||||||
|
|
||||||
using dataBuffer_t = std::array< int16_t, M17_FRAME_SAMPLES_24K >;
|
using dataBuffer_t = std::array< int16_t, M17_FRAME_SAMPLES_24K >;
|
||||||
using dataFrame_t = std::array< uint8_t, M17_FRAME_BYTES >;
|
using dataFrame_t = std::array< uint8_t, M17_FRAME_BYTES >;
|
||||||
|
|
@ -127,11 +130,13 @@ private:
|
||||||
int16_t *baseband_buffer; ///< Buffer for baseband audio handling.
|
int16_t *baseband_buffer; ///< Buffer for baseband audio handling.
|
||||||
dataBlock_t baseband; ///< Half buffer, free to be processed.
|
dataBlock_t baseband; ///< Half buffer, free to be processed.
|
||||||
uint16_t *rawFrame; ///< Analog values to be quantized.
|
uint16_t *rawFrame; ///< Analog values to be quantized.
|
||||||
uint16_t rawFrameIndex; ///< Index for filling the raw frame.
|
uint16_t frameIndex; ///< Index for filling the raw frame.
|
||||||
dataFrame_t *activeFrame; ///< Half frame, in demodulation.
|
dataFrame_t *activeFrame; ///< Half frame, in demodulation.
|
||||||
dataFrame_t *idleFrame; ///< Half frame, free to be processed.
|
dataFrame_t *idleFrame; ///< Half frame, free to be processed.
|
||||||
bool isLSF; ///< Indicates that we demodualated an LSF.
|
bool isLSF; ///< Indicates that we demodualated an LSF.
|
||||||
bool locked; ///< A syncword was detected.
|
bool locked; ///< A syncword was detected.
|
||||||
|
int16_t basebandBridge[M17_BRIDGE_SIZE] = { 0 }; ///< Bridge buffer
|
||||||
|
uint16_t phase; ///< Phase of the signal w.r.t. sampling
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* State variables
|
* State variables
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <M17/M17Utils.h>
|
#include <M17/M17Utils.h>
|
||||||
#include <interfaces/audio_stream.h>
|
#include <interfaces/audio_stream.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace M17
|
namespace M17
|
||||||
{
|
{
|
||||||
|
|
@ -50,6 +51,8 @@ void M17Demodulator::init()
|
||||||
activeFrame = new dataFrame_t;
|
activeFrame = new dataFrame_t;
|
||||||
rawFrame = new uint16_t[M17_FRAME_SYMBOLS];
|
rawFrame = new uint16_t[M17_FRAME_SYMBOLS];
|
||||||
idleFrame = new dataFrame_t;
|
idleFrame = new dataFrame_t;
|
||||||
|
frameIndex = 0;
|
||||||
|
phase = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17Demodulator::terminate()
|
void M17Demodulator::terminate()
|
||||||
|
|
@ -144,8 +147,14 @@ int32_t M17Demodulator::convolution(size_t offset,
|
||||||
int32_t conv = 0;
|
int32_t conv = 0;
|
||||||
for(uint32_t i = 0; i < target_size; i++)
|
for(uint32_t i = 0; i < target_size; i++)
|
||||||
{
|
{
|
||||||
conv += (int32_t) target[i] *
|
int16_t sample_index = offset + i * M17_SAMPLES_PER_SYMBOL;
|
||||||
(int32_t) this->baseband.data[offset + i * M17_SAMPLES_PER_SYMBOL];
|
int16_t sample = 0;
|
||||||
|
// When we are at negative indices use bridge buffer
|
||||||
|
if (sample_index < 0)
|
||||||
|
sample = basebandBridge[M17_BRIDGE_SIZE + sample_index];
|
||||||
|
else
|
||||||
|
sample = baseband.data[sample_index];
|
||||||
|
conv += (int32_t) target[i] * (int32_t) sample;
|
||||||
}
|
}
|
||||||
return conv;
|
return conv;
|
||||||
}
|
}
|
||||||
|
|
@ -178,11 +187,16 @@ sync_t M17Demodulator::nextFrameSync(uint32_t offset)
|
||||||
|
|
||||||
int8_t M17Demodulator::quantize(int32_t offset)
|
int8_t M17Demodulator::quantize(int32_t offset)
|
||||||
{
|
{
|
||||||
if (baseband.data[offset] > getQuantizationMax() * 2 / 3)
|
int16_t sample = 0;
|
||||||
|
if (offset < 0) // When we are at negative offsets use bridge buffer
|
||||||
|
sample = basebandBridge[M17_BRIDGE_SIZE + offset];
|
||||||
|
else // Otherwise use regular data buffer
|
||||||
|
sample = baseband.data[offset];
|
||||||
|
if (sample > getQuantizationMax() * 2 / 3)
|
||||||
return +3;
|
return +3;
|
||||||
else if (baseband.data[offset] < getQuantizationMin() * 2 / 3)
|
else if (sample < getQuantizationMin() * 2 / 3)
|
||||||
return -3;
|
return -3;
|
||||||
else if (baseband.data[offset] > 0)
|
else if (sample > 0)
|
||||||
return +1;
|
return +1;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -200,6 +214,9 @@ bool M17Demodulator::isFrameLSF()
|
||||||
|
|
||||||
void M17Demodulator::update()
|
void M17Demodulator::update()
|
||||||
{
|
{
|
||||||
|
M17::sync_t syncword = { -1, false };
|
||||||
|
int16_t offset = -(int16_t) M17_BRIDGE_SIZE;
|
||||||
|
uint16_t decoded_syms = 0;
|
||||||
// Read samples from the ADC
|
// Read samples from the ADC
|
||||||
baseband = inputStream_getData(basebandId);
|
baseband = inputStream_getData(basebandId);
|
||||||
|
|
||||||
|
|
@ -211,41 +228,58 @@ void M17Demodulator::update()
|
||||||
float elem = static_cast< float >(baseband.data[i]);
|
float elem = static_cast< float >(baseband.data[i]);
|
||||||
baseband.data[i] = static_cast< int16_t >(M17::rrc(elem));
|
baseband.data[i] = static_cast< int16_t >(M17::rrc(elem));
|
||||||
}
|
}
|
||||||
|
// If we are not locked search for a syncword
|
||||||
// If we locked a syncword just demodulate samples
|
if (!locked)
|
||||||
if (locked)
|
|
||||||
{
|
{
|
||||||
|
syncword = nextFrameSync(-M17_SYNCWORD_SYMBOLS * M17_SAMPLES_PER_SYMBOL);
|
||||||
}
|
if (syncword.index != -1) // Lock was just acquired
|
||||||
else // Otherwise find next syncword
|
|
||||||
{
|
|
||||||
M17::sync_t syncword = { -1, false };
|
|
||||||
uint16_t offset = 0;
|
|
||||||
syncword = nextFrameSync(offset);
|
|
||||||
if (syncword.index != -1)
|
|
||||||
{
|
{
|
||||||
locked = true;
|
locked = true;
|
||||||
// Set a flag to mark LSF
|
|
||||||
isLSF = syncword.lsf;
|
isLSF = syncword.lsf;
|
||||||
// Next syncword does not overlap with current syncword
|
offset = syncword.index + 2;
|
||||||
offset = syncword.index + M17_SAMPLES_PER_SYMBOL;
|
// DEBUG: prints
|
||||||
// Slice the input buffer to extract a frame and quantize
|
if (isLSF)
|
||||||
for(uint16_t i = 0; i < M17_FRAME_SYMBOLS; i++)
|
printf("Found LSF!\n");
|
||||||
|
else
|
||||||
|
printf("Found SYNC!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Lock was inherited from previous frame
|
||||||
|
offset = phase;
|
||||||
|
// While we are locked, demodulate available samples
|
||||||
|
while (locked && offset < (int16_t) M17_FRAME_SAMPLES_24K)
|
||||||
{
|
{
|
||||||
// Quantize
|
// Slice the input buffer to extract a frame and quantize
|
||||||
uint16_t symbol_index = syncword.index + 2 +
|
uint16_t symbol_index = offset + M17_SAMPLES_PER_SYMBOL * decoded_syms;
|
||||||
M17_SAMPLES_PER_SYMBOL * i;
|
|
||||||
updateQuantizationStats(baseband.data[symbol_index]);
|
updateQuantizationStats(baseband.data[symbol_index]);
|
||||||
int8_t symbol = quantize(symbol_index);
|
int8_t symbol = quantize(symbol_index);
|
||||||
setSymbol<M17_FRAME_BYTES>(*activeFrame, i, symbol);
|
setSymbol<M17_FRAME_BYTES>(*activeFrame, frameIndex, symbol);
|
||||||
|
frameIndex++;
|
||||||
// If the frame buffer is full switch active and idle frame
|
// If the frame buffer is full switch active and idle frame
|
||||||
if (rawFrameIndex == M17_FRAME_SYMBOLS)
|
if (frameIndex == M17_FRAME_SYMBOLS)
|
||||||
|
{
|
||||||
std::swap(activeFrame, idleFrame);
|
std::swap(activeFrame, idleFrame);
|
||||||
}
|
frameIndex = 0;
|
||||||
// If we have some samples left, try to decode the syncword
|
// DEBUG: print idleFrame bytes
|
||||||
// If decoding fails, signal lock is lost
|
for(size_t i = 0; i < idleFrame->size(); i+=2)
|
||||||
|
{
|
||||||
|
if (i % 16 == 14)
|
||||||
|
printf("\n");
|
||||||
|
printf(" %02X%02X", (*idleFrame)[i], (*idleFrame)[i+1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (frameIndex == 1 &&
|
||||||
|
((*activeFrame)[0] != stream_syncword_bytes[0] ||
|
||||||
|
(*activeFrame)[1] != stream_syncword_bytes[1])) // Lock is lost
|
||||||
|
locked = false;
|
||||||
|
}
|
||||||
|
// Compute phase of next buffer
|
||||||
|
phase = offset % M17_SAMPLES_PER_SYMBOL +
|
||||||
|
(M17_INPUT_BUF_SIZE % M17_SAMPLES_PER_SYMBOL);
|
||||||
|
// copy N samples to bridge buffer
|
||||||
|
memcpy(basebandBridge,
|
||||||
|
baseband.data + M17_FRAME_SAMPLES_24K - M17_BRIDGE_SIZE,
|
||||||
|
sizeof(int16_t) * M17_BRIDGE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue