Rewrite quantization algorithm

Quantization algorithm is now based on separate rolling averages for
positive and negative samples.
Merged csv outputs from syncword search and quantization on Linux.

TG-81
This commit is contained in:
Niccolò Izzo 2022-04-14 10:51:27 +02:00 committed by Silvano Seva
parent aa9fcc26b7
commit 7d1b89550e
5 changed files with 55 additions and 66 deletions

View File

@ -124,8 +124,8 @@ private:
static constexpr size_t M17_BRIDGE_SIZE = M17_SAMPLES_PER_SYMBOL * M17_SYNCWORD_SYMBOLS; static constexpr size_t M17_BRIDGE_SIZE = M17_SAMPLES_PER_SYMBOL * M17_SYNCWORD_SYMBOLS;
static constexpr float CONV_STATS_ALPHA = 0.001f; static constexpr float CONV_STATS_ALPHA = 0.001f;
static constexpr float QNT_STATS_ALPHA = 0.999f;
static constexpr float CONV_THRESHOLD_FACTOR = 3.40; static constexpr float CONV_THRESHOLD_FACTOR = 3.40;
static constexpr int16_t QNT_SMA_WINDOW = 40;
/** /**
* M17 syncwords; * M17 syncwords;
@ -164,8 +164,10 @@ private:
/* /*
* Quantization statistics computation * Quantization statistics computation
*/ */
float qnt_max = 0.0f; ///< Max hold of the sliced samples std::deque<int16_t> qnt_pos_fifo;
float qnt_min = 0.0f; ///< Min hold of the sliced samples. std::deque<int16_t> qnt_neg_fifo;
float qnt_pos_avg = 0.0f; ///< Rolling average of positive samples
float qnt_neg_avg = 0.0f; ///< Rolling average of negative samples
/* /*
* DSP filter state * DSP filter state

View File

@ -66,11 +66,8 @@ void M17Demodulator::init()
newFrame = false; newFrame = false;
#ifdef PLATFORM_LINUX #ifdef PLATFORM_LINUX
FILE *csv_log = fopen("demod_log_1.csv", "w"); FILE *csv_log = fopen("demod_log.csv", "w");
fprintf(csv_log, "Signal,Convolution,Threshold,Offset\n"); fprintf(csv_log, "Signal,Convolution,Threshold,Offset,Sample,Max,Min,Symbol,I\n");
fclose(csv_log);
csv_log = fopen("demod_log_2.csv", "w");
fprintf(csv_log, "Sample,Max,Min,Symbol,I\n");
fclose(csv_log); fclose(csv_log);
#endif // PLATFORM_MOD17 #endif // PLATFORM_MOD17
} }
@ -124,8 +121,8 @@ float M17Demodulator::getCorrelationStddev()
void M17Demodulator::resetQuantizationStats() void M17Demodulator::resetQuantizationStats()
{ {
qnt_max = 0.0f; qnt_pos_avg = 0.0f;
qnt_min = 0.0f; qnt_neg_avg = 0.0f;
} }
void M17Demodulator::updateQuantizationStats(int32_t offset) void M17Demodulator::updateQuantizationStats(int32_t offset)
@ -136,14 +133,28 @@ void M17Demodulator::updateQuantizationStats(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 > qnt_max) if (sample > 0)
qnt_max = sample; {
// If the FIFO is not full just push a new sample
if (qnt_pos_fifo.size() >= QNT_SMA_WINDOW)
{
qnt_pos_avg += 1 / static_cast<float>(QNT_SMA_WINDOW) *
(sample - qnt_pos_fifo.back());
qnt_pos_fifo.pop_back();
}
qnt_pos_fifo.push_front(sample);
}
else else
qnt_max *= QNT_STATS_ALPHA; {
if (sample < qnt_min) // If the FIFO is not full just push a new sample
qnt_min = sample; if (qnt_neg_fifo.size() >= QNT_SMA_WINDOW)
else {
qnt_min *= QNT_STATS_ALPHA; qnt_neg_avg += 1 / static_cast<float>(QNT_SMA_WINDOW) *
(sample - qnt_neg_fifo.back());
qnt_neg_fifo.pop_back();
}
qnt_neg_fifo.push_front(sample);
}
} }
int32_t M17Demodulator::convolution(int32_t offset, int32_t M17Demodulator::convolution(int32_t offset,
@ -169,7 +180,7 @@ int32_t M17Demodulator::convolution(int32_t offset,
sync_t M17Demodulator::nextFrameSync(int32_t offset) sync_t M17Demodulator::nextFrameSync(int32_t offset)
{ {
#ifdef PLATFORM_LINUX #ifdef PLATFORM_LINUX
FILE *csv_log = fopen("demod_log_1.csv", "a"); FILE *csv_log = fopen("demod_log.csv", "a");
#endif #endif
sync_t syncword = { -1, false }; sync_t syncword = { -1, false };
@ -192,11 +203,12 @@ sync_t M17Demodulator::nextFrameSync(int32_t offset)
else // Otherwise use regular data buffer else // Otherwise use regular data buffer
sample = baseband.data[i]; sample = baseband.data[i];
fprintf(csv_log, "%" PRId16 ",%d,%f,%d\n", fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
sample, sample,
conv, conv / 10,
CONV_THRESHOLD_FACTOR * getCorrelationStddev(), CONV_THRESHOLD_FACTOR * getCorrelationStddev() / 10,
i); i,
0,0.0,0.0,0,0);
#endif #endif
// Positive correlation peak -> frame syncword // Positive correlation peak -> frame syncword
@ -226,9 +238,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_max) / 2) if (sample > static_cast< int16_t >(qnt_pos_avg))
return +3; return +3;
else if (sample < static_cast< int16_t >(qnt_min) / 2) else if (sample < static_cast< int16_t >(qnt_neg_avg))
return -3; return -3;
else if (sample > 0) else if (sample > 0)
return +1; return +1;
@ -271,7 +283,7 @@ bool M17Demodulator::update()
dsp_dcRemoval(&dsp_state, baseband.data, baseband.len); dsp_dcRemoval(&dsp_state, baseband.data, baseband.len);
#ifdef PLATFORM_LINUX #ifdef PLATFORM_LINUX
FILE *csv_log = fopen("demod_log_2.csv", "a"); FILE *csv_log = fopen("demod_log.csv", "a");
#endif #endif
if(baseband.data != NULL) if(baseband.data != NULL)
@ -314,12 +326,13 @@ bool M17Demodulator::update()
int8_t symbol = quantize(symbol_index); int8_t symbol = quantize(symbol_index);
#ifdef PLATFORM_LINUX #ifdef PLATFORM_LINUX
fprintf(csv_log, "%" PRId16 ",%f,%f,%d,%d\n", fprintf(csv_log, "%" PRId16 ",%d,%f,%d,%" PRId16 ",%f,%f,%d,%d\n",
baseband.data[symbol_index] - (int16_t) qnt_ema, 0,0,0.0,0,
qnt_max / 2, baseband.data[symbol_index],
qnt_min / 2, qnt_pos_avg,
qnt_neg_avg,
symbol * 666, symbol * 666,
frameIndex == 0 ? 2300 : symbol_index); frameIndex);
#endif #endif
setSymbol<M17_FRAME_BYTES>(*activeFrame, frameIndex, symbol); setSymbol<M17_FRAME_BYTES>(*activeFrame, frameIndex, symbol);

View File

@ -6,11 +6,15 @@ from sys import argv
plt.rcParams["figure.autolayout"] = True plt.rcParams["figure.autolayout"] = True
df = pd.read_csv(argv[1]) df = pd.read_csv(argv[1])
#df = df.head(n=10000)
print("Contents in csv file:\n", df) print("Contents in csv file:\n", df)
#plt.plot(df.index, df.Input) plt.plot(df.index, df.Signal)
#plt.plot(df.index, df.RRCSignal) plt.plot(df.index, df.Convolution)
plt.plot(df.index, df.LSFConvolution) plt.plot(df.index, df.Threshold)
plt.plot(df.index, df.FrameConvolution) plt.plot(df.index, df.Threshold * -1)
plt.plot(df.index, df.Stddev) plt.plot(df.index, df.Offset)
plt.plot(df.index, df.Sample)
plt.plot(df.index, df.Max)
plt.plot(df.index, df.Min)
#plt.plot(df.index, df.Symbol)
plt.plot(df.index, df.I)
plt.show() plt.show()

View File

@ -1,15 +0,0 @@
#! /usr/bin/env python3
import pandas as pd
from matplotlib import pyplot as plt
from sys import argv
plt.rcParams["figure.autolayout"] = True
df = pd.read_csv(argv[1])
print("Contents in csv file:\n", df)
plt.plot(df.index, df.Signal)
plt.plot(df.index, df.Convolution)
plt.plot(df.index, df.Threshold)
plt.plot(df.index, df.Threshold * -1)
plt.plot(df.index, df.Offset)
plt.show()

View File

@ -1,15 +0,0 @@
#! /usr/bin/env python3
import pandas as pd
from matplotlib import pyplot as plt
from sys import argv
plt.rcParams["figure.autolayout"] = True
df = pd.read_csv(argv[1])
print("Contents in csv file:\n", df)
plt.plot(df.index, df.Sample)
plt.plot(df.index, df.Max)
plt.plot(df.index, df.Min)
plt.plot(df.index, df.Symbol)
plt.plot(df.index, df.I)
plt.show()