Permalink
Browse files

rtl_fm: software agc

  • Loading branch information...
keenerd committed Sep 1, 2014
1 parent 90706d4 commit df2a9c06dfd51db8d6f56b15d92c99250f967b9b
Showing with 34 additions and 34 deletions.
  1. +34 −34 src/rtl_fm.c
View
@@ -30,7 +30,6 @@
*
* todo:
* sanity checks
- * scale squelch to other input parameters
* pad output on hop
* frequency ranges could be stored better
* auto-hop after time limit
@@ -124,10 +123,9 @@ struct dongle_state
struct agc_state
{
- int64_t gain_num;
- int64_t gain_den;
- int64_t gain_max;
- int gain_int;
+ int32_t gain_num;
+ int32_t gain_den;
+ int32_t gain_max;
int peak_target;
int attack_step;
int decay_step;
@@ -232,9 +230,9 @@ void usage(void)
"\t[-E enable_option (default: none)]\n"
"\t use multiple -E to enable multiple options\n"
"\t edge: enable lower edge tuning\n"
- "\t dc: enable dc blocking filter\n"
+ "\t no-dc: disable dc blocking filter\n"
"\t deemp: enable de-emphasis filter\n"
- "\t swagc: enable software agc (only for AM, broken)\n"
+ "\t swagc: enable 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"
@@ -633,7 +631,7 @@ void fm_demod(struct demod_state *fm)
void am_demod(struct demod_state *fm)
// todo, fix this extreme laziness
{
- int i, pcm;
+ int32_t i, pcm;
int16_t *lp = fm->lowpassed;
for (i = 0; i < fm->lp_len; i += 2) {
// hypot uses floats but won't overflow
@@ -643,7 +641,7 @@ void am_demod(struct demod_state *fm)
lp[i/2] = (int16_t)sqrt(pcm) * fm->output_scale;
}
fm->lp_len = fm->lp_len / 2;
- // lowpass? (3khz) highpass? (dc)
+ // lowpass? (3khz)
}
void usb_demod(struct demod_state *fm)
@@ -764,29 +762,35 @@ int squelch_to_rms(int db, struct dongle_state *dongle, struct demod_state *demo
}
void software_agc(struct demod_state *d)
-/* ignores complex pairs, indirectly calculates power squelching */
{
int i = 0;
- int output;
+ int peaked = 0;
+ int32_t output;
struct agc_state *agc = d->agc;
int16_t *lp = d->lowpassed;
for (i=0; i < d->lp_len; i++) {
- output = (int)((int64_t)lp[i] * agc->gain_num / agc->gain_den);
+ output = ((int32_t)lp[i] * agc->gain_num / agc->gain_den);
- if (abs(output) < agc->peak_target) {
- agc->gain_num += agc->decay_step;
+ if (!peaked && abs(output) > agc->peak_target) {
+ peaked = 1;}
+ if (peaked) {
+ agc->gain_num += agc->attack_step;
} else {
- agc->gain_num -= agc->attack_step;
+ agc->gain_num += agc->decay_step;
}
if (agc->gain_num < agc->gain_den) {
agc->gain_num = agc->gain_den;}
if (agc->gain_num > agc->gain_max) {
agc->gain_num = agc->gain_max;}
- agc->gain_int = (int)(agc->gain_num / agc->gain_den);
- lp[i] = output;
+ if (output >= (1<<15)) {
+ output = (1<<15) - 1;}
+ if (output < -(1<<15)) {
+ output = -(1<<15) + 1;}
+
+ lp[i] = (int16_t)output;
}
}
@@ -812,12 +816,8 @@ void full_demod(struct demod_state *d)
} else {
low_pass(d);
}
- if (d->agc_enable) {
- software_agc(d);
- if(d->squelch_level && d->agc->gain_int > d->squelch_level) {
- do_squelch = 1;}
/* power squelch */
- } else if (d->squelch_level) {
+ if (d->squelch_level) {
sr = rms(d->lowpassed, d->lp_len, 1);
if (sr < d->squelch_level) {
do_squelch = 1;}
@@ -835,16 +835,17 @@ void full_demod(struct demod_state *d)
}
d->mode_demod(d); /* lowpassed -> lowpassed */
if (d->mode_demod == &raw_demod) {
- return;
- }
+ return;}
+ if (d->dc_block) {
+ dc_block_filter(d);}
+ if (d->agc_enable) {
+ software_agc(d);}
/* todo, fm noise squelch */
// use nicer filter here too?
if (d->post_downsample > 1) {
d->lp_len = low_pass_simple(d->lowpassed, d->lp_len, d->post_downsample);}
if (d->deemph) {
deemph_filter(d);}
- if (d->dc_block) {
- dc_block_filter(d);}
if (d->rate_out2 > 0) {
low_pass_real(d);
//arbitrary_resample(d->lowpassed, d->lowpassed, d->lp_len, d->lp_len * d->rate_out2 / d->rate_out);
@@ -1136,7 +1137,7 @@ void demod_init(struct demod_state *s)
s->prev_lpr_index = 0;
s->deemph_a = 0;
s->now_lpr = 0;
- s->dc_block = 0;
+ s->dc_block = 1;
s->dc_avg = 0;
pthread_rwlock_init(&s->rw, NULL);
pthread_cond_init(&s->ready, NULL);
@@ -1211,13 +1212,12 @@ int agc_init(struct demod_state *s)
agc = malloc(sizeof(struct agc_state));
s->agc = agc;
- agc->gain_den = 1<<13;
+ agc->gain_den = 1<<16;
agc->gain_num = agc->gain_den;
- agc->gain_int = (int)(agc->gain_num / agc->gain_den);
- agc->peak_target = 1<<13;
- agc->gain_max = 1<<10 * agc->gain_num;
- agc->attack_step = 2;
+ agc->peak_target = 1<<14;
+ agc->gain_max = 256 * agc->gain_den;
agc->decay_step = 1;
+ agc->attack_step = -2;
return 0;
}
@@ -1320,8 +1320,8 @@ int main(int argc, char **argv)
case 'E':
if (strcmp("edge", optarg) == 0) {
controller.edge = 1;}
- if (strcmp("dc", optarg) == 0) {
- demod.dc_block = 1;}
+ if (strcmp("no-dc", optarg) == 0) {
+ demod.dc_block = 0;}
if (strcmp("deemp", optarg) == 0) {
demod.deemph = 1;}
if (strcmp("swagc", optarg) == 0) {

0 comments on commit df2a9c0

Please sign in to comment.