kopia lustrzana https://github.com/OpenRTX/OpenRTX
M17 Demodulator bugfixes
Fixed several bugs in the M17 Demodulator code. TG-81pull/68/head
rodzic
d2c7be9cc8
commit
a091bca35f
|
@ -118,6 +118,7 @@ private:
|
||||||
*/
|
*/
|
||||||
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 lsf_syncword_bytes[2] = {0x55, 0xf7};
|
||||||
uint8_t stream_syncword_bytes[2] = {0xff, 0x5d};
|
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 >;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <interfaces/gpio.h>
|
#include <interfaces/gpio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace M17
|
namespace M17
|
||||||
{
|
{
|
||||||
|
@ -55,6 +56,15 @@ void M17Demodulator::init()
|
||||||
frameIndex = 0;
|
frameIndex = 0;
|
||||||
phase = 0;
|
phase = 0;
|
||||||
locked = false;
|
locked = false;
|
||||||
|
|
||||||
|
#ifndef PLATFORM_MOD17
|
||||||
|
FILE *csv_log = fopen("demod_log_1.csv", "w");
|
||||||
|
fprintf(csv_log, "Signal,Convolution,Threshold\n");
|
||||||
|
fclose(csv_log);
|
||||||
|
csv_log = fopen("demod_log_2.csv", "w");
|
||||||
|
fprintf(csv_log, "Sample,Max,Min,Symbol,I\n");
|
||||||
|
fclose(csv_log);
|
||||||
|
#endif // PLATFORM_MOD17
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17Demodulator::terminate()
|
void M17Demodulator::terminate()
|
||||||
|
@ -73,6 +83,8 @@ void M17Demodulator::startBasebandSampling()
|
||||||
M17_INPUT_BUF_SIZE,
|
M17_INPUT_BUF_SIZE,
|
||||||
BUF_CIRC_DOUBLE,
|
BUF_CIRC_DOUBLE,
|
||||||
M17_RX_SAMPLE_RATE);
|
M17_RX_SAMPLE_RATE);
|
||||||
|
// Clean start of the demodulation statistics
|
||||||
|
resetCorrelationStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
void M17Demodulator::stopBasebandSampling()
|
void M17Demodulator::stopBasebandSampling()
|
||||||
|
@ -124,7 +136,6 @@ void M17Demodulator::updateQuantizationStats(int32_t offset)
|
||||||
{
|
{
|
||||||
qnt_max *= qnt_maxmin_alpha;
|
qnt_max *= qnt_maxmin_alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sample < qnt_min)
|
if (sample < qnt_min)
|
||||||
{
|
{
|
||||||
qnt_min = sample;
|
qnt_min = sample;
|
||||||
|
@ -167,6 +178,9 @@ int32_t M17Demodulator::convolution(int32_t offset,
|
||||||
|
|
||||||
sync_t M17Demodulator::nextFrameSync(int32_t offset)
|
sync_t M17Demodulator::nextFrameSync(int32_t offset)
|
||||||
{
|
{
|
||||||
|
#ifndef PLATFORM_MOD17
|
||||||
|
FILE *csv_log = fopen("demod_log_1.csv", "a");
|
||||||
|
#endif
|
||||||
sync_t syncword = { -1, false };
|
sync_t syncword = { -1, false };
|
||||||
// Find peaks in the correlation between the baseband and the frame syncword
|
// Find peaks in the correlation between the baseband and the frame syncword
|
||||||
// Leverage the fact LSF syncword is the opposite of the frame syncword
|
// Leverage the fact LSF syncword is the opposite of the frame syncword
|
||||||
|
@ -175,10 +189,8 @@ 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);
|
||||||
//printf("%d, ", conv);
|
|
||||||
//if (i % 8 == 0)
|
|
||||||
// printf("\r\n");
|
|
||||||
updateCorrelationStats(conv);
|
updateCorrelationStats(conv);
|
||||||
|
updateQuantizationStats(baseband.data[i]);
|
||||||
// Positive correlation peak -> frame syncword
|
// Positive correlation peak -> frame syncword
|
||||||
if (conv > getCorrelationStddev() * conv_threshold_factor)
|
if (conv > getCorrelationStddev() * conv_threshold_factor)
|
||||||
{
|
{
|
||||||
|
@ -227,11 +239,13 @@ bool M17Demodulator::isFrameLSF()
|
||||||
void M17Demodulator::update()
|
void M17Demodulator::update()
|
||||||
{
|
{
|
||||||
M17::sync_t syncword = { 0, false };
|
M17::sync_t syncword = { 0, false };
|
||||||
int32_t offset = -(int32_t) M17_BRIDGE_SIZE;
|
int32_t offset = locked ? 0 : -(int32_t) M17_BRIDGE_SIZE;
|
||||||
int32_t phase = 0;
|
|
||||||
uint16_t decoded_syms = 0;
|
uint16_t decoded_syms = 0;
|
||||||
// Read samples from the ADC
|
// Read samples from the ADC
|
||||||
baseband = inputStream_getData(basebandId);
|
baseband = inputStream_getData(basebandId);
|
||||||
|
#ifndef PLATFORM_MOD17
|
||||||
|
FILE *csv_log = fopen("demod_log_2.csv", "a");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(baseband.data != NULL)
|
if(baseband.data != NULL)
|
||||||
{
|
{
|
||||||
|
@ -242,14 +256,14 @@ void M17Demodulator::update()
|
||||||
baseband.data[i] = static_cast< int16_t >(M17::rrc(elem));
|
baseband.data[i] = static_cast< int16_t >(M17::rrc(elem));
|
||||||
}
|
}
|
||||||
// Process the buffer
|
// Process the buffer
|
||||||
while(syncword.index != -1 && (offset + 1 + phase +
|
while(syncword.index != -1 &&
|
||||||
|
(offset + 1 + phase +
|
||||||
(int32_t) M17_SAMPLES_PER_SYMBOL * decoded_syms <
|
(int32_t) M17_SAMPLES_PER_SYMBOL * decoded_syms <
|
||||||
(int32_t) baseband.len))
|
(int32_t) baseband.len))
|
||||||
{
|
{
|
||||||
// If we are not locked search for a syncword
|
// If we are not locked search for a syncword
|
||||||
if (!locked)
|
if (!locked)
|
||||||
{
|
{
|
||||||
//printf("\nSearching at offset: %d\n", offset);
|
|
||||||
syncword = nextFrameSync(offset);
|
syncword = nextFrameSync(offset);
|
||||||
if (syncword.index != -1) // Lock was just acquired
|
if (syncword.index != -1) // Lock was just acquired
|
||||||
{
|
{
|
||||||
|
@ -259,42 +273,47 @@ void M17Demodulator::update()
|
||||||
#endif // PLATFORM_MOD17
|
#endif // PLATFORM_MOD17
|
||||||
isLSF = syncword.lsf;
|
isLSF = syncword.lsf;
|
||||||
offset = syncword.index + 1;
|
offset = syncword.index + 1;
|
||||||
// DEBUG: prints
|
|
||||||
//if (isLSF)
|
|
||||||
// printf("\nFound LSF at position %d!\r\n", syncword.index);
|
|
||||||
//else
|
|
||||||
// printf("\nFound SYNC at position %d!\r\n", syncword.index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// While we are locked, demodulate available samples
|
// While we are locked, demodulate available samples
|
||||||
while (locked)
|
else
|
||||||
{
|
{
|
||||||
// Slice the input buffer to extract a frame and quantize
|
// Slice the input buffer to extract a frame and quantize
|
||||||
int32_t symbol_index = offset + 1 + phase + M17_SAMPLES_PER_SYMBOL * decoded_syms;
|
int32_t symbol_index = offset + 1 + phase + M17_SAMPLES_PER_SYMBOL * decoded_syms;
|
||||||
updateQuantizationStats(baseband.data[symbol_index]);
|
updateQuantizationStats(baseband.data[symbol_index]);
|
||||||
int8_t symbol = quantize(symbol_index);
|
int8_t symbol = quantize(symbol_index);
|
||||||
|
#ifndef PLATFORM_MOD17
|
||||||
|
fprintf(csv_log, "%" PRId16 ",%f,%f,%d,%d\n",
|
||||||
|
baseband.data[symbol_index],
|
||||||
|
getQuantizationMax() * 2 / 3,
|
||||||
|
getQuantizationMin() * 2 / 3,
|
||||||
|
symbol * 10000,
|
||||||
|
symbol_index);
|
||||||
|
#endif
|
||||||
setSymbol<M17_FRAME_BYTES>(*activeFrame, frameIndex, symbol);
|
setSymbol<M17_FRAME_BYTES>(*activeFrame, frameIndex, symbol);
|
||||||
decoded_syms++;
|
decoded_syms++;
|
||||||
frameIndex++;
|
frameIndex++;
|
||||||
//printf("%2d ", symbol);
|
|
||||||
//if (decoded_syms % 16 == 0)
|
|
||||||
// printf("\n");
|
|
||||||
// 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 (frameIndex == M17_FRAME_SYMBOLS)
|
||||||
{
|
{
|
||||||
std::swap(activeFrame, idleFrame);
|
std::swap(activeFrame, idleFrame);
|
||||||
frameIndex = 0;
|
frameIndex = 0;
|
||||||
|
#ifndef PLATFORM_MOD17
|
||||||
// DEBUG: print idleFrame bytes
|
// DEBUG: print idleFrame bytes
|
||||||
//for(size_t i = 0; i < idleFrame->size(); i+=2)
|
for(size_t i = 0; i < idleFrame->size(); i+=2)
|
||||||
//{
|
{
|
||||||
// if (i % 16 == 14)
|
if (i % 16 == 14)
|
||||||
// printf("\r\n");
|
printf("\r\n");
|
||||||
// printf(" %02X%02X", (*idleFrame)[i], (*idleFrame)[i+1]);
|
printf(" %02X%02X", (*idleFrame)[i], (*idleFrame)[i+1]);
|
||||||
//}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
// Check if the decoded syncword matches with frame or lsf sync
|
||||||
if (frameIndex == M17_SYNCWORD_SYMBOLS &&
|
if (frameIndex == M17_SYNCWORD_SYMBOLS &&
|
||||||
((*activeFrame)[0] != stream_syncword_bytes[0] ||
|
((*activeFrame)[0] != stream_syncword_bytes[0] ||
|
||||||
(*activeFrame)[1] != stream_syncword_bytes[1])) // Lock is lost
|
(*activeFrame)[1] != stream_syncword_bytes[1]) &&
|
||||||
|
((*activeFrame)[0] != lsf_syncword_bytes[0] ||
|
||||||
|
(*activeFrame)[1] != lsf_syncword_bytes[1]))
|
||||||
{
|
{
|
||||||
locked = false;
|
locked = false;
|
||||||
std::swap(activeFrame, idleFrame);
|
std::swap(activeFrame, idleFrame);
|
||||||
|
@ -306,17 +325,23 @@ void M17Demodulator::update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We are at the end of the buffer
|
// We are at the end of the buffer
|
||||||
if (locked) {
|
if (locked)
|
||||||
|
{
|
||||||
// Compute phase of next buffer
|
// Compute phase of next buffer
|
||||||
phase = offset % M17_SAMPLES_PER_SYMBOL +
|
phase = offset % M17_SAMPLES_PER_SYMBOL +
|
||||||
(M17_INPUT_BUF_SIZE % M17_SAMPLES_PER_SYMBOL);
|
(M17_INPUT_BUF_SIZE % M17_SAMPLES_PER_SYMBOL);
|
||||||
}
|
}
|
||||||
// Copy last N samples to bridge buffer
|
else
|
||||||
memcpy(basebandBridge,
|
{
|
||||||
baseband.data + baseband.len - M17_BRIDGE_SIZE,
|
// Copy last N samples to bridge buffer
|
||||||
sizeof(int16_t) * M17_BRIDGE_SIZE);
|
memcpy(basebandBridge,
|
||||||
|
baseband.data + (baseband.len - M17_BRIDGE_SIZE),
|
||||||
|
sizeof(int16_t) * M17_BRIDGE_SIZE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//printf("END\n");
|
#ifndef PLATFORM_MOD17
|
||||||
|
fclose(csv_log);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* M17 */
|
} /* M17 */
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
gdb_port 3333
|
||||||
|
|
||||||
|
source [find interface/jlink.cfg]
|
||||||
|
|
||||||
|
transport select swd
|
||||||
|
|
||||||
|
source [find target/stm32f4x.cfg]
|
|
@ -0,0 +1,13 @@
|
||||||
|
#! /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.show()
|
|
@ -0,0 +1,15 @@
|
||||||
|
#! /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()
|
Ładowanie…
Reference in New Issue