diff --git a/adaptive.c b/adaptive.c index 51c8d7e..cb609e6 100644 --- a/adaptive.c +++ b/adaptive.c @@ -34,28 +34,31 @@ static float adaptive_gain_down_db; // block handling // -static unsigned adaptive_block_remaining; -static unsigned adaptive_block_size; +static unsigned adaptive_block_remaining; // samples in each block +static unsigned adaptive_block_size; // samples remaining in the current block void adaptive_init(); void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded); static void adaptive_update_single(uint16_t *buf, unsigned length, struct modesMessage *decoded); static void adaptive_end_of_block(); +static void adaptive_control_update(); // // burst handling // -static unsigned adaptive_burst_window_size; -static unsigned adaptive_burst_window_remaining; -static unsigned adaptive_burst_window_counter; -static unsigned adaptive_burst_runlength; -static unsigned adaptive_burst_block_counter; -static unsigned adaptive_burst_block_loud_decodes; -static double adaptive_burst_smoothed; -static double adaptive_burst_loud_decodes_smoothed; -static unsigned adaptive_burst_change_delay; -static double adaptive_burst_loud_threshold; +static unsigned adaptive_burst_window_size; // samples in each burst window +static unsigned adaptive_burst_window_remaining; // samples remaining in the current burst window +static unsigned adaptive_burst_window_counter; // loud samples seen in current burst window +static unsigned adaptive_burst_runlength; // consecutive loud burst windows seen +static unsigned adaptive_burst_block_loud_undecoded; // loud undecoded bursts seen in this block so far +static unsigned adaptive_burst_block_loud_decoded; // loud decoded messages seen in this block so far +static double adaptive_burst_loud_undecoded_smoothed; // smoothed rate of loud misdecodes per block +static double adaptive_burst_loud_decoded_smoothed; // smoothed rate of loud successful decodes per block +static unsigned adaptive_burst_change_timer; // countdown inhibiting control after changing gain +static double adaptive_burst_loud_threshold; // current signal level threshold for a "loud decode" +static unsigned adaptive_burst_loud_blocks = 0; // consecutive blocks with loud rate +static unsigned adaptive_burst_quiet_blocks = 0; // consecutive blocks with quiet rate static void adaptive_burst_update(uint16_t *buf, unsigned length); static void adaptive_burst_skip(unsigned length); @@ -64,23 +67,23 @@ static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows); static void adaptive_burst_end_of_window(unsigned counter); static void adaptive_burst_end_of_block(); -static void adaptive_burst_control_update(); - // // noise floor measurement (adaptive dynamic range) // -static unsigned *adaptive_range_radix; -static unsigned adaptive_range_counter; -static double adaptive_range_smoothed; +static unsigned *adaptive_range_radix; // radix-sort buckets for current block +static unsigned adaptive_range_radix_counter; // sum of all radix-sort buckets (= number of samples sorted) +static double adaptive_range_smoothed; // smoothed noise floor estimate, dBFS static enum { RANGE_SCAN_IDLE, RANGE_SCAN_UP, RANGE_SCAN_DOWN } adaptive_range_state = RANGE_SCAN_UP; -static unsigned adaptive_range_delay; +static unsigned adaptive_range_change_timer; // countdown inhibiting control after changing gain +static unsigned adaptive_range_rescan_timer; // countdown to next upwards gain reprobe +static int adaptive_range_gain_limit; // probed maximum gain step with acceptable dynamic range static void adaptive_range_update(uint16_t *buf, unsigned length); static void adaptive_range_end_of_block(); -static void adaptive_range_control_update(); - +// Try to change the SDR gain to 'step' and tell the user about it, +// with 'why' as the reason to show. Return true if the gain actually changed. static bool adaptive_set_gain(int step, const char *why) { if (step < adaptive_gain_min) @@ -96,9 +99,14 @@ static bool adaptive_set_gain(int step, const char *why) sdrGetGainDb(current_gain), current_gain, sdrGetGainDb(step), step, why); int new_gain = sdrSetGain(step); - return (current_gain != new_gain); + bool changed = (current_gain != new_gain); + if (changed) + ++Modes.stats_current.adaptive_gain_changes; + return changed; } +// Update internal state to reflect a gain change +// (usually after adaptive_set_gain returns true, but also called during init) static void adaptive_gain_changed() { int new_gain = sdrGetGain(); @@ -107,8 +115,14 @@ static void adaptive_gain_changed() double loud_threshold_dbfs = 0 - adaptive_gain_up_db - 3.0; adaptive_burst_loud_threshold = pow(10, loud_threshold_dbfs / 10.0); + + adaptive_range_change_timer = Modes.adaptive_range_change_delay; + adaptive_burst_change_timer = Modes.adaptive_burst_change_delay; + adaptive_burst_loud_blocks = 0; + adaptive_burst_quiet_blocks = 0; } +// External init entry point void adaptive_init() { int maxgain = sdrGetMaxGain(); @@ -130,16 +144,13 @@ void adaptive_init() adaptive_burst_window_size = Modes.sample_rate / 25000; adaptive_burst_window_remaining = adaptive_burst_window_size; adaptive_burst_window_counter = 0; - adaptive_burst_change_delay = Modes.adaptive_burst_change_delay; // Use an overall block size that is an exact multiple of the burst window, close to 1 second long adaptive_block_size = adaptive_burst_window_size * 25000; adaptive_block_remaining = adaptive_block_size; adaptive_range_radix = calloc(sizeof(unsigned), 65536); - adaptive_range_state = RANGE_SCAN_UP; - adaptive_range_delay = Modes.adaptive_range_scan_delay; // select and enforce gain limits for (adaptive_gain_min = 0; adaptive_gain_min < maxgain; ++adaptive_gain_min) { @@ -160,6 +171,8 @@ void adaptive_init() fprintf(stderr, "adaptive: enabled burst control\n"); adaptive_set_gain(sdrGetGain(), "constraining gain to adaptive gain limits"); adaptive_gain_changed(); + + adaptive_range_gain_limit = sdrGetGain(); } // Feed some samples into the adaptive system. Any number of samples might be passed in. @@ -190,7 +203,7 @@ static void adaptive_update_single(uint16_t *buf, unsigned length, struct modesM { if (decoded) { if (/* decoded->msgbits == 112 && */ decoded->signalLevel >= adaptive_burst_loud_threshold) - ++adaptive_burst_block_loud_decodes; + ++adaptive_burst_block_loud_decoded; adaptive_burst_skip(length); } else { adaptive_burst_update(buf, length); @@ -300,7 +313,7 @@ static void adaptive_burst_end_of_window(unsigned counter) // that as a candidate for an over-amplified message that was // not decoded. if (adaptive_burst_runlength >= 2 && adaptive_burst_runlength <= 5) - ++adaptive_burst_block_counter; + ++adaptive_burst_block_loud_undecoded; adaptive_burst_runlength = 0; } } @@ -312,7 +325,7 @@ static void adaptive_range_update(uint16_t *buf, unsigned length) if (!Modes.adaptive_range_control) return; - adaptive_range_counter += length; + adaptive_range_radix_counter += length; while (length--) { // do a very simple radix sort of sample magnitudes // so we can later find the Nth percentile value @@ -331,7 +344,7 @@ static void adaptive_range_end_of_block() unsigned n = 0, i = 0; // measure Nth percentile magnitude - unsigned count_n = adaptive_range_counter * Modes.adaptive_range_percentile / 100; + unsigned count_n = adaptive_range_radix_counter * Modes.adaptive_range_percentile / 100; while (i < 65536 && n <= count_n) n += adaptive_range_radix[i++]; uint16_t percentile_n = i - 1; @@ -347,7 +360,7 @@ static void adaptive_range_end_of_block() // reset radix sort for the next block memset(adaptive_range_radix, 0, 65536 * sizeof(unsigned)); - adaptive_range_counter = 0; + adaptive_range_radix_counter = 0; } // Burst measurement: we reached the end of a block, update our burst rate estimate @@ -356,25 +369,17 @@ static void adaptive_burst_end_of_block() if (!Modes.adaptive_burst_control) return; - // maintain an EMA of the number of bursts seen per block - Modes.stats_current.adaptive_loud_undecoded += adaptive_burst_block_counter; - adaptive_burst_smoothed = adaptive_burst_smoothed * (1 - Modes.adaptive_burst_alpha) + adaptive_burst_block_counter * Modes.adaptive_burst_alpha; - adaptive_burst_block_counter = 0; + // maintain an EMA of the number of undecoded loud bursts seen per block + Modes.stats_current.adaptive_loud_undecoded += adaptive_burst_block_loud_undecoded; + adaptive_burst_loud_undecoded_smoothed = adaptive_burst_loud_undecoded_smoothed * (1 - Modes.adaptive_burst_alpha) + adaptive_burst_block_loud_undecoded * Modes.adaptive_burst_alpha; + adaptive_burst_block_loud_undecoded = 0; // maintain an EMA of the number of decoded, but loud, messages seen per block - Modes.stats_current.adaptive_loud_decoded += adaptive_burst_block_loud_decodes; - adaptive_burst_loud_decodes_smoothed = adaptive_burst_loud_decodes_smoothed * (1 - Modes.adaptive_burst_alpha) + adaptive_burst_block_loud_decodes * Modes.adaptive_burst_alpha; - adaptive_burst_block_loud_decodes = 0; + Modes.stats_current.adaptive_loud_decoded += adaptive_burst_block_loud_decoded; + adaptive_burst_loud_decoded_smoothed = adaptive_burst_loud_decoded_smoothed * (1 - Modes.adaptive_burst_alpha) + adaptive_burst_block_loud_decoded * Modes.adaptive_burst_alpha; + adaptive_burst_block_loud_decoded = 0; } -// consecutive blocks with loud rate -static unsigned adaptive_burst_loud_blocks = 0; -// consecutive blocks with quiet rate -static unsigned adaptive_burst_quiet_blocks = 0; -// are we suppressing gain due to a burst? -static bool adaptive_burst_suppressing = false; -// what was the gain before we started suppressing? -static int adaptive_burst_orig_gain = 0; void flush_stats(uint64_t now); @@ -396,32 +401,41 @@ static void adaptive_end_of_block() adaptive_range_end_of_block(); adaptive_burst_end_of_block(); - adaptive_burst_control_update(); - adaptive_range_control_update(); + adaptive_control_update(); Modes.stats_current.adaptive_valid = true; unsigned current = Modes.stats_current.adaptive_gain = sdrGetGain(); + Modes.stats_current.adaptive_range_gain_limit = adaptive_range_gain_limit; ++Modes.stats_current.adaptive_gain_seconds[current < STATS_GAIN_COUNT ? current : STATS_GAIN_COUNT-1]; - if (adaptive_burst_suppressing) - ++Modes.stats_current.adaptive_gain_reduced_seconds; } -static void adaptive_burst_control_update() +static void adaptive_control_update() { - if (!Modes.adaptive_burst_control) - return; + // votes for what to do with the gain + // "gain_not_up" overlaps somewhat with "gain_down", but they are not identical; + // burst control may want to prevent gain from increasing, but not necessarily + // decrease gain. - if (adaptive_range_state != RANGE_SCAN_IDLE) - return; - - if (adaptive_burst_change_delay) - --adaptive_burst_change_delay; + bool gain_up = false; + const char *gain_up_reason = NULL; + bool gain_down = false; + const char *gain_down_reason = NULL; + bool gain_not_up = false; - if (!adaptive_burst_change_delay) { - if (adaptive_burst_smoothed > Modes.adaptive_burst_loud_rate) { + int current_gain = sdrGetGain(); + + if (adaptive_burst_change_timer) + --adaptive_burst_change_timer; + if (adaptive_range_change_timer > 0) + --adaptive_range_change_timer; + if (adaptive_range_rescan_timer > 0) + --adaptive_range_rescan_timer; + + if (Modes.adaptive_burst_control && !adaptive_burst_change_timer) { + if (adaptive_burst_loud_undecoded_smoothed > Modes.adaptive_burst_loud_rate) { adaptive_burst_quiet_blocks = 0; ++adaptive_burst_loud_blocks; - } else if (adaptive_burst_loud_decodes_smoothed < Modes.adaptive_burst_quiet_rate) { + } else if (adaptive_burst_loud_decoded_smoothed < Modes.adaptive_burst_quiet_rate) { adaptive_burst_loud_blocks = 0; ++adaptive_burst_quiet_blocks; } else { @@ -431,122 +445,128 @@ static void adaptive_burst_control_update() if (adaptive_burst_loud_blocks >= Modes.adaptive_burst_loud_runlength) { // we need to reduce gain (further) - if (!adaptive_burst_suppressing) { - adaptive_burst_suppressing = true; - adaptive_burst_orig_gain = sdrGetGain(); + gain_down = gain_not_up = true; + gain_down_reason = "high rate of loud undecoded messages"; + + // if we're currently doing a downward scan, reducing gain further may confuse it; + // stop that scan and restart it once we are no longer in a reduced-gain state + if (adaptive_range_state == RANGE_SCAN_DOWN) { + adaptive_range_state = RANGE_SCAN_IDLE; + adaptive_range_rescan_timer = 0; + } + } else if (adaptive_burst_quiet_blocks < Modes.adaptive_burst_quiet_runlength) { + // we're OK at the current gain, but should not increase it + gain_not_up = true; + } else if (current_gain < adaptive_range_gain_limit) { + // we're OK at the current gain, and can increase gain to the previously discovered + // dynamic range limit + gain_up = true; + gain_up_reason = "low loud message rate and gain below dynamic range limit"; + } + } + + if (Modes.adaptive_range_control && !adaptive_range_change_timer) { + float available_range = -20 * log10(adaptive_range_smoothed / 65536.0); + // allow the gain limit to increase if this gain setting is acceptable + // (decreasing the limit is done separately in SCAN_UP / IDLE states when we decide to reduce gain) + if (available_range >= Modes.adaptive_range_target && current_gain > adaptive_range_gain_limit) + adaptive_range_gain_limit = current_gain; + + switch (adaptive_range_state) { + case RANGE_SCAN_UP: + if (available_range < Modes.adaptive_range_target) { + // Current gain fails to meet our target. Switch to downward scanning. + fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), switching to downward scan\n", available_range, Modes.adaptive_range_target); + gain_down = gain_not_up = true; + gain_down_reason = "probing dynamic range gain lower bound"; + adaptive_range_state = RANGE_SCAN_DOWN; + if (adaptive_range_gain_limit >= current_gain) + adaptive_range_gain_limit = current_gain - 1; + break; } - adaptive_decrease_gain("saw a noisy period with many undecoded loud messages"); - adaptive_burst_loud_blocks = 0; - adaptive_burst_change_delay = Modes.adaptive_burst_change_delay; - } + if (sdrGetGain() >= adaptive_gain_max) { + // We have reached our upper gain limit + fprintf(stderr, "adaptive: reached upper gain limit, halting dynamic range scan here\n"); + adaptive_range_state = RANGE_SCAN_IDLE; + adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay; + break; + } - if (adaptive_burst_suppressing && adaptive_burst_quiet_blocks >= Modes.adaptive_burst_quiet_runlength) { - // we can relax the gain restriction - adaptive_increase_gain("saw a quiet period with few loud messages"); - adaptive_burst_quiet_blocks = 0; - adaptive_burst_change_delay = Modes.adaptive_burst_change_delay; + // This gain step is OK and we have more to try, try the next gain step up. + // (But if burst detection has inhibited increasing gain, don't do anything yet, just try again next block) + if (!gain_not_up) { + fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), continuing upward scan\n", available_range, Modes.adaptive_range_target); + gain_up = true; + gain_up_reason = "probing dynamic range gain upper bound"; + } + break; - if (sdrGetGain() >= adaptive_burst_orig_gain) - adaptive_burst_suppressing = false; + case RANGE_SCAN_DOWN: + if (available_range >= Modes.adaptive_range_target) { + // Current gain meets our target; we are done with the scan. + fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), stopping downwards scan here\n", available_range, Modes.adaptive_range_target); + adaptive_range_state = RANGE_SCAN_IDLE; + adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay; + break; + } + + if (sdrGetGain() <= adaptive_gain_min) { + fprintf(stderr, "adaptive: reached lower gain limit, halting dynamic range scan here\n"); + adaptive_range_state = RANGE_SCAN_IDLE; + adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay; + break; + } + + // This gain step is too loud and we have more to try, try the next gain step down + fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), continuing downwards scan\n", available_range, Modes.adaptive_range_target); + gain_down = gain_not_up = true; + gain_down_reason = "probing dynamic range gain lower bound"; + break; + + case RANGE_SCAN_IDLE: + // Look for increased noise that could be compensated for by decreasing gain. + // Do this even if we're waiting to rescan or if burst control is also active + if (available_range + adaptive_gain_down_db / 2 < Modes.adaptive_range_target && sdrGetGain() > adaptive_gain_min) { + fprintf(stderr, "adaptive: available dynamic range (%.1fdB) + half gain step down (%.1fdB) < required dynamic range (%.1fdB), starting downward scan\n", + available_range, Modes.adaptive_range_target, adaptive_gain_down_db); + if (current_gain >= adaptive_range_gain_limit) + adaptive_range_gain_limit = current_gain - 1; + adaptive_range_state = RANGE_SCAN_DOWN; + gain_down = gain_not_up = true; + gain_down_reason = "dynamic range fell below target value"; + break; + } + + // Infrequently consider increasing gain to handle the case where we've selected a too-low gain where the noise floor is dominated by noise unrelated to the gain setting. + // But don't do this while burst control is preventing gain increases. + if (!adaptive_range_rescan_timer && !gain_not_up) { + if (available_range >= Modes.adaptive_range_target && sdrGetGain() < adaptive_gain_max) { + fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n"); + gain_up = true; + gain_up_reason = "periodic re-probing of dynamic range gain upper bound"; + adaptive_range_state = RANGE_SCAN_UP; + break; + } + + // Nothing to do for a while. + adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay; + } + + break; + + default: + fprintf(stderr, "adaptive: in a weird state (%d), trying to fix it\n", adaptive_range_state); + adaptive_range_state = RANGE_SCAN_IDLE; + adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay; + break; } } -} - -static void adaptive_range_control_update() -{ - if (!Modes.adaptive_range_control) - return; - - if (adaptive_range_delay > 0) - --adaptive_range_delay; - - float available_range = -20 * log10(adaptive_range_smoothed / 65536.0); - - switch (adaptive_range_state) { - case RANGE_SCAN_UP: - if (adaptive_range_delay > 0) - break; - - if (available_range < Modes.adaptive_range_target) { - // Current gain fails to meet our target. Switch to downward scanning. - fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), switching to downward scan\n", available_range, Modes.adaptive_range_target); - adaptive_decrease_gain("downwards dynamic range gain scan"); - adaptive_range_state = RANGE_SCAN_DOWN; - adaptive_range_delay = Modes.adaptive_range_scan_delay; - break; - } - - if (sdrGetGain() >= adaptive_gain_max) { - // We have reached our upper gain limit - fprintf(stderr, "adaptive: reached upper gain limit, halting dynamic range scan here\n"); - adaptive_range_state = RANGE_SCAN_IDLE; - adaptive_range_delay = Modes.adaptive_range_rescan_delay; - break; - } - - // This gain step is OK and we have more to try, try the next gain step up. - fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), continuing upward scan\n", available_range, Modes.adaptive_range_target); - adaptive_increase_gain("upwards dynamic range scan"); - adaptive_range_delay = Modes.adaptive_range_scan_delay; - break; - - case RANGE_SCAN_DOWN: - if (adaptive_range_delay > 0) - break; - - if (available_range >= Modes.adaptive_range_target) { - // Current gain meets our target; we are done with the scan. - fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), stopping downwards scan here\n", available_range, Modes.adaptive_range_target); - adaptive_range_state = RANGE_SCAN_IDLE; - adaptive_range_delay = Modes.adaptive_range_rescan_delay; - break; - } - - if (sdrGetGain() <= adaptive_gain_min) { - fprintf(stderr, "adaptive: reached lower gain limit, halting dynamic range scan here\n"); - adaptive_range_state = RANGE_SCAN_IDLE; - adaptive_range_delay = Modes.adaptive_range_rescan_delay; - break; - } - - // This gain step is too loud and we have more to try, try the next gain step down - fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), continuing downwards scan\n", available_range, Modes.adaptive_range_target); - adaptive_decrease_gain("downwards dynamic range gain scan"); - adaptive_range_delay = Modes.adaptive_range_scan_delay; - break; - - case RANGE_SCAN_IDLE: - // Look for increased noise that could be compensated for by decreasing gain. - // Do this even if we're delaying. - if (available_range + adaptive_gain_down_db / 2 < Modes.adaptive_range_target && sdrGetGain() > adaptive_gain_min) { - fprintf(stderr, "adaptive: available dynamic range (%.1fdB) + half gain step down (%.1fdB) < required dynamic range (%.1fdB), starting downward scan\n", - available_range, Modes.adaptive_range_target, adaptive_gain_down_db); - adaptive_range_state = RANGE_SCAN_DOWN; - adaptive_range_delay = Modes.adaptive_range_scan_delay; - break; - } - - if (adaptive_range_delay > 0) - break; - - // Infrequently consider increasing gain to handle the case where we've selected a too-low gain where the noise floor is dominated by noise unrelated to the gain setting - if (available_range >= Modes.adaptive_range_target && sdrGetGain() < adaptive_gain_max) { - fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n"); - adaptive_increase_gain("upwards dynamic range scan"); - adaptive_range_state = RANGE_SCAN_UP; - adaptive_range_delay = Modes.adaptive_range_scan_delay; - break; - } - - // Nothing to do for a while. - adaptive_range_delay = Modes.adaptive_range_rescan_delay; - break; - - default: - fprintf(stderr, "adaptive: in a weird state (%d), trying to fix it\n", adaptive_range_state); - adaptive_range_state = RANGE_SCAN_IDLE; - adaptive_range_delay = Modes.adaptive_range_scan_delay; - break; - } + + // now actually perform any gain changes + + if (gain_down) + adaptive_decrease_gain(gain_down_reason); + else if (gain_up && !gain_not_up) + adaptive_increase_gain(gain_up_reason); } diff --git a/dump1090.c b/dump1090.c index 2ef773e..febecee 100644 --- a/dump1090.c +++ b/dump1090.c @@ -128,7 +128,7 @@ static void modesInitConfig(void) { Modes.adaptive_burst_control = false; Modes.adaptive_burst_alpha = 2.0 / (5 + 1); - Modes.adaptive_burst_change_delay = 15; + Modes.adaptive_burst_change_delay = 5; Modes.adaptive_burst_loud_runlength = 10; Modes.adaptive_burst_loud_rate = 5.0; Modes.adaptive_burst_quiet_runlength = 10; @@ -137,7 +137,7 @@ static void modesInitConfig(void) { Modes.adaptive_range_control = false; Modes.adaptive_range_alpha = 2.0 / (5 + 1); Modes.adaptive_range_percentile = 40; - Modes.adaptive_range_scan_delay = 15; + Modes.adaptive_range_change_delay = 10; Modes.adaptive_range_rescan_delay = 900; sdrInitConfig(); @@ -353,6 +353,8 @@ static void showHelp(void) " Adaptive gain\n" "\n" "--adaptive-burst Adjust gain for too-loud message bursts\n" +"--adaptive-range-change-delay Set delay after changing gain before\n" +" resuming burst control (seconds)\n" "--adaptive-burst-alpha Set burst rate smoothing factor\n" " (0..1, smaller=more smoothing)\n" "--adaptive-burst-loud-rate Set burst rate for gain decrease\n" @@ -364,8 +366,8 @@ static void showHelp(void) "--adaptive-range-alpha Set dynamic range noise smoothing factor\n" " (0..1, smaller=more smoothing)\n" "--adaptive-range-percentile

