mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-11-03 13:30:52 -05: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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user