kopia lustrzana https://github.com/keenerd/rtl-sdr
rtl_fm: add swagc-aggressive
rodzic
c6e6be52f7
commit
86f950389a
54
src/rtl_fm.c
54
src/rtl_fm.c
|
@ -103,6 +103,13 @@ static int atan_lut_coef = 8;
|
|||
int16_t shared_samples[SHARED_SIZE][MAXIMUM_BUF_LENGTH];
|
||||
int ss_busy[SHARED_SIZE] = {0};
|
||||
|
||||
enum agc_mode_t
|
||||
{
|
||||
agc_off = 0,
|
||||
agc_normal,
|
||||
agc_aggressive
|
||||
};
|
||||
|
||||
struct dongle_state
|
||||
{
|
||||
int exit_flag;
|
||||
|
@ -170,7 +177,7 @@ struct demod_state
|
|||
int dc_block, dc_avg;
|
||||
int rotate_enable;
|
||||
struct translate_state rotate;
|
||||
int agc_enable;
|
||||
enum agc_mode_t agc_mode;
|
||||
struct agc_state *agc;
|
||||
void (*mode_demod)(struct demod_state*);
|
||||
pthread_rwlock_t rw;
|
||||
|
@ -248,6 +255,7 @@ void usage(void)
|
|||
"\t no-dc: disable dc blocking filter\n"
|
||||
"\t deemp: enable de-emphasis filter\n"
|
||||
"\t swagc: enable software agc (only for AM modes)\n"
|
||||
"\t swagc-aggressive: enable aggressive software agc (only for AM modes)\n"
|
||||
"\t direct: enable direct sampling\n"
|
||||
"\t no-mod: enable no-mod direct sampling\n"
|
||||
"\t offset: enable offset tuning\n"
|
||||
|
@ -823,19 +831,31 @@ void software_agc(struct demod_state *d)
|
|||
{
|
||||
int i = 0;
|
||||
int peaked = 0;
|
||||
int32_t output;
|
||||
int32_t output = 0;
|
||||
int abs_output = 0;
|
||||
struct agc_state *agc = d->agc;
|
||||
int16_t *lp = d->lowpassed;
|
||||
int attack_step = agc->attack_step;
|
||||
int aggressive = agc_aggressive == d->agc_mode;
|
||||
float peak_factor = 1.0;
|
||||
|
||||
for (i=0; i < d->lp_len; i++) {
|
||||
output = (int32_t)lp[i] * agc->gain_num + agc->error;
|
||||
agc->error = output % agc->gain_den;
|
||||
output /= agc->gain_den;
|
||||
abs_output = abs(output);
|
||||
peaked = abs_output > agc->peak_target;
|
||||
|
||||
if (peaked && aggressive && attack_step <= 1) {
|
||||
peak_factor = fmin(5.0, (float) abs_output / agc->peak_target);
|
||||
attack_step = (int) (pow(agc->attack_step - peak_factor, peak_factor) * (176 + 3 * peak_factor));
|
||||
}
|
||||
|
||||
if (!peaked && abs(output) > agc->peak_target) {
|
||||
peaked = 1;}
|
||||
if (peaked) {
|
||||
agc->gain_num += agc->attack_step;
|
||||
agc->gain_num -= attack_step;
|
||||
if (aggressive) {
|
||||
attack_step = (int) (attack_step / 1.2);
|
||||
}
|
||||
} else {
|
||||
agc->gain_num += agc->decay_step;
|
||||
}
|
||||
|
@ -901,7 +921,7 @@ void full_demod(struct demod_state *d)
|
|||
return;}
|
||||
if (d->dc_block) {
|
||||
dc_block_filter(d);}
|
||||
if (d->agc_enable) {
|
||||
if (d->agc_mode != agc_off) {
|
||||
software_agc(d);}
|
||||
/* todo, fm noise squelch */
|
||||
// use nicer filter here too?
|
||||
|
@ -1167,7 +1187,7 @@ void clone_demod(struct demod_state *d2, struct demod_state *d1)
|
|||
d2->deemph_a = d1->deemph_a;
|
||||
d2->dc_block = d1->dc_block;
|
||||
d2->rotate_enable = d1->rotate_enable;
|
||||
d2->agc_enable = d1->agc_enable;
|
||||
d2->agc_mode = d1->agc_mode;
|
||||
d2->mode_demod = d1->mode_demod;
|
||||
}
|
||||
|
||||
|
@ -1310,7 +1330,7 @@ void demod_init(struct demod_state *s)
|
|||
s->post_downsample = 1; // once this works, default = 4
|
||||
s->custom_atan = 0;
|
||||
s->deemph = 0;
|
||||
s->agc_enable = 0;
|
||||
s->agc_mode = agc_off;
|
||||
s->rotate_enable = 0;
|
||||
s->rotate.len = 0;
|
||||
s->rotate.sincos = NULL;
|
||||
|
@ -1409,11 +1429,16 @@ int agc_init(struct demod_state *s)
|
|||
s->agc = agc;
|
||||
|
||||
agc->gain_den = 1<<15;
|
||||
agc->gain_num = agc->gain_den;
|
||||
agc->peak_target = 1<<14;
|
||||
agc->gain_max = 256 * agc->gain_den;
|
||||
agc->decay_step = 1;
|
||||
agc->attack_step = -2;
|
||||
agc->gain_num = agc->gain_den;
|
||||
agc->decay_step = 1;
|
||||
agc->attack_step = 2;
|
||||
if (s->agc_mode == agc_aggressive) {
|
||||
agc->decay_step = agc->decay_step * 4;
|
||||
agc->attack_step = agc->attack_step * 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1463,7 +1488,6 @@ int main(int argc, char **argv)
|
|||
dongle_init(&dongle);
|
||||
demod_init(&demod);
|
||||
demod_init(&demod2);
|
||||
agc_init(&demod);
|
||||
output_init(&output);
|
||||
controller_init(&controller);
|
||||
|
||||
|
@ -1523,7 +1547,9 @@ int main(int argc, char **argv)
|
|||
if (strcmp("deemp", optarg) == 0) {
|
||||
demod.deemph = 1;}
|
||||
if (strcmp("swagc", optarg) == 0) {
|
||||
demod.agc_enable = 1;}
|
||||
demod.agc_mode = agc_normal;}
|
||||
if (strcmp("swagc-aggressive", optarg) == 0) {
|
||||
demod.agc_mode = agc_aggressive;}
|
||||
if (strcmp("direct", optarg) == 0) {
|
||||
dongle.direct_sampling = 1;}
|
||||
if (strcmp("no-mod", optarg) == 0) {
|
||||
|
@ -1583,6 +1609,8 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
agc_init(&demod);
|
||||
|
||||
/* quadruple sample_rate to limit to Δθ to ±π/2 */
|
||||
demod.rate_in *= demod.post_downsample;
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue