kopia lustrzana https://github.com/OpenRTX/OpenRTX
Improve quantization strategy
Now quantization is performed by averaging syncword samples and dividing the resulting threshold by a constant. TG-81pull/68/head
rodzic
2e7ed7a8f0
commit
c4483edff0
|
@ -125,7 +125,7 @@ private:
|
||||||
|
|
||||||
static constexpr float CONV_STATS_ALPHA = 0.001f;
|
static constexpr float CONV_STATS_ALPHA = 0.001f;
|
||||||
static constexpr float CONV_THRESHOLD_FACTOR = 3.40;
|
static constexpr float CONV_THRESHOLD_FACTOR = 3.40;
|
||||||
static constexpr int16_t QNT_SMA_WINDOW = 40;
|
static constexpr int16_t QNT_SMA_WINDOW = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* M17 syncwords;
|
* M17 syncwords;
|
||||||
|
@ -142,7 +142,7 @@ 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 frameIndex; ///< Index for filling the raw frame.
|
uint16_t frame_index; ///< Index for filling the raw frame.
|
||||||
frame_t *activeFrame; ///< Half frame, in demodulation.
|
frame_t *activeFrame; ///< Half frame, in demodulation.
|
||||||
frame_t *idleFrame; ///< Half frame, free to be processed.
|
frame_t *idleFrame; ///< Half frame, free to be processed.
|
||||||
bool isLSF; ///< Indicates that we demodualated an LSF.
|
bool isLSF; ///< Indicates that we demodualated an LSF.
|
||||||
|
|
|
@ -60,7 +60,7 @@ void M17Demodulator::init()
|
||||||
activeFrame = new frame_t;
|
activeFrame = new frame_t;
|
||||||
rawFrame = new uint16_t[M17_FRAME_SYMBOLS];
|
rawFrame = new uint16_t[M17_FRAME_SYMBOLS];
|
||||||
idleFrame = new frame_t;
|
idleFrame = new frame_t;
|
||||||
frameIndex = 0;
|
frame_index = 0;
|
||||||
phase = 0;
|
phase = 0;
|
||||||
locked = false;
|
locked = false;
|
||||||
newFrame = false;
|
newFrame = false;
|
||||||
|
@ -90,6 +90,7 @@ void M17Demodulator::startBasebandSampling()
|
||||||
M17_RX_SAMPLE_RATE);
|
M17_RX_SAMPLE_RATE);
|
||||||
// Clean start of the demodulation statistics
|
// Clean start of the demodulation statistics
|
||||||
resetCorrelationStats();
|
resetCorrelationStats();
|
||||||
|
resetQuantizationStats();
|
||||||
// DC removal filter reset
|
// DC removal filter reset
|
||||||
dsp_resetFilterState(&dsp_state);
|
dsp_resetFilterState(&dsp_state);
|
||||||
}
|
}
|
||||||
|
@ -135,25 +136,39 @@ void M17Demodulator::updateQuantizationStats(int32_t offset)
|
||||||
sample = baseband.data[offset];
|
sample = baseband.data[offset];
|
||||||
if (sample > 0)
|
if (sample > 0)
|
||||||
{
|
{
|
||||||
// If the FIFO is not full just push a new sample
|
qnt_pos_fifo.push_front(sample);
|
||||||
if (qnt_pos_fifo.size() >= QNT_SMA_WINDOW)
|
// FIFO not full, compute traditional average
|
||||||
|
if (qnt_pos_fifo.size() <= QNT_SMA_WINDOW)
|
||||||
|
{
|
||||||
|
int32_t acc = 0;
|
||||||
|
for(auto e : qnt_pos_fifo)
|
||||||
|
acc += e;
|
||||||
|
qnt_pos_avg = acc / static_cast<float>(qnt_pos_fifo.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
qnt_pos_avg += 1 / static_cast<float>(QNT_SMA_WINDOW) *
|
qnt_pos_avg += 1 / static_cast<float>(QNT_SMA_WINDOW) *
|
||||||
(sample - qnt_pos_fifo.back());
|
(sample - qnt_pos_fifo.back());
|
||||||
qnt_pos_fifo.pop_back();
|
qnt_pos_fifo.pop_back();
|
||||||
}
|
}
|
||||||
qnt_pos_fifo.push_front(sample);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the FIFO is not full just push a new sample
|
qnt_neg_fifo.push_front(sample);
|
||||||
if (qnt_neg_fifo.size() >= QNT_SMA_WINDOW)
|
// FIFO not full, compute traditional average
|
||||||
|
if (qnt_neg_fifo.size() <= QNT_SMA_WINDOW)
|
||||||
|
{
|
||||||
|
int32_t acc = 0;
|
||||||
|
for(auto e : qnt_neg_fifo)
|
||||||
|
acc += e;
|
||||||
|
qnt_neg_avg = acc / static_cast<float>(qnt_neg_fifo.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
qnt_neg_avg += 1 / static_cast<float>(QNT_SMA_WINDOW) *
|
qnt_neg_avg += 1 / static_cast<float>(QNT_SMA_WINDOW) *
|
||||||
(sample - qnt_neg_fifo.back());
|
(sample - qnt_neg_fifo.back());
|
||||||
qnt_neg_fifo.pop_back();
|
qnt_neg_fifo.pop_back();
|
||||||
}
|
}
|
||||||
qnt_neg_fifo.push_front(sample);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +209,6 @@ sync_t M17Demodulator::nextFrameSync(int32_t offset)
|
||||||
// If we are not locked search for a syncword
|
// If we are not locked search for a syncword
|
||||||
int32_t conv = convolution(i, stream_syncword, M17_SYNCWORD_SYMBOLS);
|
int32_t conv = convolution(i, stream_syncword, M17_SYNCWORD_SYMBOLS);
|
||||||
updateCorrelationStats(conv);
|
updateCorrelationStats(conv);
|
||||||
updateQuantizationStats(i);
|
|
||||||
|
|
||||||
#ifdef PLATFORM_LINUX
|
#ifdef PLATFORM_LINUX
|
||||||
int16_t sample = 0;
|
int16_t sample = 0;
|
||||||
|
@ -239,9 +253,9 @@ int8_t M17Demodulator::quantize(int32_t offset)
|
||||||
sample = basebandBridge[M17_BRIDGE_SIZE + offset];
|
sample = basebandBridge[M17_BRIDGE_SIZE + offset];
|
||||||
else // Otherwise use regular data buffer
|
else // Otherwise use regular data buffer
|
||||||
sample = baseband.data[offset];
|
sample = baseband.data[offset];
|
||||||
if (sample > static_cast< int16_t >(qnt_pos_avg * 0.067))
|
if (sample > static_cast< int16_t >(qnt_pos_avg / 1.7))
|
||||||
return +3;
|
return +3;
|
||||||
else if (sample < static_cast< int16_t >(qnt_neg_avg * 0.067))
|
else if (sample < static_cast< int16_t >(qnt_neg_avg / 1.7))
|
||||||
return -3;
|
return -3;
|
||||||
else if (sample > 0)
|
else if (sample > 0)
|
||||||
return +1;
|
return +1;
|
||||||
|
@ -312,7 +326,7 @@ bool M17Demodulator::update()
|
||||||
isLSF = syncword.lsf;
|
isLSF = syncword.lsf;
|
||||||
offset = syncword.index + 4;
|
offset = syncword.index + 4;
|
||||||
phase = 0;
|
phase = 0;
|
||||||
frameIndex = 0;
|
frame_index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// While we are locked, demodulate available samples
|
// While we are locked, demodulate available samples
|
||||||
|
@ -322,8 +336,9 @@ bool M17Demodulator::update()
|
||||||
int32_t symbol_index = offset
|
int32_t symbol_index = offset
|
||||||
+ phase
|
+ phase
|
||||||
+ (M17_SAMPLES_PER_SYMBOL * decoded_syms);
|
+ (M17_SAMPLES_PER_SYMBOL * decoded_syms);
|
||||||
|
// Update quantization stats only on syncwords
|
||||||
updateQuantizationStats(symbol_index);
|
if (frame_index < M17_SYNCWORD_SYMBOLS)
|
||||||
|
updateQuantizationStats(symbol_index);
|
||||||
int8_t symbol = quantize(symbol_index);
|
int8_t symbol = quantize(symbol_index);
|
||||||
|
|
||||||
#ifdef PLATFORM_LINUX
|
#ifdef PLATFORM_LINUX
|
||||||
|
@ -333,63 +348,64 @@ bool M17Demodulator::update()
|
||||||
fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
|
fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
|
||||||
0,0,0.0,symbol_index - 4 + i,
|
0,0,0.0,symbol_index - 4 + i,
|
||||||
baseband.data[symbol_index - 4 + i],
|
baseband.data[symbol_index - 4 + i],
|
||||||
qnt_pos_avg,
|
qnt_pos_avg / 1.7,
|
||||||
qnt_neg_avg,
|
qnt_neg_avg / 1.7,
|
||||||
0,
|
0,
|
||||||
frameIndex);
|
frame_index);
|
||||||
}
|
}
|
||||||
fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
|
fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
|
||||||
0,0,0.0,symbol_index,
|
0,0,0.0,symbol_index,
|
||||||
baseband.data[symbol_index],
|
baseband.data[symbol_index],
|
||||||
qnt_pos_avg,
|
qnt_pos_avg / 1.7,
|
||||||
qnt_neg_avg,
|
qnt_neg_avg / 1.7,
|
||||||
symbol * 666,
|
symbol * 666,
|
||||||
frameIndex);
|
frame_index);
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
if ((symbol_index + i + 1) < static_cast<int32_t> (baseband.len))
|
if ((symbol_index + i + 1) < static_cast<int32_t> (baseband.len))
|
||||||
fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
|
fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
|
||||||
0,0,0.0,symbol_index + i + 1,
|
0,0,0.0,symbol_index + i + 1,
|
||||||
baseband.data[symbol_index + i + 1],
|
baseband.data[symbol_index + i + 1],
|
||||||
qnt_pos_avg,
|
qnt_pos_avg / 1.7,
|
||||||
qnt_neg_avg,
|
qnt_neg_avg / 1.7,
|
||||||
0,
|
0,
|
||||||
frameIndex);
|
frame_index);
|
||||||
}
|
}
|
||||||
fflush(csv_log);
|
fflush(csv_log);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
setSymbol<M17_FRAME_BYTES>(*activeFrame, frameIndex, symbol);
|
setSymbol<M17_FRAME_BYTES>(*activeFrame, frame_index, symbol);
|
||||||
decoded_syms++;
|
decoded_syms++;
|
||||||
frameIndex++;
|
frame_index++;
|
||||||
|
|
||||||
// If the frame buffer is full switch active and idle frame
|
// If the frame buffer is full switch active and idle frame
|
||||||
if (frameIndex == M17_FRAME_SYMBOLS)
|
if (frame_index == M17_FRAME_SYMBOLS)
|
||||||
{
|
{
|
||||||
std::swap(activeFrame, idleFrame);
|
std::swap(activeFrame, idleFrame);
|
||||||
frameIndex = 0;
|
frame_index = 0;
|
||||||
newFrame = true;
|
newFrame = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If syncword is not valid, lock is lost, accept 2 bit errors
|
if (frame_index == M17_SYNCWORD_SYMBOLS)
|
||||||
uint8_t hammingSync = hammingDistance((*activeFrame)[0],
|
|
||||||
stream_syncword_bytes[0])
|
|
||||||
+ hammingDistance((*activeFrame)[1],
|
|
||||||
stream_syncword_bytes[1]);
|
|
||||||
|
|
||||||
uint8_t hammingLsf = hammingDistance((*activeFrame)[0],
|
|
||||||
lsf_syncword_bytes[0])
|
|
||||||
+ hammingDistance((*activeFrame)[1],
|
|
||||||
lsf_syncword_bytes[1]);
|
|
||||||
|
|
||||||
if (frameIndex == M17_SYNCWORD_SYMBOLS)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// If syncword is not valid, lock is lost, accept 2 bit errors
|
||||||
|
uint8_t hammingSync = hammingDistance((*activeFrame)[0],
|
||||||
|
stream_syncword_bytes[0])
|
||||||
|
+ hammingDistance((*activeFrame)[1],
|
||||||
|
stream_syncword_bytes[1]);
|
||||||
|
|
||||||
|
uint8_t hammingLsf = hammingDistance((*activeFrame)[0],
|
||||||
|
lsf_syncword_bytes[0])
|
||||||
|
+ hammingDistance((*activeFrame)[1],
|
||||||
|
lsf_syncword_bytes[1]);
|
||||||
|
|
||||||
// Too many errors in the syncword, lock is lost
|
// Too many errors in the syncword, lock is lost
|
||||||
if ((hammingSync > 1) && (hammingLsf > 1))
|
if ((hammingSync > 1) && (hammingLsf > 1))
|
||||||
{
|
{
|
||||||
locked = false;
|
locked = false;
|
||||||
std::swap(activeFrame, idleFrame);
|
std::swap(activeFrame, idleFrame);
|
||||||
frameIndex = 0;
|
frame_index = 0;
|
||||||
newFrame = true;
|
newFrame = true;
|
||||||
|
|
||||||
#ifdef PLATFORM_MOD17
|
#ifdef PLATFORM_MOD17
|
||||||
|
|
|
@ -15,6 +15,6 @@ plt.plot(df.index, df.Offset)
|
||||||
plt.plot(df.index, df.Sample)
|
plt.plot(df.index, df.Sample)
|
||||||
plt.plot(df.index, df.Max)
|
plt.plot(df.index, df.Max)
|
||||||
plt.plot(df.index, df.Min)
|
plt.plot(df.index, df.Min)
|
||||||
#plt.plot(df.index, df.Symbol)
|
plt.plot(df.index, df.Symbol)
|
||||||
plt.plot(df.index, df.I)
|
plt.plot(df.index, df.I)
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
Ładowanie…
Reference in New Issue