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:
parent
93e1b9e10d
commit
c11eca44bb
95
dump1090.c
95
dump1090.c
|
@ -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;
|
||||
|
@ -568,32 +585,14 @@ static void display_stats(void) {
|
|||
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_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);
|
||||
}
|
||||
|
||||
|
||||
|
|
42
dump1090.h
42
dump1090.h
|
@ -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;
|
||||
|
|
131
mode_s.c
131
mode_s.c
|
@ -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;}
|
||||
}
|
||||
}
|
||||
switch (errors) {
|
||||
case 0: dstats->demodulated0++; break;
|
||||
case 1: dstats->demodulated1++; break;
|
||||
case 2: dstats->demodulated2++; break;
|
||||
default: dstats->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;
|
||||
}
|
||||
}
|
||||
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..
|
||||
|
@ -2194,8 +2174,8 @@ void detectModeS_oversample(uint16_t *m, uint32_t mlen) {
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue