rtl_fm: in-place demodulators

squashed
Kyle Keen 2014-08-26 17:22:36 -04:00
rodzic 8189495888
commit 7a98f12bcc
1 zmienionych plików z 43 dodań i 52 usunięć

Wyświetl plik

@ -107,7 +107,7 @@ struct dongle_state
uint32_t freq; uint32_t freq;
uint32_t rate; uint32_t rate;
int gain; int gain;
uint16_t buf16[MAXIMUM_BUF_LENGTH]; int16_t buf16[MAXIMUM_BUF_LENGTH];
uint32_t buf_len; uint32_t buf_len;
int ppm_error; int ppm_error;
int offset_tuning; int offset_tuning;
@ -124,10 +124,8 @@ struct demod_state
int lp_len; int lp_len;
int16_t lp_i_hist[10][6]; int16_t lp_i_hist[10][6];
int16_t lp_q_hist[10][6]; int16_t lp_q_hist[10][6];
int16_t result[MAXIMUM_BUF_LENGTH];
int16_t droop_i_hist[9]; int16_t droop_i_hist[9];
int16_t droop_q_hist[9]; int16_t droop_q_hist[9];
int result_len;
int rate_in; int rate_in;
int rate_out; int rate_out;
int rate_out2; int rate_out2;
@ -353,22 +351,23 @@ void low_pass_real(struct demod_state *s)
/* simple square window FIR */ /* simple square window FIR */
// add support for upsampling? // add support for upsampling?
{ {
int16_t *lp = s->lowpassed;
int i=0, i2=0; int i=0, i2=0;
int fast = (int)s->rate_out; int fast = (int)s->rate_out;
int slow = s->rate_out2; int slow = s->rate_out2;
while (i < s->result_len) { while (i < s->lp_len) {
s->now_lpr += s->result[i]; s->now_lpr += lp[i];
i++; i++;
s->prev_lpr_index += slow; s->prev_lpr_index += slow;
if (s->prev_lpr_index < fast) { if (s->prev_lpr_index < fast) {
continue; continue;
} }
s->result[i2] = (int16_t)(s->now_lpr / (fast/slow)); lp[i2] = (int16_t)(s->now_lpr / (fast/slow));
s->prev_lpr_index -= fast; s->prev_lpr_index -= fast;
s->now_lpr = 0; s->now_lpr = 0;
i2 += 1; i2 += 1;
} }
s->result_len = i2; s->lp_len = i2;
} }
void fifth_order(int16_t *data, int length, int16_t *hist) void fifth_order(int16_t *data, int length, int16_t *hist)
@ -546,35 +545,32 @@ int esbensen(int ar, int aj, int br, int bj)
void fm_demod(struct demod_state *fm) void fm_demod(struct demod_state *fm)
{ {
int i, pcm; int i, pcm = 0;
int16_t *lp = fm->lowpassed; int16_t *lp = fm->lowpassed;
pcm = polar_discriminant(lp[0], lp[1], int16_t pr = fm->pre_r;
fm->pre_r, fm->pre_j); int16_t pj = fm->pre_j;
fm->result[0] = (int16_t)pcm; for (i = 0; i < (fm->lp_len-1); i += 2) {
for (i = 2; i < (fm->lp_len-1); i += 2) {
switch (fm->custom_atan) { switch (fm->custom_atan) {
case 0: case 0:
pcm = polar_discriminant(lp[i], lp[i+1], pcm = polar_discriminant(lp[i], lp[i+1], pr, pj);
lp[i-2], lp[i-1]);
break; break;
case 1: case 1:
pcm = polar_disc_fast(lp[i], lp[i+1], pcm = polar_disc_fast(lp[i], lp[i+1], pr, pj);
lp[i-2], lp[i-1]);
break; break;
case 2: case 2:
pcm = polar_disc_lut(lp[i], lp[i+1], pcm = polar_disc_lut(lp[i], lp[i+1], pr, pj);
lp[i-2], lp[i-1]);
break; break;
case 3: case 3:
pcm = esbensen(lp[i], lp[i+1], pcm = esbensen(lp[i], lp[i+1], pr, pj);
lp[i-2], lp[i-1]);
break; break;
} }
fm->result[i/2] = (int16_t)pcm; pr = lp[i];
pj = lp[i+1];
fm->lowpassed[i/2] = (int16_t)pcm;
} }
fm->pre_r = lp[fm->lp_len - 2]; fm->pre_r = pr;
fm->pre_j = lp[fm->lp_len - 1]; fm->pre_j = pj;
fm->result_len = fm->lp_len/2; fm->lp_len = fm->lp_len / 2;
} }
void am_demod(struct demod_state *fm) void am_demod(struct demod_state *fm)
@ -582,15 +578,14 @@ void am_demod(struct demod_state *fm)
{ {
int i, pcm; int i, pcm;
int16_t *lp = fm->lowpassed; int16_t *lp = fm->lowpassed;
int16_t *r = fm->result;
for (i = 0; i < fm->lp_len; i += 2) { for (i = 0; i < fm->lp_len; i += 2) {
// hypot uses floats but won't overflow // hypot uses floats but won't overflow
//r[i/2] = (int16_t)hypot(lp[i], lp[i+1]); //r[i/2] = (int16_t)hypot(lp[i], lp[i+1]);
pcm = lp[i] * lp[i]; pcm = lp[i] * lp[i];
pcm += lp[i+1] * lp[i+1]; pcm += lp[i+1] * lp[i+1];
r[i/2] = (int16_t)sqrt(pcm) * fm->output_scale; lp[i/2] = (int16_t)sqrt(pcm) * fm->output_scale;
} }
fm->result_len = fm->lp_len/2; fm->lp_len = fm->lp_len / 2;
// lowpass? (3khz) highpass? (dc) // lowpass? (3khz) highpass? (dc)
} }
@ -598,49 +593,44 @@ void usb_demod(struct demod_state *fm)
{ {
int i, pcm; int i, pcm;
int16_t *lp = fm->lowpassed; int16_t *lp = fm->lowpassed;
int16_t *r = fm->result;
for (i = 0; i < fm->lp_len; i += 2) { for (i = 0; i < fm->lp_len; i += 2) {
pcm = lp[i] + lp[i+1]; pcm = lp[i] + lp[i+1];
r[i/2] = (int16_t)pcm * fm->output_scale; lp[i/2] = (int16_t)pcm * fm->output_scale;
} }
fm->result_len = fm->lp_len/2; fm->lp_len = fm->lp_len / 2;
} }
void lsb_demod(struct demod_state *fm) void lsb_demod(struct demod_state *fm)
{ {
int i, pcm; int i, pcm;
int16_t *lp = fm->lowpassed; int16_t *lp = fm->lowpassed;
int16_t *r = fm->result;
for (i = 0; i < fm->lp_len; i += 2) { for (i = 0; i < fm->lp_len; i += 2) {
pcm = lp[i] - lp[i+1]; pcm = lp[i] - lp[i+1];
r[i/2] = (int16_t)pcm * fm->output_scale; lp[i/2] = (int16_t)pcm * fm->output_scale;
} }
fm->result_len = fm->lp_len/2; fm->lp_len = fm->lp_len / 2;
} }
void raw_demod(struct demod_state *fm) void raw_demod(struct demod_state *fm)
{ {
int i; return;
for (i = 0; i < fm->lp_len; i++) {
fm->result[i] = (int16_t)fm->lowpassed[i];
}
fm->result_len = fm->lp_len;
} }
void deemph_filter(struct demod_state *fm) void deemph_filter(struct demod_state *fm)
{ {
static int avg; // cheating... static int avg; // cheating, not threadsafe
int i, d; int i, d;
int16_t *lp = fm->lowpassed;
// de-emph IIR // de-emph IIR
// avg = avg * (1 - alpha) + sample * alpha; // avg = avg * (1 - alpha) + sample * alpha;
for (i = 0; i < fm->result_len; i++) { for (i = 0; i < fm->lp_len; i++) {
d = fm->result[i] - avg; d = lp[i] - avg;
if (d > 0) { if (d > 0) {
avg += (d + fm->deemph_a/2) / fm->deemph_a; avg += (d + fm->deemph_a/2) / fm->deemph_a;
} else { } else {
avg += (d - fm->deemph_a/2) / fm->deemph_a; avg += (d - fm->deemph_a/2) / fm->deemph_a;
} }
fm->result[i] = (int16_t)avg; lp[i] = (int16_t)avg;
} }
} }
@ -648,13 +638,14 @@ void dc_block_filter(struct demod_state *fm)
{ {
int i, avg; int i, avg;
int64_t sum = 0; int64_t sum = 0;
for (i=0; i < fm->result_len; i++) { int16_t *lp = fm->lowpassed;
sum += fm->result[i]; for (i=0; i < fm->lp_len; i++) {
sum += lp[i];
} }
avg = sum / fm->result_len; avg = sum / fm->lp_len;
avg = (avg + fm->dc_avg * 9) / 10; avg = (avg + fm->dc_avg * 9) / 10;
for (i=0; i < fm->result_len; i++) { for (i=0; i < fm->lp_len; i++) {
fm->result[i] -= avg; lp[i] -= avg;
} }
fm->dc_avg = avg; fm->dc_avg = avg;
} }
@ -812,21 +803,21 @@ void full_demod(struct demod_state *d)
} else { } else {
d->squelch_hits = 0;} d->squelch_hits = 0;}
} }
d->mode_demod(d); /* lowpassed -> result */ d->mode_demod(d); /* lowpassed -> lowpassed */
if (d->mode_demod == &raw_demod) { if (d->mode_demod == &raw_demod) {
return; return;
} }
/* todo, fm noise squelch */ /* todo, fm noise squelch */
// use nicer filter here too? // use nicer filter here too?
if (d->post_downsample > 1) { if (d->post_downsample > 1) {
d->result_len = low_pass_simple(d->result, d->result_len, d->post_downsample);} d->lp_len = low_pass_simple(d->lowpassed, d->lp_len, d->post_downsample);}
if (d->deemph) { if (d->deemph) {
deemph_filter(d);} deemph_filter(d);}
if (d->dc_block) { if (d->dc_block) {
dc_block_filter(d);} dc_block_filter(d);}
if (d->rate_out2 > 0) { if (d->rate_out2 > 0) {
low_pass_real(d); low_pass_real(d);
//arbitrary_resample(d->result, d->result, d->result_len, d->result_len * d->rate_out2 / d->rate_out); //arbitrary_resample(d->lowpassed, d->lowpassed, d->lp_len, d->lp_len * d->rate_out2 / d->rate_out);
} }
} }
@ -881,8 +872,8 @@ static void *demod_thread_fn(void *arg)
continue; continue;
} }
pthread_rwlock_wrlock(&o->rw); pthread_rwlock_wrlock(&o->rw);
memcpy(o->result, d->result, 2*d->result_len); memcpy(o->result, d->lowpassed, 2*d->lp_len);
o->result_len = d->result_len; o->result_len = d->lp_len;
pthread_rwlock_unlock(&o->rw); pthread_rwlock_unlock(&o->rw);
safe_cond_signal(&o->ready, &o->ready_m); safe_cond_signal(&o->ready, &o->ready_m);
} }