Hamming [8,4] 2-bit-errors -> soft decision

pull/27/head
Zilog80 2020-04-27 23:35:45 +02:00
rodzic 441317f5dc
commit 438590bc6f
3 zmienionych plików z 268 dodań i 94 usunięć

Wyświetl plik

@ -835,7 +835,7 @@ int read_slbit(dsp_t *dsp, int *bit, int inv, int ofs, int pos, float l, int spi
}
sample -= dc;
if ( l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum -= sample;
if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum -= sample;
dsp->sc++;
} while (dsp->sc < bg); // n < dsp->sps
@ -853,9 +853,9 @@ int read_slbit(dsp_t *dsp, int *bit, int inv, int ofs, int pos, float l, int spi
+dsp->bufs[(dsp->sample_out-dsp->buffered+1 + ofs + dsp->M) % dsp->M]);
sample = avg + scale*(sample - avg); // spikes
}
sample -= dc;
sample -= dc;
if ( l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum += sample;
if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum += sample;
dsp->sc++;
} while (dsp->sc < bg); // n < dsp->sps
@ -867,6 +867,81 @@ int read_slbit(dsp_t *dsp, int *bit, int inv, int ofs, int pos, float l, int spi
return 0;
}
int read_softbit(dsp_t *dsp, hsbit_t *shb, int inv, int ofs, int pos, float l, int spike) {
// symlen==2: manchester2 10->0,01->1: 2.bit
float sample;
float avg;
float ths = 0.5, scale = 0.27;
double sum = 0.0;
double mid;
//double l = 1.0;
double bg = pos*dsp->symlen*dsp->sps;
double dc = 0.0;
ui8_t bit = 0;
if (dsp->opt_dc && dsp->opt_iq < 2) dc = dsp->dc;
if (pos == 0) {
bg = 0;
dsp->sc = 0;
}
if (dsp->symlen == 2) {
mid = bg + (dsp->sps-1)/2.0;
bg += dsp->sps;
do {
if (dsp->buffered > 0) dsp->buffered -= 1;
else if (f32buf_sample(dsp, inv) == EOF) return EOF;
sample = dsp->bufs[(dsp->sample_out-dsp->buffered + ofs + dsp->M) % dsp->M];
if (spike && fabs(sample - avg) > ths) {
avg = 0.5*(dsp->bufs[(dsp->sample_out-dsp->buffered-1 + ofs + dsp->M) % dsp->M]
+dsp->bufs[(dsp->sample_out-dsp->buffered+1 + ofs + dsp->M) % dsp->M]);
sample = avg + scale*(sample - avg); // spikes
}
sample -= dc;
if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum -= sample;
dsp->sc++;
} while (dsp->sc < bg); // n < dsp->sps
}
mid = bg + (dsp->sps-1)/2.0;
bg += dsp->sps;
do {
if (dsp->buffered > 0) dsp->buffered -= 1;
else if (f32buf_sample(dsp, inv) == EOF) return EOF;
sample = dsp->bufs[(dsp->sample_out-dsp->buffered + ofs + dsp->M) % dsp->M];
if (spike && fabs(sample - avg) > ths) {
avg = 0.5*(dsp->bufs[(dsp->sample_out-dsp->buffered-1 + ofs + dsp->M) % dsp->M]
+dsp->bufs[(dsp->sample_out-dsp->buffered+1 + ofs + dsp->M) % dsp->M]);
sample = avg + scale*(sample - avg); // spikes
}
sample -= dc;
if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum += sample;
dsp->sc++;
} while (dsp->sc < bg); // n < dsp->sps
if (sum >= 0) bit = 1;
else bit = 0;
shb->hb = bit;
shb->sb = (float)sum;
return 0;
}
/* -------------------------------------------------------------------------- */
#define IF_SAMPLE_RATE 48000

Wyświetl plik

