Try all phases if --oversample --phase-enhance is on.

If we demodulate a message in 2.4MHz mode and it has a bad, uncorrectable CRC,
and --phase-enhance is on, then retry with the other possible phases until
we get a good CRC or run out of phases to try.

This is very expensive in AGC mode (lots of candidates that are not real
messages) but relatively cheap otherwise. It yields another 10% messages.

Also factor out some common stats code to avoid lots more copy/paste.
This commit is contained in:
Oliver Jowett 2014-09-30 17:02:22 +01:00
parent 93e1b9e10d
commit c11eca44bb
3 changed files with 133 additions and 143 deletions

View file

@ -494,6 +494,44 @@ void showCopyright(void) {
#endif
static void display_demod_stats(const char *prefix, struct demod_stats *dstats) {
int j;
printf("%d %sdemodulated with 0 errors\n", dstats->demodulated0, prefix);
printf("%d %sdemodulated with 1 error\n", dstats->demodulated1, prefix);
printf("%d %sdemodulated with 2 errors\n", dstats->demodulated2, prefix);
printf("%d %sdemodulated with > 2 errors\n", dstats->demodulated3, prefix);
printf("%d %swith good crc\n", dstats->goodcrc, prefix);
for (j = 0; j < MODES_MAX_PHASE_STATS; ++j)
if (dstats->goodcrc_byphase[j] > 0)
printf(" %d %swith phase offset %d\n", dstats->goodcrc_byphase[j], prefix, j);
printf("%d %swith bad crc\n", dstats->badcrc, prefix);
printf("%d %serrors corrected\n", dstats->fixed, prefix);
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf(" %d %swith %d bit %s\n", dstats->bit_fix[j], prefix, j+1, (j==0)?"error":"errors");
}
}
static void reset_demod_stats(struct demod_stats *dstats) {
int j;
dstats->demodulated0 =
dstats->demodulated1 =
dstats->demodulated2 =
dstats->goodcrc =
dstats->badcrc =
dstats->fixed = 0;
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
dstats->bit_fix[j] = 0;
}
for (j = 0; j < MODES_MAX_PHASE_STATS; j++) {
dstats->goodcrc_byphase[j] = 0;
}
}
static void display_stats(void) {
int j;
time_t now = time(NULL);
@ -523,37 +561,16 @@ static void display_stats(void) {
printf(" %d with phase offset %d\n", Modes.stat_preamble_phase[j], j);
printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected);
printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected);
printf("%d demodulated with 0 errors\n", Modes.stat_demodulated0);
printf("%d demodulated with 1 error\n", Modes.stat_demodulated1);
printf("%d demodulated with 2 errors\n", Modes.stat_demodulated2);
printf("%d demodulated with > 2 errors\n", Modes.stat_demodulated3);
printf("%d with good crc\n", Modes.stat_goodcrc);
for (j = 0; j < MODES_MAX_PHASE_STATS; ++j)
if (Modes.stat_goodcrc_phase[j] > 0)
printf(" %d with phase offset %d\n", Modes.stat_goodcrc_phase[j], j);
printf("%d with bad crc\n", Modes.stat_badcrc);
printf("%d errors corrected\n", Modes.stat_fixed);
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors");
}
display_demod_stats("", &Modes.stat_demod);
if (Modes.phase_enhance) {
printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase);
printf("%d phase enhanced demodulated with 0 errors\n", Modes.stat_ph_demodulated0);
printf("%d phase enhanced demodulated with 1 error\n", Modes.stat_ph_demodulated1);
printf("%d phase enhanced demodulated with 2 errors\n", Modes.stat_ph_demodulated2);
printf("%d phase enhanced demodulated with > 2 errors\n", Modes.stat_ph_demodulated3);
printf("%d phase enhanced with good crc\n", Modes.stat_ph_goodcrc);
printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc);
printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed);
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf(" %d with %d bit %s\n", Modes.stat_ph_bit_fix[j], j+1, (j==0)?"error":"errors");
}
display_demod_stats("phase enhanced ", &Modes.stat_demod_phasecorrected);
}
printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed);
printf("%d total usable messages\n",
Modes.stat_demod.goodcrc + Modes.stat_demod_phasecorrected.goodcrc +
Modes.stat_demod.fixed + Modes.stat_demod_phasecorrected.fixed);
fflush(stdout);
Modes.stat_cputime.tv_sec = 0;
@ -567,33 +584,15 @@ static void display_stats(void) {
Modes.stat_preamble_not_quiet =
Modes.stat_valid_preamble =
Modes.stat_DF_Len_Corrected =
Modes.stat_DF_Type_Corrected =
Modes.stat_demodulated0 =
Modes.stat_demodulated1 =
Modes.stat_demodulated2 =
Modes.stat_demodulated3 =
Modes.stat_goodcrc =
Modes.stat_badcrc =
Modes.stat_fixed = 0;
Modes.stat_out_of_phase =
Modes.stat_ph_demodulated0 =
Modes.stat_ph_demodulated1 =
Modes.stat_ph_demodulated2 =
Modes.stat_ph_demodulated3 =
Modes.stat_ph_goodcrc =
Modes.stat_ph_badcrc =
Modes.stat_ph_fixed = 0;
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
Modes.stat_ph_bit_fix[j] = 0;
Modes.stat_bit_fix[j] = 0;
}
Modes.stat_DF_Type_Corrected =
Modes.stat_out_of_phase = 0;
for (j = 0; j < MODES_MAX_PHASE_STATS; j++) {
Modes.stat_preamble_phase[j] = 0;
Modes.stat_goodcrc_phase[j] = 0;
}
reset_demod_stats(&Modes.stat_demod);
reset_demod_stats(&Modes.stat_demod_phasecorrected);
}

