M17 demod: fixed BERT

This commit is contained in:
f4exb 2022-07-06 07:01:42 +02:00
parent 1fa3adb669
commit c3f55af6a6
14 changed files with 125 additions and 45 deletions

View File

@ -49,6 +49,8 @@ add_library(modems SHARED
${modems_SOURCES}
)
target_link_libraries(modems)
target_link_libraries(modems
Qt5::Core
)
install(TARGETS modems DESTINATION ${INSTALL_LIB_DIR})

View File

@ -1,3 +1,6 @@
#include <QDebug>
#include <QString>
#include "M17Demodulator.h"
namespace modemm17 {
@ -103,6 +106,7 @@ void M17Demodulator::dcd_off()
dev.deviation(),
dev.offset(),
(int) demodState,
(int) sync_word_type,
clock_recovery.clock_estimate(),
sample_index,
sync_sample_index,
@ -210,7 +214,7 @@ void M17Demodulator::do_lsf_sync()
if (sync_triggered > 0.1)
{
std::cerr << "M17Demodulator::do_lsf_sync: preamble:" << sync_triggered << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: preamble:" << sync_triggered;
return;
}
@ -218,11 +222,11 @@ void M17Demodulator::do_lsf_sync()
bert_triggered = packet_sync.triggered(correlator);
if (sync_triggered != 0) {
std::cerr << "M17Demodulator::do_lsf_sync: sync_triggered:" << sync_triggered << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: sync_triggered:" << sync_triggered;
}
if (bert_triggered != 0) {
std::cerr << "M17Demodulator::do_lsf_sync: bert_triggered:" << bert_triggered << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: bert_triggered:" << bert_triggered;
}
if (bert_triggered < 0)
@ -232,7 +236,7 @@ void M17Demodulator::do_lsf_sync()
update_values(sample_index);
demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::BERT;
std::cerr << "M17Demodulator::do_lsf_sync: BERT:" << (int) sync_word_type << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: BERT:" << (int) sync_word_type;
}
else if (bert_triggered > 0)
{
@ -241,7 +245,7 @@ void M17Demodulator::do_lsf_sync()
update_values(sample_index);
demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::PACKET;
std::cerr << "M17Demodulator::do_lsf_sync: PACKET:" << (int) sync_word_type << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: PACKET:" << (int) sync_word_type;
}
else if (std::abs(sync_triggered) > 0.1)
{
@ -253,13 +257,13 @@ void M17Demodulator::do_lsf_sync()
{
demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::LSF;
std::cerr << "M17Demodulator::do_lsf_sync: LSF:" << (int) sync_word_type << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: LSF:" << (int) sync_word_type;
}
else
{
demodState = DemodState::FRAME;
sync_word_type = M17FrameDecoder::SyncWordType::STREAM;
std::cerr << "M17Demodulator::do_lsf_sync: STREAM:" << (int) sync_word_type << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: STREAM:" << (int) sync_word_type;
}
}
else if (++missing_sync_count > 192)
@ -267,7 +271,7 @@ void M17Demodulator::do_lsf_sync()
demodState = DemodState::UNLOCKED;
decoder.reset();
missing_sync_count = 0;
std::cerr << "M17Demodulator::do_lsf_sync: UNLOCKED:" << (int) sync_word_type << std::endl;
qDebug() << "modemm17::M17Demodulator::do_lsf_sync: UNLOCKED:" << (int) sync_word_type;
}
else
{
@ -403,7 +407,6 @@ void M17Demodulator::do_frame(float filtered_sample)
if (len != 0)
{
// std::cerr << "M17Demodulator::do_frame: sync_word_type:" << (int) sync_word_type << " len:" << len << std::endl;
need_clock_update_ = true;
M17FrameDecoder::input_buffer_t buffer;
std::copy(tmp, tmp + len, buffer.begin());
@ -411,6 +414,11 @@ void M17Demodulator::do_frame(float filtered_sample)
cost_count = viterbi_cost > 90 ? cost_count + 1 : 0;
cost_count = viterbi_cost > 100 ? cost_count + 1 : cost_count;
cost_count = viterbi_cost > 110 ? cost_count + 1 : cost_count;
// qDebug() << "modemm17::M17Demodulator::do_frame: "
// << "sync_word_type:" << (int) sync_word_type
// << " len:" << len
// << " viterbi_cost: " << viterbi_cost
// << " cost_count" << cost_count;
if (cost_count > 75)
{
@ -487,6 +495,7 @@ void M17Demodulator::operator()(const float input)
dev.deviation(),
dev.offset(),
(int) demodState,
(int) sync_word_type,
clock_recovery.clock_estimate(),
sample_index,
sync_sample_index,
@ -575,6 +584,7 @@ void M17Demodulator::operator()(const float input)
dev.deviation(),
dev.offset(),
(int) demodState,
(int) sync_word_type,
clock_recovery.clock_estimate(),
sample_index,
sync_sample_index,

View File

@ -37,7 +37,7 @@ struct M17_API M17Demodulator
using collelator_t = Correlator;
using sync_word_t = SyncWord<collelator_t>;
using callback_t = M17FrameDecoder::callback_t;
using diagnostic_callback_t = std::function<void(bool, float, float, float, int, float, int, int, int, int)>;
using diagnostic_callback_t = std::function<void(bool, float, float, float, int, int, float, int, int, int, int)>;
enum class DemodState {
UNLOCKED,

View File

@ -2,6 +2,9 @@
#pragma once
#include <QDebug>
#include <QString>
#include "M17Randomizer.h"
#include "PolynomialInterleaver.h"
#include "Trellis.h"
@ -22,15 +25,16 @@ namespace modemm17
template <typename C, size_t N>
void dump(const std::array<C,N>& data, char header = 'D')
QString dump(const std::array<C,N>& data, char header = 'D')
{
std::cerr << header << " = ";
QString s(header);
s += "=";
for (auto c : data) {
std::cerr << std::hex << std::setw(2) << std::setfill('0') << (int) c << " ";
s += QString("%1 ").arg((int) c, 2, 16, QChar('0'));
}
std::cerr << std::dec << std::endl;
return s;
}
struct M17FrameDecoder
@ -153,8 +157,7 @@ struct M17FrameDecoder
viterbi_cost = viterbi_.decode(depuncture_buffer.lsf, decode_buffer.lsf);
to_byte_array(decode_buffer.lsf, output_buffer.lsf);
// std::cerr << "M17FrameDecoder::decode_lsf: vierbi:" << viterbi_cost << std::endl;
// dump(output_buffer.lsf);
// qDebug() << "modemm17::M17FrameDecoder::decode_lsf: vierbi:" << viterbi_cost <<dump(output_buffer.lsf);
crc_.reset();
for (auto c : output_buffer.lsf) crc_(c);
@ -169,8 +172,7 @@ struct M17FrameDecoder
}
else
{
std::cerr << "M17FrameDecoder::decode_lsf: bad CRC:" << std::endl;
dump(output_buffer.lsf);
qDebug() << "modemm17::M17FrameDecoder::decode_lsf: bad CRC:" << dump(output_buffer.lsf);
}
lich_segments = 0;
@ -262,9 +264,10 @@ struct M17FrameDecoder
return DecodeResult::INCOMPLETE;
}
DecodeResult decode_bert(input_buffer_t&, int& viterbi_cost)
DecodeResult decode_bert(input_buffer_t& buffer, int& viterbi_cost)
{
depunctured_buffer_t depuncture_buffer;
depuncture(buffer, depuncture_buffer.bert, P2);
viterbi_cost = viterbi_.decode(depuncture_buffer.bert, decode_buffer.bert);
to_byte_array(decode_buffer.bert, output_buffer.bert);

View File

@ -1,5 +1,8 @@
#pragma once
#include <QDebug>
#include <QString>
#include "FirFilter.h"
#include "LinkSetupFrame.h"
#include "CRC16.h"
@ -177,7 +180,7 @@ public:
auto size = puncture(encoded, punctured, P1);
if (size != 368) {
std::cerr << "modemm17::M17Modulator::make_lsf: incorrect size (not 368)" << size;
qWarning() << "modemm17::M17Modulator::make_lsf: incorrect size (not 368)" << size;
}
interleaver.interleave(punctured);
@ -277,7 +280,7 @@ public:
auto size = modemm17::puncture(encoded, punctured, modemm17::P2);
if (size != 272) {
std::cerr << "modemm17::M17Modulator::make_stream_data_frame: incorrect size (not 272)" << size;
qWarning() << "modemm17::M17Modulator::make_stream_data_frame: incorrect size (not 272)" << size;
}
return punctured;
@ -310,7 +313,9 @@ public:
packet_assembly[25] = 0x80 | ((packet_size+2)<<2); // sent packet size includes CRC
packet_assembly[packet_size] = crc_.get_bytes()[1];
packet_assembly[packet_size+1] = crc_.get_bytes()[0];
std::cerr << "M17Modulator::make_packet_frame:" << std::hex << (int) crc_.get_bytes()[1] << ":" << (int) crc_.get_bytes()[0] << std::endl;
qDebug() << QString("modemm17::M17Modulator::make_packet_frame: %1:%2")
.arg((int) crc_.get_bytes()[1], 2, 16, QChar('0'))
.arg((int) crc_.get_bytes()[0], 2, 16, QChar('0'));
}
else
{
@ -359,7 +364,7 @@ public:
auto size = puncture(encoded, punctured, P3);
if (size != 368) {
std::cerr << "modemm17::M17Modulator::make_packet_frame: incorrect size (not 368)" << size;
qWarning() << "modemm17::M17Modulator::make_packet_frame: incorrect size (not 368)" << size;
}
interleaver.interleave(punctured);
@ -372,7 +377,7 @@ public:
{
std::array<uint8_t, 25> data; // 24.6125 bytes, 197 bits
// Generate the data.
// Generate the data (24*8 = 192 bits).
for (size_t i = 0; i != data.size() - 1; ++i)
{
uint8_t byte = 0;
@ -386,8 +391,8 @@ public:
data[i] = byte;
}
// Generate the data (last 5 bits).
uint8_t byte = 0;
for (int i = 0; i != 5; ++i)
{
byte <<= 1;
@ -397,10 +402,12 @@ public:
byte <<= 3;
data[24] = byte;
// Convolutional encode
std::array<uint8_t, 402> encoded;
size_t index = 0;
uint32_t memory = 0;
// 24*8 = 192 first bits
for (size_t i = 0; i != data.size() - 1; ++i)
{
auto b = data[i];
@ -415,8 +422,8 @@ public:
}
}
// last 5 bits
auto b = data[24];
for (size_t j = 0; j != 5; ++j)
{
uint32_t x = (b & 0x80) >> 7;
@ -438,7 +445,7 @@ public:
auto size = puncture(encoded, punctured, P2);
if (size != 368) {
std::cerr << "modemm17::M17Modulator::make_bert_frame: incorrect size (not 368)" << size;
qWarning() << "modemm17::M17Modulator::make_bert_frame: incorrect size (not 368)" << size;
}
return punctured;

View File

@ -47,7 +47,7 @@ constexpr auto P1 = std::array<int8_t, 61>{
1, 0, 1, 1 // M15
};
/// Puncture matrix for audio frames. Rate 6/11.
/// Puncture matrix for audio and BERT frames. Rate 11/12.
constexpr auto P2 = std::array<int8_t, 12>{
1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 0};

View File

@ -219,6 +219,7 @@ public:
float& deviation,
float& offset,
int& status,
int& sync_word_type,
float& clock,
int& sampleIndex,
int& syncIndex,
@ -226,7 +227,19 @@ public:
int& viterbiCost
) const
{
m_basebandSink->getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost);
m_basebandSink->getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
}
uint32_t getLSFCount() const { return m_basebandSink->getLSFCount(); }

View File

@ -80,6 +80,7 @@ public:
float& deviation,
float& offset,
int& status,
int& sync_word_type,
float& clock,
int& sampleIndex,
int& syncIndex,
@ -87,7 +88,19 @@ public:
int& viterbiCost
) const
{
m_sink.getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost);
m_sink.getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
}
uint32_t getLSFCount() const { return m_sink.getLSFCount(); }

View File

@ -604,13 +604,26 @@ void M17DemodGUI::tick()
float deviation;
float offset;
int status;
int sync_word_type;
float clock;
int sampleIndex;
int syncIndex;
int clockIndex;
int viterbiCost;
m_m17Demod->getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost);
m_m17Demod->getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
if (dcd) {
ui->dcdLabel->setStyleSheet("QLabel { background-color : green; }");
@ -624,7 +637,7 @@ void M17DemodGUI::tick()
ui->lockLabel->setStyleSheet("QLabel { background-color : green; }");
}
ui->syncText->setText(getStatus(status, m_m17Demod->getStreamElsePacket(), m_m17Demod->getStdPacketProtocol()));
ui->syncText->setText(getStatus(status, sync_word_type, m_m17Demod->getStreamElsePacket(), m_m17Demod->getStdPacketProtocol()));
ui->evmText->setText(tr("%1").arg(evm*100.0f, 3, 'f', 1));
ui->deviationText->setText(tr("%1").arg(deviation/1.5f, 3, 'f', 2));
ui->offsetText->setText(tr("%1").arg(offset/1.5f, 3, 'f', 2));
@ -657,11 +670,11 @@ void M17DemodGUI::tick()
m_tickCount++;
}
QString M17DemodGUI::getStatus(int status, bool streamElsePacket, int packetProtocol)
QString M17DemodGUI::getStatus(int status, int sync_word_type, bool streamElsePacket, int packetProtocol)
{
if (status == 0) {
return "Unlocked";
} else if (status == 4) {
} else if ((status == 5) && (sync_word_type == 3)) {
return "BERT";
} else if (streamElsePacket) {
return "Stream";

View File

@ -110,7 +110,7 @@ private:
bool handleMessage(const Message& message);
void makeUIConnections();
void updateAbsoluteCenterFrequency();
QString getStatus(int status, bool streamElsePacket, int packetProtocol);
QString getStatus(int status, int sync_word_type, bool streamElsePacket, int packetProtocol);
void packetReceived(QByteArray packet);
void leaveEvent(QEvent*);

View File

@ -1370,13 +1370,13 @@
<rect>
<x>203</x>
<y>65</y>
<width>25</width>
<width>30</width>
<height>28</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>25</width>
<width>30</width>
<height>0</height>
</size>
</property>

View File

@ -102,6 +102,7 @@ void M17DemodProcessor::diagnostic_callback(
float deviation,
float offset,
int status,
int sync_word_type,
float clock,
int sample_index,
int sync_index,
@ -116,6 +117,7 @@ void M17DemodProcessor::diagnostic_callback(
m_this->m_deviation = deviation;
m_this->m_offset = offset;
m_this->m_status = status;
m_this->m_syncWordType = sync_word_type;
m_this->m_clock = clock;
m_this->m_sampleIndex = sample_index;
m_this->m_syncIndex = sync_index;

View File

@ -71,6 +71,7 @@ public:
float& deviation,
float& offset,
int& status,
int& sync_word_type,
float& clock,
int& sampleIndex,
int& syncIndex,
@ -83,6 +84,7 @@ public:
deviation = m_deviation;
offset = m_offset;
status = m_status;
sync_word_type = m_syncWordType;
clock = m_clock;
sampleIndex = m_sampleIndex;
syncIndex = m_syncIndex;
@ -112,16 +114,17 @@ private:
M17DemodAudioInterpolatorFilter m_upsamplingFilter;
// Diagnostics
bool m_dcd; //!< Data Carrier Detect
float m_evm; //!< Error Vector Magnitude in percent
float m_deviation; //!< Estimated deviation. Ideal = 1.0
float m_offset; //!< Estimated frequency offset. Ideal = 0.0 practically limited to ~[-0.18, 0.18]
int m_status; //!< Status
bool m_dcd; //!< Data Carrier Detect
float m_evm; //!< Error Vector Magnitude in percent
float m_deviation; //!< Estimated deviation. Ideal = 1.0
float m_offset; //!< Estimated frequency offset. Ideal = 0.0 practically limited to ~[-0.18, 0.18]
int m_status; //!< Status
int m_syncWordType; //!< Sync word type
float m_clock;
int m_sampleIndex;
int m_syncIndex;
int m_clockIndex;
int m_viterbiCost; //!< [-1:128] ideally 0
int m_viterbiCost; //!< [-1:128] ideally 0
QString m_srcCall;
QString m_destCall;
@ -141,6 +144,7 @@ private:
float deviation,
float offset,
int status,
int sync_word_type,
float clock,
int sample_index,
int sync_index,

View File

@ -82,6 +82,7 @@ public:
float& deviation,
float& offset,
int& status,
int& sync_word_type,
float& clock,
int& sampleIndex,
int& syncIndex,
@ -89,7 +90,19 @@ public:
int& viterbiCost
) const
{
m_m17DemodProcessor.getDiagnostics(dcd, evm, deviation, offset, status, clock, sampleIndex, syncIndex, clockIndex, viterbiCost);
m_m17DemodProcessor.getDiagnostics(
dcd,
evm,
deviation,
offset,
status,
sync_word_type,
clock,
sampleIndex,
syncIndex,
clockIndex,
viterbiCost
);
}
uint32_t getLSFCount() const { return m_m17DemodProcessor.getLSFCount(); }