Set dynamic range noise percentile\n" -"--adaptive-range-scan-delay Set data collection interval for dynamic\n" -" range gain scanning (seconds)\n" +"--adaptive-range-change-delay Set delay after changing gain before\n" +" resuming dynamic range control (seconds)\n" "--adaptive-range-rescan-delay Set rescan interval for dynamic range\n" " gain scanning (seconds)\n" "--adaptive-min-gain Set gain adjustment range lower limit (dB)\n" @@ -765,7 +767,7 @@ int main(int argc, char **argv) { Modes.adaptive_burst_control = true; } else if (!strcmp(argv[j], "--adaptive-burst-alpha") && more) { Modes.adaptive_burst_alpha = atof(argv[++j]); - } else if (!strcmp(argv[j], "--adaptive-burst-delay") && more) { + } else if (!strcmp(argv[j], "--adaptive-burst-change-delay") && more) { Modes.adaptive_burst_change_delay = atoi(argv[++j]); } else if (!strcmp(argv[j], "--adaptive-burst-loud-rate") && more) { Modes.adaptive_burst_loud_rate = atof(argv[++j]); @@ -783,8 +785,8 @@ int main(int argc, char **argv) { Modes.adaptive_range_percentile = atoi(argv[++j]); } else if (!strcmp(argv[j], "--adaptive-range-target") && more) { Modes.adaptive_range_target = atof(argv[++j]); - } else if (!strcmp(argv[j], "--adaptive-range-scan-delay") && more) { - Modes.adaptive_range_scan_delay = atoi(argv[++j]); + } else if (!strcmp(argv[j], "--adaptive-range-change-delay") && more) { + Modes.adaptive_range_change_delay = atoi(argv[++j]); } else if (!strcmp(argv[j], "--adaptive-range-rescan-delay") && more) { Modes.adaptive_range_rescan_delay = atoi(argv[++j]); } else if (sdrHandleOption(argc, argv, &j)) { diff --git a/dump1090.h b/dump1090.h index 41799a7..c0eb1bc 100644 --- a/dump1090.h +++ b/dump1090.h @@ -406,7 +406,7 @@ struct _Modes { // Internal state float adaptive_range_alpha; unsigned adaptive_range_percentile; float adaptive_range_target; - unsigned adaptive_range_scan_delay; + unsigned adaptive_range_change_delay; unsigned adaptive_range_rescan_delay; }; diff --git a/net_io.c b/net_io.c index 6ba9f16..a257d94 100644 --- a/net_io.c +++ b/net_io.c @@ -1863,13 +1863,15 @@ static char * appendStatsJson(char *p, p = safe_snprintf(p, end, ",\"adaptive\":" "{\"gain_db\":%.1f" - ",\"gain_reduced_seconds\":%u" + ",\"dynamic_range_limit_db\":%.1f" + ",\"gain_changes\":%u" ",\"loud_undecoded\":%u" ",\"loud_decoded\":%u" ",\"noise_dbfs\":%.1f" ",\"gain_seconds\":[", sdrGetGainDb(st->adaptive_gain), - st->adaptive_gain_reduced_seconds, + sdrGetGainDb(st->adaptive_range_gain_limit), + st->adaptive_gain_changes, st->adaptive_loud_undecoded, st->adaptive_loud_decoded, st->adaptive_noise_dbfs); diff --git a/stats.c b/stats.c index 01e7e89..652d9ad 100644 --- a/stats.c +++ b/stats.c @@ -120,11 +120,15 @@ void display_stats(struct stats *st) { " %5u loud undecoded bursts\n" " %5u loud decoded messages\n" " %5.1f dBFS current noise floor\n" - " %5.1f dB current gain setting\n", + " %5.1f dB current gain setting\n" + " %5.1f dB current dynamic range gain upper limit\n" + " %5u gain changes caused by adaptive gain control\n", st->adaptive_loud_undecoded, st->adaptive_loud_decoded, st->adaptive_noise_dbfs, - sdrGetGainDb(st->adaptive_gain)); + sdrGetGainDb(st->adaptive_gain), + sdrGetGainDb(st->adaptive_range_gain_limit), + st->adaptive_gain_changes); uint32_t total_seconds = 0; for (unsigned i = 0; i < STATS_GAIN_COUNT; ++i) @@ -140,9 +144,6 @@ void display_stats(struct stats *st) { } } - printf(" %5u seconds (%5.1f%%) at reduced gain due to loud messages\n", - st->adaptive_gain_reduced_seconds, 100.0 * st->adaptive_gain_reduced_seconds / total_seconds); - printf(" Gain histogram:\n"); for (unsigned i = 0; i < STATS_GAIN_COUNT; ++i) { unsigned seconds = st->adaptive_gain_seconds[i]; @@ -408,8 +409,9 @@ void add_stats(const struct stats *st1, const struct stats *st2, struct stats *t target->adaptive_gain = adaptive_best->adaptive_gain; for (unsigned i = 0; i < STATS_GAIN_COUNT; ++i) target->adaptive_gain_seconds[i] = st1->adaptive_gain_seconds[i] + st2->adaptive_gain_seconds[i]; - target->adaptive_gain_reduced_seconds = st1->adaptive_gain_reduced_seconds + st2->adaptive_gain_reduced_seconds; target->adaptive_loud_undecoded = st1->adaptive_loud_undecoded + st2->adaptive_loud_undecoded; target->adaptive_loud_decoded = st1->adaptive_loud_decoded + st2->adaptive_loud_decoded; + target->adaptive_gain_changes = st1->adaptive_gain_changes + st2->adaptive_gain_changes; target->adaptive_noise_dbfs = adaptive_best->adaptive_noise_dbfs; + target->adaptive_range_gain_limit = adaptive_best->adaptive_range_gain_limit; } diff --git a/stats.h b/stats.h index e1ca139..33bef18 100644 --- a/stats.h +++ b/stats.h @@ -135,10 +135,11 @@ struct stats { bool adaptive_valid; // is the following data valid? int adaptive_gain; // Current gain step in use uint32_t adaptive_gain_seconds[STATS_GAIN_COUNT]; // Seconds spent at each gain step - uint32_t adaptive_gain_reduced_seconds; // Seconds spent at a reduced gain due to burst detection uint32_t adaptive_loud_undecoded; // Total number of loud, undecoded bursts uint32_t adaptive_loud_decoded; // Total number of loud, decoded messages + uint32_t adaptive_gain_changes; // Total number of gain changes caused by adaptive gain control double adaptive_noise_dbfs; // Current adaptive-dynamic-range smoothed noise measurement, dBFS + int adaptive_range_gain_limit; // Current adaptive-dynamic-range gain step limit }; void add_stats(const struct stats *st1, const struct stats *st2, struct stats *target);