diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index 856d8d7a7..03b5219f5 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -26,6 +26,12 @@ #include "q65.h" #include "pdmath.h" +// Minimum codeword loglikelihood for decoding +#define Q65_LLH_THRESHOLD -260.0f + +// This value produce the same WER performance in decode_fullaplist +// #define Q65_LLH_THRESHOLD -262.0f + static int _q65_crc6(int *x, int sz); static void _q65_crc12(int *y, int *x, int sz); @@ -608,8 +614,13 @@ int q65_decode(q65_codec_ds *pCodec, int* pDecodedCodeword, int *pDecodedMsg, co if (pDecodedMsg) memcpy(pDecodedMsg,px,nK*sizeof(int)); - if (pDecodedCodeword==NULL) // user is not interested in it +#ifndef Q65_CHECKLLH + if (pDecodedCodeword==NULL) // user is not interested in the decoded codeword return rc; // return the number of iterations required to decode +#else + if (pDecodedCodeword==NULL) // we must have a buffer + return Q65_DECODE_INVPARAMS; // return error +#endif // crc matches therefore we can reconstruct the transmitted codeword // reencoding the information available in px... @@ -632,11 +643,83 @@ int q65_decode(q65_codec_ds *pCodec, int* pDecodedCodeword, int *pDecodedMsg, co memcpy(pDecodedCodeword,py,nN*sizeof(int)); // no puncturing } +#ifdef Q65_CHECKLLH + if (q65_check_llh(NULL,pDecodedCodeword, nN, nM, pIntrinsics)==0) // llh less than threshold + return Q65_DECODE_LLHLOW; +#endif + return rc; // return the number of iterations required to decode } +// Compute and verify the loglikelihood of the decoded codeword +int q65_check_llh(float *llh, const int* ydec, const int nN, const int nM, const float *pIntrin) +{ + int k; + float t = 0; + + for (k=0;k=Q65_LLH_THRESHOLD); +} + +// Full AP decoding from a list of codewords +int q65_decode_fullaplist(q65_codec_ds *codec, + int *ydec, + int *xdec, + const float *pIntrinsics, + const int *pCodewords, + const int nCodewords) +{ + int k; + int nK, nN, nM; + + float llh; + float maxllh = Q65_LLH_THRESHOLD-1; // set to a value less than the threshold + int maxcw = -1; // index of the most likely codeword + const int *pCw; + + if (nCodewords<1 || nCodewords>Q65_FULLAPLIST_SIZE) + return Q65_DECODE_INVPARAMS; // invalid list length + + nK = q65_get_message_length(codec); + nN = q65_get_codeword_length(codec); + nM = q65_get_alphabet_size(codec); + + // compute codewords log likelihoods and find max + pCw = pCodewords; // start from the first codeword + for (k=0;kmaxllh) { + maxllh = llh; + maxcw = k; + } + // point to next codeword + pCw+=nN; + } + + if (maxcw<0) // no llh larger than threshold found + return Q65_DECODE_FAILED; + + pCw = pCodewords+nN*maxcw; + memcpy(ydec,pCw,nN*sizeof(int)); + memcpy(xdec,pCw,nK*sizeof(int)); + + return maxcw; // index to the decoded message (>=0) + +} + + + // helper functions ------------------------------------------------------------- diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h index d36cb608f..bd80a934c 100644 --- a/lib/qra/q65/q65.h +++ b/lib/qra/q65/q65.h @@ -28,10 +28,18 @@ #define Q65_DECODE_INVPARAMS -1 #define Q65_DECODE_FAILED -2 #define Q65_DECODE_CRCMISMATCH -3 +#define Q65_DECODE_LLHLOW -4 +#define Q65_DECODE_UNDETERR -5 + +// Verify loglikelihood after successful decoding +#define Q65_CHECKLLH +// Max codeword list size in q65_decode_fullaplist +#define Q65_FULLAPLIST_SIZE 64 // maximum number of weights for the fast-fading metric evaluation #define Q65_FASTFADING_MAXWEIGTHS 65 + typedef struct { const qracode *pQraCode; // qra code to be used by the codec float decoderEsNoMetric; // value for which we optimize the decoder metric @@ -72,6 +80,13 @@ int q65_decode(q65_codec_ds *pCodec, const int *pAPMask, const int *pAPSymbols); +int q65_decode_fullaplist(q65_codec_ds *codec, + int *ydec, + int *xdec, + const float *pIntrinsics, + const int *pCodewords, + const int nCodewords); + int q65_esnodb(const q65_codec_ds *pCodec, float *pEsNodB, const int *ydec, @@ -100,4 +115,7 @@ static void _q65_mask(const qracode *pcode, float *ix, const int *mask, const in int _q65_get_alphabet_size(const qracode *pCode); int _q65_get_bits_per_symbol(const qracode *pCode); +// internally used but made public for threshold optimization +int q65_check_llh(float *llh, const int* ydec, const int nN, const int nM, const float *pIntrin); + #endif // _qra65_h