View file

@ -96,6 +96,8 @@
// When changing, change also fixBitErrors() and modesInitErrorTable() !!
#define MODES_MAX_BITERRORS 2 // Global max for fixable bit erros
#define MODES_MAX_PHASE_STATS 10
#define MODEAC_MSG_SAMPLES (25 * 2) // include up to the SPI bit
#define MODEAC_MSG_BYTES 2
#define MODEAC_MSG_SQUELCH_LEVEL 0x07FF // Average signal strength limit
@ -246,6 +248,22 @@ struct stDF {
unsigned char msg[MODES_LONG_MSG_BYTES]; // the binary
} tDF;
// Common stats for non-phase-corrected vs phase-corrected cases
struct demod_stats {
unsigned int demodulated0;
unsigned int demodulated1;
unsigned int demodulated2;
unsigned int demodulated3;
unsigned int goodcrc;
unsigned int goodcrc_byphase[MODES_MAX_PHASE_STATS];
unsigned int badcrc;
unsigned int fixed;
// Histogram of fixed bit errors: index 0 for single bit erros,
// index 1 for double bit errors etc.
unsigned int bit_fix[MODES_MAX_BITERRORS];
};
// Program global state
struct { // Internal state
pthread_t reader_thread;
@ -348,39 +366,19 @@ struct { // Internal state
struct stDF *pDF; // Pointer to DF list
// Statistics
#define MODES_MAX_PHASE_STATS 12
unsigned int stat_preamble_no_correlation;
unsigned int stat_preamble_not_quiet;
unsigned int stat_valid_preamble;
unsigned int stat_preamble_phase[MODES_MAX_PHASE_STATS];
unsigned int stat_demodulated0;
unsigned int stat_demodulated1;
unsigned int stat_demodulated2;
unsigned int stat_demodulated3;
unsigned int stat_goodcrc;
unsigned int stat_goodcrc_phase[MODES_MAX_PHASE_STATS];
unsigned int stat_badcrc;
unsigned int stat_fixed;
// Histogram of fixed bit errors: index 0 for single bit erros,
// index 1 for double bit errors etc.
unsigned int stat_bit_fix[MODES_MAX_BITERRORS];
struct demod_stats stat_demod;
struct demod_stats stat_demod_phasecorrected;
unsigned int stat_http_requests;
unsigned int stat_sbs_connections;
unsigned int stat_raw_connections;
unsigned int stat_beast_connections;
unsigned int stat_out_of_phase;
unsigned int stat_ph_demodulated0;
unsigned int stat_ph_demodulated1;
unsigned int stat_ph_demodulated2;
unsigned int stat_ph_demodulated3;
unsigned int stat_ph_goodcrc;
unsigned int stat_ph_badcrc;
unsigned int stat_ph_fixed;
// Histogram of fixed bit errors: index 0 for single bit erros,
// index 1 for double bit errors etc.
unsigned int stat_ph_bit_fix[MODES_MAX_BITERRORS];
unsigned int stat_DF_Len_Corrected;
unsigned int stat_DF_Type_Corrected;

137
mode_s.c
View file

@ -1818,49 +1818,25 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
// Update statistics
if (Modes.stats) {
if (mm.crcok || use_correction || mm.correctedbits) {
struct demod_stats *dstats = (use_correction ? &Modes.stat_demod_phasecorrected : &Modes.stat_demod);
if (use_correction) {
switch (errors) {
case 0: {Modes.stat_ph_demodulated0++; break;}
case 1: {Modes.stat_ph_demodulated1++; break;}
case 2: {Modes.stat_ph_demodulated2++; break;}
default:{Modes.stat_ph_demodulated3++; break;}
}
} else {
switch (errors) {
case 0: {Modes.stat_demodulated0++; break;}
case 1: {Modes.stat_demodulated1++; break;}
case 2: {Modes.stat_demodulated2++; break;}
default:{Modes.stat_demodulated3++; break;}
}
}
if (mm.correctedbits == 0) {
if (use_correction) {
if (mm.crcok) {Modes.stat_ph_goodcrc++;}
else {Modes.stat_ph_badcrc++;}
} else {
if (mm.crcok) {Modes.stat_goodcrc++;}
else {Modes.stat_badcrc++;}
}
} else if (use_correction) {
Modes.stat_ph_badcrc++;
Modes.stat_ph_fixed++;
if ( (mm.correctedbits)
&& (mm.correctedbits <= MODES_MAX_BITERRORS) ) {
Modes.stat_ph_bit_fix[mm.correctedbits-1] += 1;
}
} else {
Modes.stat_badcrc++;
Modes.stat_fixed++;
if ( (mm.correctedbits)
&& (mm.correctedbits <= MODES_MAX_BITERRORS) ) {
Modes.stat_bit_fix[mm.correctedbits-1] += 1;
}
}
switch (errors) {
case 0: dstats->demodulated0++; break;
case 1: dstats->demodulated1++; break;
case 2: dstats->demodulated2++; break;
default: dstats->demodulated3++; break;
}
if (mm.crcok) {
dstats->goodcrc++;
dstats->goodcrc_byphase[0]++;
} else if (mm.correctedbits > 0) {
dstats->badcrc++;
dstats->fixed++;
if (mm.correctedbits <= MODES_MAX_BITERRORS)
dstats->bit_fix[mm.correctedbits-1] += 1;
} else {
dstats->badcrc++;
}
}
@ -1878,7 +1854,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
}
// Skip this message if we are sure it's fine
if (mm.crcok) {
if (mm.crcok || mm.correctedbits) {
j += (MODES_PREAMBLE_US+msglen)*2 - 1;
}
@ -1972,19 +1948,19 @@ static inline int slice_phase4(uint16_t *m) {
}
static inline int correlate_phase0(uint16_t *m) {
return slice_phase0(m) * 3;
return slice_phase0(m) * 26;
}
static inline int correlate_phase1(uint16_t *m) {
return slice_phase1(m) * 4;
return slice_phase1(m) * 38;
}
static inline int correlate_phase2(uint16_t *m) {
return slice_phase2(m) * 4;
return slice_phase2(m) * 38;
}
static inline int correlate_phase3(uint16_t *m) {
return slice_phase3(m) * 3;
return slice_phase3(m) * 26;
}
static inline int correlate_phase4(uint16_t *m) {
return slice_phase4(m) * 2;
return slice_phase4(m) * 19;
}
//
@ -2092,6 +2068,7 @@ void detectModeS_oversample(uint16_t *m, uint32_t mlen) {
uint8_t theByte, theErrs;
uint32_t sigLevel, noiseLevel;
uint16_t snr;
int try_phase;
// Look for a message starting at around sample 0 with phase offset 3..7
@ -2183,6 +2160,9 @@ void detectModeS_oversample(uint16_t *m, uint32_t mlen) {
Modes.stat_valid_preamble++;
Modes.stat_preamble_phase[initial_phase%MODES_MAX_PHASE_STATS]++;
try_phase = initial_phase;
retry:
// Rather than clear the whole mm structure, just clear the parts which are required. The clear
// is required for every possible preamble, and we don't want to be memset-ing the whole
// modesMessage structure if we don't have to..
@ -2192,10 +2172,10 @@ void detectModeS_oversample(uint16_t *m, uint32_t mlen) {
// Decode all the next 112 bits, regardless of the actual message
// size. We'll check the actual message type later
pMsg = &msg[0];
pPtr = &m[j+19] + (initial_phase/5);
phase = initial_phase % 5;
pPtr = &m[j+19] + (try_phase/5);
phase = try_phase % 5;
theByte = 0;
theErrs = 0; errorsTy = 0;
errors = 0; errors56 = 0;
@ -2369,46 +2349,59 @@ void detectModeS_oversample(uint16_t *m, uint32_t mlen) {
// && ((2 * snr) > (int) (MODES_MSG_SQUELCH_DB * 10))
&& (errors <= MODES_MSG_ENCODER_ERRS) ) {
// Set initial mm structure details
mm.timestampMsg = Modes.timestampBlk + (j*5) + initial_phase;
mm.timestampMsg = Modes.timestampBlk + (j*5) + try_phase;
mm.signalLevel = (snr > 255 ? 255 : (uint8_t)snr);
mm.phase_corrected = 0;
//dumpRawMessage("decoded with oversampling", msg, m, j);
mm.phase_corrected = (initial_phase != try_phase);
// Decode the received message
decodeModesMessage(&mm, msg);
// Update statistics
if (Modes.stats) {
struct demod_stats *dstats = (mm.phase_corrected ? &Modes.stat_demod_phasecorrected : &Modes.stat_demod);
switch (errors) {
case 0: {Modes.stat_demodulated0++; break;}
case 1: {Modes.stat_demodulated1++; break;}
case 2: {Modes.stat_demodulated2++; break;}
default:{Modes.stat_demodulated3++; break;}
case 0: dstats->demodulated0++; break;
case 1: dstats->demodulated1++; break;
case 2: dstats->demodulated2++; break;
default: dstats->demodulated3++; break;
}
if (mm.correctedbits == 0) {
if (mm.crcok) {
Modes.stat_goodcrc++;
Modes.stat_goodcrc_phase[initial_phase%MODES_MAX_PHASE_STATS]++;
} else {Modes.stat_badcrc++;}
if (mm.crcok) {
dstats->goodcrc++;
dstats->goodcrc_byphase[try_phase%MODES_MAX_PHASE_STATS]++;
} else if (mm.correctedbits > 0) {
dstats->badcrc++;
dstats->fixed++;
if (mm.correctedbits <= MODES_MAX_BITERRORS)
dstats->bit_fix[mm.correctedbits-1] += 1;
} else {
Modes.stat_badcrc++;
Modes.stat_fixed++;
if ( (mm.correctedbits)
&& (mm.correctedbits <= MODES_MAX_BITERRORS) ) {
Modes.stat_bit_fix[mm.correctedbits-1] += 1;
}
dstats->badcrc++;
}
}
// Skip this message if we are sure it's fine
if (mm.crcok) {
if (mm.crcok || mm.correctedbits) {
j += (16+msglen)*6/5 - 1;
}
// Pass data to the next layer
useModesMessage(&mm);
// Only try with different phases if we mostly demodulated OK,
// but the CRC failed. This seems to catch most of the cases
// where trying different phases actually helps, and is much
// cheaper than trying it on every single candidate that passes
// peak detection
if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits) {
if (try_phase == initial_phase)
++Modes.stat_out_of_phase;
try_phase++;
if (try_phase == 9)
try_phase = 4;
if (try_phase != initial_phase)
goto retry;
}
}
}