Improved robustness of frame type detection, now based on minimum hamming distance between syncwords

This commit is contained in:
Silvano Seva 2022-05-17 21:54:46 +02:00
parent 115982d279
commit 7aff678069
5 changed files with 79 additions and 36 deletions

View File

@ -238,14 +238,6 @@ private:
*/
int8_t quantize(int32_t offset);
/**
* Compute Hamming Distance between two bytes
*
* @param x: first byte
* @param y: second byte
*/
uint8_t hammingDistance(uint8_t x, uint8_t y);
/**
* Perform a limited search for a syncword using correlation
*

15
openrtx/include/protocols/M17/M17FrameDecoder.h Executable file → Normal file
View File

@ -25,6 +25,7 @@
#error This header is C++ only!
#endif
#include <cstdint>
#include <string>
#include <array>
#include "M17LinkSetupFrame.h"
@ -97,6 +98,17 @@ public:
private:
/**
* Determine frame type by searching which syncword among the standard M17
* ones has the minumum hamming distance from the given one. If the hamming
* distance exceeds a masimum absolute threshold the frame is declared of
* unknown type.
*
* @param syncWord: frame syncword.
* @return frame type based on the given syncword.
*/
M17FrameType getFrameType(const std::array< uint8_t, 2 >& syncWord);
/**
* Decode Link Setup Frame data and update the internal LSF field with
* the new frame data.
@ -129,6 +141,9 @@ private:
M17LinkSetupFrame lsfFromLich; ///< LSF assembled from LICH segments.
M17StreamFrame streamFrame; ///< Latest stream dat frame received.
M17Viterbi viterbi; ///< Viterbi decoder.
///< Maximum allowed hamming distance when determining the frame type.
static constexpr uint8_t MAX_SYNC_HAMM_DISTANCE = 4;
};
} // namespace M17

View File

@ -39,9 +39,9 @@ namespace M17
* of bytes. Bits are counted scanning from left to right, thus bit number zero
* is the leftmost bit of array[0].
*
* \param array: byte array.
* \param pos: bit position inside the array.
* \return value of the indexed bit, as boolean variable.
* @param array: byte array.
* @param pos: bit position inside the array.
* @return value of the indexed bit, as boolean variable.
*/
template < size_t N >
inline bool getBit(const std::array< uint8_t, N >& array, const size_t pos)
@ -57,9 +57,9 @@ inline bool getBit(const std::array< uint8_t, N >& array, const size_t pos)
* of bytes. Bits are counted scanning from left to right, thus bit number zero
* is the leftmost bit of array[0].
*
* \param array: byte array.
* \param pos: bit position inside the array.
* \param bit: bit value to be set.
* @param array: byte array.
* @param pos: bit position inside the array.
* @param bit: bit value to be set.
*/
template < size_t N >
inline void setBit(std::array< uint8_t, N >& array, const size_t pos,
@ -78,9 +78,9 @@ inline void setBit(std::array< uint8_t, N >& array, const size_t pos,
* symbols are filled from the least significant bit pair to the most
* significant bit pair.
*
* \param array: byte array.
* \param pos: symbol position inside the array.
* \param symbol: symbol to be set, either -3, -1, +1, +3.
* @param array: byte array.
* @param pos: symbol position inside the array.
* @param symbol: symbol to be set, either -3, -1, +1, +3.
*/
template < size_t N >
inline void setSymbol(std::array< uint8_t, N >& array, const size_t pos,
@ -108,6 +108,18 @@ inline void setSymbol(std::array< uint8_t, N >& array, const size_t pos,
}
}
/**
* Compute the hamming distance between two bytes.
*
* @param x: first byte.
* @param y: second byte.
* @return hamming distance between x and y.
*/
static inline uint8_t hammingDistance(const uint8_t x, const uint8_t y)
{
return __builtin_popcount(x ^ y);
}
} // namespace M17
#endif // M17_UTILS_H

View File

@ -310,11 +310,6 @@ bool M17::M17Demodulator::isLocked()
return locked;
}
uint8_t M17Demodulator::hammingDistance(uint8_t x, uint8_t y)
{
return __builtin_popcount(x ^ y);
}
int32_t M17Demodulator::syncwordSweep(int32_t offset)
{
int32_t max_conv = 0, max_index = 0;

View File

@ -23,6 +23,7 @@
#include <M17/M17Interleaver.h>
#include <M17/M17Decorrelator.h>
#include <M17/M17CodePuncturing.h>
#include <M17/M17Utils.h>
#include <algorithm>
using namespace M17;
@ -51,30 +52,58 @@ M17FrameType M17FrameDecoder::decodeFrame(const frame_t& frame)
decorrelate(data);
deinterleave(data);
auto type = getFrameType(syncWord);
switch(type)
{
case M17FrameType::LINK_SETUP:
decodeLSF(data);
break;
case M17FrameType::STREAM:
decodeStream(data);
break;
default:
break;
}
return type;
}
M17FrameType M17FrameDecoder::getFrameType(const std::array< uint8_t, 2 >& syncWord)
{
// Preamble
if((syncWord[0] == 0x77) && (syncWord[1] == 0x77))
M17FrameType type = M17FrameType::PREAMBLE;
uint8_t minDistance = hammingDistance(syncWord[0], 0x77)
+ hammingDistance(syncWord[1], 0x77);
// Link setup frame
uint8_t hammDistance = hammingDistance(syncWord[0], LSF_SYNC_WORD[0])
+ hammingDistance(syncWord[1], LSF_SYNC_WORD[1]);
if(hammDistance < minDistance)
{
return M17FrameType::PREAMBLE;
type = M17FrameType::LINK_SETUP;
minDistance = hammDistance;
}
// Link Setup Frame
if(syncWord == LSF_SYNC_WORD)
// Stream frame
hammDistance = hammingDistance(syncWord[0], STREAM_SYNC_WORD[0])
+ hammingDistance(syncWord[1], STREAM_SYNC_WORD[1]);
if(hammDistance < minDistance)
{
decodeLSF(data);
return M17FrameType::LINK_SETUP;
type = M17FrameType::STREAM;
minDistance = hammDistance;
}
// Stream data frame
uint8_t hd = __builtin_popcount(syncWord[0] ^ STREAM_SYNC_WORD[0])
+ __builtin_popcount(syncWord[1] ^ STREAM_SYNC_WORD[1]);
if(hd <= 4)
// Check value of minimum hamming distance found, if exceeds the allowed
// limit consider the frame as of unknown type.
if(minDistance > MAX_SYNC_HAMM_DISTANCE)
{
decodeStream(data);
return M17FrameType::STREAM;
type = M17FrameType::UNKNOWN;
}
// If we get here, we received an unknown frame
return M17FrameType::UNKNOWN;
return type;
}
void M17FrameDecoder::decodeLSF(const std::array< uint8_t, 46 >& data)