Adaptive gain: more aggressively re-probe for a higher gain

following a decrease in gain due to an increased noise floor.

This is controlled by --adaptive-range-scan-delay and defaults
to 5 minutes (vs. the default rescan delay of 1 hour)
This commit is contained in:
Oliver Jowett 2021-12-07 17:29:50 +08:00
parent fa8a066b4c
commit f932baa5fa
3 changed files with 17 additions and 8 deletions

View File

@ -107,7 +107,7 @@ static void adaptive_burst_end_of_block();
static unsigned *adaptive_range_radix; // radix-sort buckets for current block 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 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 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 enum { RANGE_SCAN_IDLE, RANGE_SCAN_UP, RANGE_SCAN_DOWN, RANGE_RESCAN_UP, RANGE_RESCAN_DOWN } adaptive_range_state = RANGE_SCAN_UP;
static unsigned adaptive_range_change_timer; // countdown inhibiting control after changing gain 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 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 int adaptive_range_gain_limit; // probed maximum gain step with acceptable dynamic range
@ -196,7 +196,7 @@ void adaptive_init()
adaptive_burst_window_counter = 0; adaptive_burst_window_counter = 0;
adaptive_range_radix = calloc(sizeof(unsigned), 65536); adaptive_range_radix = calloc(sizeof(unsigned), 65536);
adaptive_range_state = RANGE_SCAN_UP; adaptive_range_state = RANGE_RESCAN_UP;
// select and enforce gain limits // select and enforce gain limits
for (adaptive_gain_min = 0; adaptive_gain_min < maxgain; ++adaptive_gain_min) { for (adaptive_gain_min = 0; adaptive_gain_min < maxgain; ++adaptive_gain_min) {
@ -514,7 +514,7 @@ static void adaptive_control_update()
// if we're currently doing a downward scan, reducing gain further may confuse it; // 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 // stop that scan and restart it once we are no longer in a reduced-gain state
if (adaptive_range_state == RANGE_SCAN_DOWN) { if (adaptive_range_state == RANGE_SCAN_DOWN || adaptive_range_state == RANGE_RESCAN_DOWN) {
adaptive_range_state = RANGE_SCAN_IDLE; adaptive_range_state = RANGE_SCAN_IDLE;
adaptive_range_rescan_timer = 0; adaptive_range_rescan_timer = 0;
} }
@ -539,12 +539,13 @@ static void adaptive_control_update()
} }
switch (adaptive_range_state) { switch (adaptive_range_state) {
case RANGE_SCAN_UP: case RANGE_SCAN_UP:
case RANGE_RESCAN_UP:
if (available_range < Modes.adaptive_range_target) { if (available_range < Modes.adaptive_range_target) {
// Current gain fails to meet our target. Switch to downward scanning. // 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); 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 = gain_not_up = true;
gain_down_reason = "probing dynamic range gain lower bound"; gain_down_reason = "probing dynamic range gain lower bound";
adaptive_range_state = RANGE_SCAN_DOWN; adaptive_range_state = (adaptive_range_state == RANGE_RESCAN_UP ? RANGE_RESCAN_DOWN : RANGE_SCAN_DOWN);
if (adaptive_range_gain_limit >= current_gain) { if (adaptive_range_gain_limit >= current_gain) {
adaptive_range_gain_limit = current_gain - 1; adaptive_range_gain_limit = current_gain - 1;
} }
@ -569,11 +570,12 @@ static void adaptive_control_update()
break; break;
case RANGE_SCAN_DOWN: case RANGE_SCAN_DOWN:
case RANGE_RESCAN_DOWN:
if (available_range >= Modes.adaptive_range_target) { if (available_range >= Modes.adaptive_range_target) {
// Current gain meets our target; we are done with the scan. // 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); 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_state = RANGE_SCAN_IDLE;
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay; adaptive_range_rescan_timer = (adaptive_range_state == RANGE_SCAN_DOWN ? Modes.adaptive_range_scan_delay : Modes.adaptive_range_rescan_delay);
break; break;
} }
@ -616,7 +618,7 @@ static void adaptive_control_update()
fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n"); fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n");
gain_up = true; gain_up = true;
gain_up_reason = "periodic re-probing of dynamic range gain upper bound"; gain_up_reason = "periodic re-probing of dynamic range gain upper bound";
adaptive_range_state = RANGE_SCAN_UP; adaptive_range_state = RANGE_RESCAN_UP;
break; break;
} }

View File

@ -143,6 +143,7 @@ static void modesInitConfig(void) {
Modes.adaptive_range_alpha = 2.0 / (5 + 1); Modes.adaptive_range_alpha = 2.0 / (5 + 1);
Modes.adaptive_range_percentile = 40; Modes.adaptive_range_percentile = 40;
Modes.adaptive_range_change_delay = 10; Modes.adaptive_range_change_delay = 10;
Modes.adaptive_range_scan_delay = 300;
Modes.adaptive_range_rescan_delay = 3600; Modes.adaptive_range_rescan_delay = 3600;
sdrInitConfig(); sdrInitConfig();
@ -373,8 +374,11 @@ static void showHelp(void)
"--adaptive-range-percentile <p> Set dynamic range noise percentile\n" "--adaptive-range-percentile <p> Set dynamic range noise percentile\n"
"--adaptive-range-change-delay <s> Set delay after changing gain before\n" "--adaptive-range-change-delay <s> Set delay after changing gain before\n"
" resuming dynamic range control (seconds)\n" " resuming dynamic range control (seconds)\n"
"--adaptive-range-rescan-delay <s> Set rescan interval for dynamic range\n" "--adaptive-range-scan-delay <s> Set scan interval for dynamic range\n"
" gain scanning (seconds)\n" " gain scanning following a gain decrease\n"
" due to an increase in noise (seconds)\n"
"--adaptive-range-rescan-delay <s> Set periodic rescan interval for dynamic\n"
" range gain scanning (seconds)\n"
"--adaptive-min-gain <g> Set gain adjustment range lower limit (dB)\n" "--adaptive-min-gain <g> Set gain adjustment range lower limit (dB)\n"
"--adaptive-max-gain <g> Set gain adjustment range upper limit (dB)\n" "--adaptive-max-gain <g> Set gain adjustment range upper limit (dB)\n"
"--adaptive-duty-cycle <p> Set adaptive gain duty cycle %% (1..100)\n" "--adaptive-duty-cycle <p> Set adaptive gain duty cycle %% (1..100)\n"
@ -796,6 +800,8 @@ int main(int argc, char **argv) {
Modes.adaptive_range_target = atof(argv[++j]); Modes.adaptive_range_target = atof(argv[++j]);
} else if (!strcmp(argv[j], "--adaptive-range-change-delay") && more) { } else if (!strcmp(argv[j], "--adaptive-range-change-delay") && more) {
Modes.adaptive_range_change_delay = atoi(argv[++j]); Modes.adaptive_range_change_delay = atoi(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-rescan-delay") && more) { } else if (!strcmp(argv[j], "--adaptive-range-rescan-delay") && more) {
Modes.adaptive_range_rescan_delay = atoi(argv[++j]); Modes.adaptive_range_rescan_delay = atoi(argv[++j]);
} else if (sdrHandleOption(argc, argv, &j)) { } else if (sdrHandleOption(argc, argv, &j)) {

View File

@ -431,6 +431,7 @@ struct _Modes { // Internal state
unsigned adaptive_range_percentile; unsigned adaptive_range_percentile;
float adaptive_range_target; float adaptive_range_target;
unsigned adaptive_range_change_delay; unsigned adaptive_range_change_delay;
unsigned adaptive_range_scan_delay;
unsigned adaptive_range_rescan_delay; unsigned adaptive_range_rescan_delay;
}; };