@ -138,10 +138,17 @@ typedef struct {
} pcm_t;
typedef struct {
ui8_t hb;
float sb;
} hsbit_t;
float read_wav_header(pcm_t *, FILE *);
int f32buf_sample(dsp_t *, int);
int read_slbit(dsp_t *, int*, int, int, int, float, int);
int read_softbit(dsp_t *, hsbit_t *, int, int, int, float, int );
int init_buffers(dsp_t *);
int free_buffers(dsp_t *);

Wyświetl plik

@ -68,7 +68,7 @@ typedef struct {
float status[2];
float _frmcnt;
char sonde_id[16]; // "ID__:xxxxxxxx\0\0"
char frame_bits[BITFRAME_LEN+4];
hsbit_t frame[BITFRAME_LEN+4]; // char frame_bits[BITFRAME_LEN+4];
char dat_str[9][13+1];
sn_t snc;
pcksts_t pck[9];
@ -98,6 +98,15 @@ static char dfm_header[] = "0100010111001111";
#define DAT2 (16+160) // 104 bit
// frame: 280 bit
static ui8_t G[8][4] = // Generator
{{ 1, 0, 0, 0},
{ 0, 1, 0, 0},
{ 0, 0, 1, 0},
{ 0, 0, 0, 1},
{ 0, 1, 1, 1},
{ 1, 0, 1, 1},
{ 1, 1, 0, 1},
{ 1, 1, 1, 0}};
static ui8_t H[4][8] = // Parity-Check
{{ 0, 1, 1, 1, 1, 0, 0, 0},
{ 1, 0, 1, 1, 0, 1, 0, 0},
@ -105,6 +114,28 @@ static ui8_t H[4][8] = // Parity-Check
{ 1, 1, 1, 0, 0, 0, 0, 1}};
static ui8_t He[8] = { 0x7, 0xB, 0xD, 0xE, 0x8, 0x4, 0x2, 0x1}; // Spalten von H:
// 1-bit-error-Syndrome
static ui8_t codewords[16][8]; // (valid) Hamming codewords
static int nib4bits(ui8_t nib, ui8_t *bits) { // big endian
int j;
nib &= 0xF;
for (j = 0; j < 4; j++) {
bits[j] = (nib>>(3-j)) & 0x1;
}
return 0;
}
static int gencode(ui8_t msg[4], ui8_t code[8]) {
int i, j; // Gm=c
for (i = 0; i < 8; i++) {
code[i] = 0;
for (j = 0; j < 4; j++) {
code[i] ^= G[i][j] & msg[j];
}
}
return 0;
}
static ui32_t bits2val(ui8_t *bits, int len) { // big endian
int j;
@ -117,18 +148,16 @@ static ui32_t bits2val(ui8_t *bits, int len) { // big endian
return val;
}
static void deinterleave(char *str, int L, ui8_t *block) {
static void deinterleave(hsbit_t *str, int L, hsbit_t *block) {
int i, j;
for (j = 0; j < B; j++) { // L = 7, 13
for (i = 0; i < L; i++) {
if (str[L*j+i] >= 0x30 && str[L*j+i] <= 0x31) {
block[B*i+j] = str[L*j+i] - 0x30; // ASCII -> bit
}
block[B*i+j] = str[L*j+i];
}
}
}
static int check(ui8_t code[8]) {
static int check(int opt_ecc, hsbit_t code[8]) {
int i, j; // Bei Demodulierung durch Nulldurchgaenge, wenn durch Fehler ausser Takt,
ui32_t synval = 0; // verschieben sich die bits. Fuer Hamming-Decode waere es besser,
ui8_t syndrom[4]; // sync zu Beginn mit Header und dann Takt beibehalten fuer decision.
@ -137,7 +166,7 @@ static int check(ui8_t code[8]) {
for (i = 0; i < 4; i++) { // S = 4
syndrom[i] = 0;
for (j = 0; j < 8; j++) { // B = 8
syndrom[i] ^= H[i][j] & code[j];
syndrom[i] ^= H[i][j] & code[j].hb;
}
}
synval = bits2val(syndrom, 4);
@ -151,22 +180,64 @@ static int check(ui8_t code[8]) {
}
}
else ret = 0;
if (ret > 0) code[ret-1] ^= 0x1;
if (ret > 0) code[ret-1].hb ^= 0x1; // d=1: 1-bit-error
else if (ret < 0 && opt_ecc == 2) { // d=2: 2-bit-error: soft decision
// Hamming [8,4]
// 256 words:
// 16 codewords
// 16*8=128 1-error words (dist=1)
// 16*7=112 2-error words (dist=2)
// each 2-error word has 4 codewords w/ dist=2
// choose best "correlation"
int n;
int maxn = -1;
int d = 0;
float sum = 0.0;
float maxsum = 0.0;
for (i = 0; i < 8; i++) {
sum += (2*code[i].hb-1) * code[i].sb;
}
for (n = 0; n < 16; n++) {
d = 0;
sum = 0.0;
for (i = 0; i < 8; i++) { // d(a,b) = sum_i a[i]^b[i]
if (code[i].hb != codewords[n][i]) d++;
}
if (d == 2) { // dist=2
// softbits correlation:
// - interleaving
// + no pulse-shaping -> sum
for (i = 0; i < 8; i++) {
sum += (2*codewords[n][i]-1) * code[i].sb;
}
if (sum*sum >= maxsum*maxsum) {
maxsum = sum;
maxn = n;
}
}
}
if (maxn >= 0) {
for (i = 0; i < 8; i++) {
if (code[i].hb = codewords[maxn][i]);
}
}
}
return ret;
}
static int hamming(int opt_ecc, ui8_t *ham, int L, ui8_t *sym) {
static int hamming(int opt_ecc, hsbit_t *ham, int L, ui8_t *sym) {
int i, j;
int ecc = 0, ret = 0; // L = 7, 13
for (i = 0; i < L; i++) { // L * 2 nibble (data+parity)
if (opt_ecc) {
ecc = check(ham+B*i);
ecc = check(opt_ecc, ham+B*i);
if (ecc > 0) ret |= (1<<i);
if (ecc < 0) ret |= ecc; // -1
}
for (j = 0; j < S; j++) { // systematic: bits 0..S-1 data
sym[S*i+j] = ham[B*i+j];
sym[S*i+j] = ham[B*i+j].hb;
}
}
return ret;
@ -691,17 +762,17 @@ static int print_frame(gpx_t *gpx) {
int ret0, ret1, ret2;
int ret = 0;
ui8_t hamming_conf[ 7*B]; // 7*8=56
ui8_t hamming_dat1[13*B]; // 13*8=104
ui8_t hamming_dat2[13*B];
hsbit_t hamming_conf[ 7*B]; // 7*8=56
hsbit_t hamming_dat1[13*B]; // 13*8=104
hsbit_t hamming_dat2[13*B];
ui8_t block_conf[ 7*S]; // 7*4=28
ui8_t block_dat1[13*S]; // 13*4=52
ui8_t block_dat2[13*S];
deinterleave(gpx->frame_bits+CONF, 7, hamming_conf);
deinterleave(gpx->frame_bits+DAT1, 13, hamming_dat1);
deinterleave(gpx->frame_bits+DAT2, 13, hamming_dat2);
deinterleave(gpx->frame+CONF, 7, hamming_conf);
deinterleave(gpx->frame+DAT1, 13, hamming_dat1);
deinterleave(gpx->frame+DAT2, 13, hamming_dat2);
ret0 = hamming(gpx->option.ecc, hamming_conf, 7, block_conf);
ret1 = hamming(gpx->option.ecc, hamming_dat1, 13, block_dat1);
@ -750,14 +821,14 @@ static int print_frame(gpx_t *gpx) {
}
else if (gpx->option.ecc) {
if (ret0 == 0 || ret0 > 0) {
if (ret0 == 0 || ret0 > 0 || gpx->option.ecc == 2) {
conf_out(gpx, block_conf, ret0);
}
if (ret1 == 0 || ret1 > 0) {
if (ret1 == 0 || ret1 > 0 || gpx->option.ecc == 2) {
frid = dat_out(gpx, block_dat1, ret1);
if (frid == 8) print_gpx(gpx);
}
if (ret2 == 0 || ret2 > 0) {
if (ret2 == 0 || ret2 > 0 || gpx->option.ecc == 2) {
frid = dat_out(gpx, block_dat2, ret2);
if (frid == 8) print_gpx(gpx);
}
@ -866,7 +937,7 @@ int main(int argc, char **argv) {
int ret = 0;
int k;
int bit;
hsbit_t hsbit;
int bitpos = 0;
int bitQ;
int pos;
@ -926,7 +997,8 @@ int main(int argc, char **argv) {
else if ( (strcmp(*argv, "-i") == 0) || (strcmp(*argv, "--invert") == 0) ) {
option_inv = 0x1;
}
else if ( (strcmp(*argv, "--ecc") == 0) ) { option_ecc = 1; }
else if ( (strcmp(*argv, "--ecc" ) == 0) ) { option_ecc = 1; }
else if ( (strcmp(*argv, "--ecc2") == 0) ) { option_ecc = 2; }
else if ( (strcmp(*argv, "--ptu") == 0) ) {
option_ptu = 1;
//gpx.ptu_out = 1; // force ptu (non PS-15)
@ -1002,9 +1074,26 @@ int main(int argc, char **argv) {
}
if (!wavloaded) fp = stdin;
if ( option_dist || option_json ) option_ecc = 1;
if (option_ecc)
{
ui8_t nib, msg[4], code[8];
for (nib = 0; nib < 16; nib++) {
nib4bits(nib, msg);
gencode(msg, code);
for (k = 0; k < 8; k++) codewords[nib][k] = code[k];
}
}
// init gpx
strcpy(gpx.frame_bits, dfm_header); //, sizeof(dfm_header);
//strcpy(gpx.frame_bits, dfm_header); //, sizeof(dfm_header);
for (k = 0; k < strlen(dfm_header); k++) {
gpx.frame[k].hb = dfm_header[k] & 1;
gpx.frame[k].sb = 2*gpx.frame[k].hb - 1;
}
for (k = 0; k < 9; k++) gpx.pck[k].ec = -1; // init ecc-status
gpx.option.inv = option_inv;
@ -1093,89 +1182,92 @@ int main(int argc, char **argv) {
bitofs += shift;
while ( 1 )
while ( 1 )
{
if (option_bin) { // aka find_binrawhead()
header_found = find_binhead(fp, &hdb, &_mv); // symbols or bits?
hdrcnt += nfrms;
}
else { // FM-audio:
header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0
_mv = dsp.mv;
}
if (header_found == EOF) break;
// mv == correlation score
if (_mv *(0.5-gpx.option.inv) < 0) {
if (gpx.option.aut == 0) header_found = 0;
else gpx.option.inv ^= 0x1;
}
if (header_found)
{
if (option_bin) { // aka find_binrawhead()
header_found = find_binhead(fp, &hdb, &_mv); // symbols or bits?
hdrcnt += nfrms;
}
else { // FM-audio:
header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0
_mv = dsp.mv;
}
if (header_found == EOF) break;
bitpos = 0;
pos = headerlen;
pos /= 2;
// mv == correlation score
if (_mv *(0.5-gpx.option.inv) < 0) {
if (gpx.option.aut == 0) header_found = 0;
else gpx.option.inv ^= 0x1;
}
//if (fabs(mv) > 0.85) nfrms = 8; else nfrms = 4; // test OK/KO/NO count
if (header_found)
{
bitpos = 0;
pos = headerlen;
pos /= 2;
//if (fabs(mv) > 0.85) nfrms = 8; else nfrms = 4; // test OK/KO/NO count
frm = 0;
while ( frm < nfrms ) { // nfrms=1,2,4,8
frm = 0;
while ( frm < nfrms ) { // nfrms=1,2,4,8
if (option_bin) {
gpx._frmcnt = hdrcnt + frm;
}
else {
gpx._frmcnt = dsp.mv_pos/(2.0*dsp.sps*BITFRAME_LEN) + frm;
}
while ( pos < BITFRAME_LEN )
{
if (option_bin) {
gpx._frmcnt = hdrcnt + frm;
// symbols or bits?
// manchester1 1->10,0->01: 1.bit (DFM-06)
// manchester2 0->10,1->01: 2.bit (DFM-09)
bitQ = fgetc(fp);
if (bitQ != EOF) {
hsbit.hb = bitQ & 0x1;
bitQ = fgetc(fp); // check: rbit0^rbit1=1 (Manchester)
if (bitQ != EOF) hsbit.hb = bitQ & 0x1; // 2.bit (DFM-09)
hsbit.sb = 2*hsbit.hb - 1;
}
}
else {
gpx._frmcnt = dsp.mv_pos/(2.0*dsp.sps*BITFRAME_LEN) + frm;
}
while ( pos < BITFRAME_LEN )
{
if (option_bin) {
// symbols or bits?
// manchester1 1->10,0->01: 1.bit (DFM-06)
// manchester2 0->10,1->01: 2.bit (DFM-09)
bitQ = fgetc(fp);
if (bitQ != EOF) {
bit = bitQ & 0x1;
bitQ = fgetc(fp); // check: rbit0^rbit1=1 (Manchester)
if (bitQ != EOF) bit = bitQ & 0x1; // 2.bit (DFM-09)
}
if (option_iq >= 2) {
float bl = -1;
if (option_iq > 2) bl = 4.0;
bitQ = read_softbit(&dsp, &hsbit, 0/*gpx.option.inv*/, bitofs, bitpos, bl, 0);
}
else {
if (option_iq >= 2) {
float bl = -1;
if (option_iq > 2) bl = 4.0;
bitQ = read_slbit(&dsp, &bit, 0/*gpx.option.inv*/, bitofs, bitpos, bl, 0);
}
else {
bitQ = read_slbit(&dsp, &bit, 0/*gpx.option.inv*/, bitofs, bitpos, -1, spike);
}
bitQ = read_softbit(&dsp, &hsbit, 0/*gpx.option.inv*/, bitofs, bitpos, -1, spike);
}
if ( bitQ == EOF ) { frm = nfrms; break; } // liest 2x EOF
if (gpx.option.inv) bit ^= 1;
gpx.frame_bits[pos] = 0x30 + bit;
pos++;
bitpos += 1;
}
gpx.frame_bits[pos] = '\0';
if ( bitQ == EOF ) { frm = nfrms; break; } // liest 2x EOF
ret = print_frame(&gpx);
if (pos < BITFRAME_LEN) break;
pos = 0;
frm += 1;
//if (ret < 0) frms += 1;
if (gpx.option.inv) {
hsbit.hb ^= 1;
hsbit.sb = -hsbit.sb;
}
gpx.frame[pos] = hsbit;
pos++;
bitpos += 1;
}
ret = print_frame(&gpx);
if (pos < BITFRAME_LEN) break;
pos = 0;
frm += 1;
//if (ret < 0) frms += 1;
}
header_found = 0;
pos = headerlen;
}
if (!option_bin) free_buffers(&dsp);
else {
if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; }
}
header_found = 0;
pos = headerlen;
}
if (!option_bin) free_buffers(&dsp);
else {
if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; }
}
fclose(fp);