mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-26 22:28:41 -05:00
4de778c4e7
The WSPR message is unpacked into a symbol per byte array which is processed by encoding a whole number of bytes of message, this requires the output array to be bigger than the number of symbols to accommodate extra values that are not part of the message due to rounding up to whole bytes. I.e. 176 (11*8*2) elements to contain the 162 symbols. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6532 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
240 lines
6.8 KiB
C
240 lines
6.8 KiB
C
/*
|
|
This file is part of wsprd.
|
|
|
|
File name: fano.c
|
|
|
|
Description: Soft decision Fano sequential decoder for K=32 r=1/2
|
|
convolutional code.
|
|
|
|
Copyright 1994, Phil Karn, KA9Q
|
|
Minor modifications by Joe Taylor, K1JT
|
|
*/
|
|
|
|
#define LL 1 // Select Layland-Lushbaugh code
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include "fano.h"
|
|
|
|
struct node {
|
|
unsigned long encstate; // Encoder state of next node
|
|
long gamma; // Cumulative metric to this node
|
|
int metrics[4]; // Metrics indexed by all possible tx syms
|
|
int tm[2]; // Sorted metrics for current hypotheses
|
|
int i; // Current branch being tested
|
|
};
|
|
|
|
// Convolutional coding polynomials. All are rate 1/2, K=32
|
|
#ifdef NASA_STANDARD
|
|
/* "NASA standard" code by Massey & Costello
|
|
* Nonsystematic, quick look-in, dmin=11, dfree=23
|
|
* used on Pioneer 10-12, Helios A,B
|
|
*/
|
|
#define POLY1 0xbbef6bb7
|
|
#define POLY2 0xbbef6bb5
|
|
#endif
|
|
|
|
#ifdef MJ
|
|
/* Massey-Johannesson code
|
|
* Nonsystematic, quick look-in, dmin=13, dfree>=23
|
|
* Purported to be more computationally efficient than Massey-Costello
|
|
*/
|
|
#define POLY1 0xb840a20f
|
|
#define POLY2 0xb840a20d
|
|
#endif
|
|
|
|
#ifdef LL
|
|
/* Layland-Lushbaugh code
|
|
* Nonsystematic, non-quick look-in, dmin=?, dfree=?
|
|
*/
|
|
#define POLY1 0xf2d05351
|
|
#define POLY2 0xe4613c47
|
|
#endif
|
|
|
|
/* Convolutionally encode a packet. The input data bytes are read
|
|
* high bit first and the encoded packet is written into 'symbols',
|
|
* one symbol per byte. The first symbol is generated from POLY1,
|
|
* the second from POLY2.
|
|
*
|
|
* Storing only one symbol per byte uses more space, but it is faster
|
|
* and easier than trying to pack them more compactly.
|
|
*/
|
|
int encode(
|
|
unsigned char *symbols, // Output buffer, 2*nbytes*8
|
|
unsigned char *data, // Input buffer, nbytes
|
|
unsigned int nbytes) // Number of bytes in data
|
|
{
|
|
unsigned long encstate;
|
|
int sym;
|
|
int i;
|
|
|
|
encstate = 0;
|
|
while(nbytes-- != 0) {
|
|
for(i=7;i>=0;i--) {
|
|
encstate = (encstate << 1) | ((*data >> i) & 1);
|
|
ENCODE(sym,encstate);
|
|
*symbols++ = sym >> 1;
|
|
*symbols++ = sym & 1;
|
|
}
|
|
data++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Decode packet with the Fano algorithm.
|
|
* Return 0 on success, -1 on timeout
|
|
*/
|
|
int fano(
|
|
unsigned int *metric, // Final path metric (returned value)
|
|
unsigned int *cycles, // Cycle count (returned value)
|
|
unsigned int *maxnp, // Progress before timeout (returned value)
|
|
unsigned char *data, // Decoded output data
|
|
unsigned char *symbols, // Raw deinterleaved input symbols
|
|
unsigned int nbits, // Number of output bits
|
|
int mettab[2][256], // Metric table, [sent sym][rx symbol]
|
|
int delta, // Threshold adjust parameter
|
|
unsigned int maxcycles) // Decoding timeout in cycles per bit
|
|
{
|
|
struct node *nodes; // First node
|
|
struct node *np; // Current node
|
|
struct node *lastnode; // Last node
|
|
struct node *tail; // First node of tail
|
|
int t; // Threshold
|
|
int m0,m1;
|
|
int ngamma;
|
|
unsigned int lsym;
|
|
unsigned int i;
|
|
|
|
if((nodes = (struct node *)malloc((nbits+1)*sizeof(struct node))) == NULL) {
|
|
printf("malloc failed\n");
|
|
return 0;
|
|
}
|
|
lastnode = &nodes[nbits-1];
|
|
tail = &nodes[nbits-31];
|
|
*maxnp = 0;
|
|
|
|
/* Compute all possible branch metrics for each symbol pair
|
|
* This is the only place we actually look at the raw input symbols
|
|
*/
|
|
for(np=nodes;np <= lastnode;np++) {
|
|
np->metrics[0] = mettab[0][symbols[0]] + mettab[0][symbols[1]];
|
|
np->metrics[1] = mettab[0][symbols[0]] + mettab[1][symbols[1]];
|
|
np->metrics[2] = mettab[1][symbols[0]] + mettab[0][symbols[1]];
|
|
np->metrics[3] = mettab[1][symbols[0]] + mettab[1][symbols[1]];
|
|
symbols += 2;
|
|
}
|
|
np = nodes;
|
|
np->encstate = 0;
|
|
|
|
// Compute and sort branch metrics from root node */
|
|
ENCODE(lsym,np->encstate); // 0-branch (LSB is 0)
|
|
m0 = np->metrics[lsym];
|
|
|
|
/* Now do the 1-branch. To save another ENCODE call here and
|
|
* inside the loop, we assume that both polynomials are odd,
|
|
* providing complementary pairs of branch symbols.
|
|
|
|
* This code should be modified if a systematic code were used.
|
|
*/
|
|
|
|
m1 = np->metrics[3^lsym];
|
|
if(m0 > m1) {
|
|
np->tm[0] = m0; // 0-branch has better metric
|
|
np->tm[1] = m1;
|
|
} else {
|
|
np->tm[0] = m1; // 1-branch is better
|
|
np->tm[1] = m0;
|
|
np->encstate++; // Set low bit
|
|
}
|
|
np->i = 0; // Start with best branch
|
|
maxcycles *= nbits;
|
|
np->gamma = t = 0;
|
|
|
|
// Start the Fano decoder
|
|
for(i=1;i <= maxcycles;i++) {
|
|
if((int)(np-nodes) > (int)*maxnp) *maxnp=(int)(np-nodes);
|
|
#ifdef debug
|
|
printf("k=%ld, g=%ld, t=%d, m[%d]=%d, maxnp=%d, encstate=%lx\n",
|
|
np-nodes,np->gamma,t,np->i,np->tm[np->i],*maxnp,np->encstate);
|
|
#endif
|
|
// Look forward */
|
|
ngamma = np->gamma + np->tm[np->i];
|
|
if(ngamma >= t) {
|
|
if(np->gamma < t + delta) { // Node is acceptable
|
|
/* First time we've visited this node;
|
|
* Tighten threshold.
|
|
*
|
|
* This loop could be replaced with
|
|
* t += delta * ((ngamma - t)/delta);
|
|
* but the multiply and divide are slower.
|
|
*/
|
|
while(ngamma >= t + delta) t += delta;
|
|
}
|
|
np[1].gamma = ngamma; // Move forward
|
|
np[1].encstate = np->encstate << 1;
|
|
if( ++np == (lastnode+1) ) {
|
|
break; // Done!
|
|
}
|
|
|
|
/* Compute and sort metrics, starting with the
|
|
* zero branch
|
|
*/
|
|
ENCODE(lsym,np->encstate);
|
|
if(np >= tail) {
|
|
/* The tail must be all zeroes, so don't
|
|
* bother computing the 1-branches here.
|
|
*/
|
|
np->tm[0] = np->metrics[lsym];
|
|
} else {
|
|
m0 = np->metrics[lsym];
|
|
m1 = np->metrics[3^lsym];
|
|
if(m0 > m1) {
|
|
np->tm[0] = m0; // 0-branch is better
|
|
np->tm[1] = m1;
|
|
} else {
|
|
np->tm[0] = m1; // 1-branch is better
|
|
np->tm[1] = m0;
|
|
np->encstate++; // Set low bit
|
|
}
|
|
}
|
|
np->i = 0; // Start with best branch
|
|
continue;
|
|
}
|
|
// Threshold violated, can't go forward
|
|
for(;;) { // Look backward
|
|
if(np == nodes || np[-1].gamma < t) {
|
|
/* Can't back up either.
|
|
* Relax threshold and and look
|
|
* forward again to better branch.
|
|
*/
|
|
t -= delta;
|
|
if(np->i != 0) {
|
|
np->i = 0;
|
|
np->encstate ^= 1;
|
|
}
|
|
break;
|
|
}
|
|
// Back up
|
|
if(--np < tail && np->i != 1) {
|
|
np->i++; // Search next best branch
|
|
np->encstate ^= 1;
|
|
break;
|
|
} // else keep looking back
|
|
}
|
|
}
|
|
*metric = np->gamma; // Return the final path metric
|
|
|
|
// Copy decoded data to user's buffer
|
|
nbits >>= 3;
|
|
np = &nodes[7];
|
|
while(nbits-- != 0) {
|
|
*data++ = np->encstate;
|
|
np += 8;
|
|
}
|
|
*cycles = i+1;
|
|
|
|
free(nodes);
|
|
if(i >= maxcycles) return -1; // Decoder timed out
|
|
return 0; // Successful completion
|
|
}
|