mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-03-23 20:48:33 -04:00
added likelihood check for better false rejection - added function q65_decode_fullaplist for full-ap decoding of a list of codewords
This commit is contained in:
parent
d26acd048c
commit
4bd7fcb4a1
@ -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<nN;k++) {
|
||||
t+=logf(pIntrin[ydec[k]]);
|
||||
pIntrin+=nM;
|
||||
}
|
||||
|
||||
if (llh!=NULL)
|
||||
*llh = t;
|
||||
|
||||
return (t>=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;k<nCodewords;k++) {
|
||||
// compute and check this codeword loglikelihood
|
||||
if (q65_check_llh(&llh,pCw, nN, nM, pIntrinsics)==1) // larger than threshold
|
||||
// select the codeword with max logll
|
||||
if (llh>maxllh) {
|
||||
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 -------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user