SDR: Use filter to remove harmonics caused by downsampling/upsampling
This drastically increases the signal-noise-ratio and removes co-channel interferences. It gains CPU usage, but only on SDR threads, not on the main thread.
This commit is contained in:
parent
ff5faa8697
commit
f469879ed0
|
@ -115,6 +115,7 @@ void iir_process(iir_filter_t *filter, sample_t *samples, int length)
|
||||||
b1 = filter->b1;
|
b1 = filter->b1;
|
||||||
b2 = filter->b2;
|
b2 = filter->b2;
|
||||||
|
|
||||||
|
/* these are state pointers, so no need to write back */
|
||||||
z1 = filter->z1;
|
z1 = filter->z1;
|
||||||
z2 = filter->z2;
|
z2 = filter->z2;
|
||||||
|
|
||||||
|
@ -131,3 +132,36 @@ void iir_process(iir_filter_t *filter, sample_t *samples, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iir_process_baseband(iir_filter_t *filter, float *baseband, int length)
|
||||||
|
{
|
||||||
|
double a0, a1, a2, b1, b2;
|
||||||
|
double *z1, *z2;
|
||||||
|
double in, out;
|
||||||
|
int iterations = filter->iter;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* get states */
|
||||||
|
a0 = filter->a0;
|
||||||
|
a1 = filter->a1;
|
||||||
|
a2 = filter->a2;
|
||||||
|
b1 = filter->b1;
|
||||||
|
b2 = filter->b2;
|
||||||
|
|
||||||
|
/* these are state pointers, so no need to write back */
|
||||||
|
z1 = filter->z1;
|
||||||
|
z2 = filter->z2;
|
||||||
|
|
||||||
|
/* process filter */
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
in = *baseband;
|
||||||
|
for (j = 0; j < iterations; j++) {
|
||||||
|
out = in * a0 + z1[j];
|
||||||
|
z1[j] = in * a1 + z2[j] - b1 * out;
|
||||||
|
z2[j] = in * a2 - b2 * out;
|
||||||
|
in = out;
|
||||||
|
}
|
||||||
|
*baseband = in;
|
||||||
|
baseband += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,5 +12,6 @@ void iir_highpass_init(iir_filter_t *filter, double frequency, int samplerate, i
|
||||||
void iir_bandpass_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
|
void iir_bandpass_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
|
||||||
void iir_notch_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
|
void iir_notch_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
|
||||||
void iir_process(iir_filter_t *filter, sample_t *samples, int length);
|
void iir_process(iir_filter_t *filter, sample_t *samples, int length);
|
||||||
|
void iir_process_baseband(iir_filter_t *filter, float *baseband, int length);
|
||||||
|
|
||||||
#endif /* _FILTER_H */
|
#endif /* _FILTER_H */
|
||||||
|
|
|
@ -47,6 +47,10 @@ enum paging_signal;
|
||||||
/* enable to debug buffer handling */
|
/* enable to debug buffer handling */
|
||||||
//#define DEBUG_BUFFER
|
//#define DEBUG_BUFFER
|
||||||
|
|
||||||
|
/* enable to test without oversampling filter */
|
||||||
|
//#define DISABLE_FILTER
|
||||||
|
|
||||||
|
|
||||||
typedef struct sdr_thread {
|
typedef struct sdr_thread {
|
||||||
int use;
|
int use;
|
||||||
volatile int running, exit; /* flags to control exit of threads */
|
volatile int running, exit; /* flags to control exit of threads */
|
||||||
|
@ -56,6 +60,7 @@ typedef struct sdr_thread {
|
||||||
volatile int in, out; /* in and out pointers (atomic, so no locking required) */
|
volatile int in, out; /* in and out pointers (atomic, so no locking required) */
|
||||||
int max_fill; /* measure maximum buffer fill */
|
int max_fill; /* measure maximum buffer fill */
|
||||||
double max_fill_timer; /* timer to display/reset maximum fill */
|
double max_fill_timer; /* timer to display/reset maximum fill */
|
||||||
|
iir_filter_t lp[2]; /* filter for upsample/downsample IQ data */
|
||||||
} sdr_thread_t;
|
} sdr_thread_t;
|
||||||
|
|
||||||
typedef struct sdr_chan {
|
typedef struct sdr_chan {
|
||||||
|
@ -148,6 +153,10 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sdr->thread_read.in = sdr->thread_read.out = 0;
|
sdr->thread_read.in = sdr->thread_read.out = 0;
|
||||||
|
if (oversample > 1) {
|
||||||
|
iir_lowpass_init(&sdr->thread_read.lp[0], samplerate / 2.0, sdr_config->samplerate, 2);
|
||||||
|
iir_lowpass_init(&sdr->thread_read.lp[1], samplerate / 2.0, sdr_config->samplerate, 2);
|
||||||
|
}
|
||||||
memset(&sdr->thread_write, 0, sizeof(sdr->thread_write));
|
memset(&sdr->thread_write, 0, sizeof(sdr->thread_write));
|
||||||
sdr->thread_write.buffer_size = sdr->latspl * 2 + 2;
|
sdr->thread_write.buffer_size = sdr->latspl * 2 + 2;
|
||||||
sdr->thread_write.buffer = calloc(sdr->thread_write.buffer_size, sizeof(*sdr->thread_write.buffer));
|
sdr->thread_write.buffer = calloc(sdr->thread_write.buffer_size, sizeof(*sdr->thread_write.buffer));
|
||||||
|
@ -161,6 +170,10 @@ void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_freq
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sdr->thread_write.in = sdr->thread_write.out = 0;
|
sdr->thread_write.in = sdr->thread_write.out = 0;
|
||||||
|
if (oversample > 1) {
|
||||||
|
iir_lowpass_init(&sdr->thread_write.lp[0], samplerate / 2.0, sdr_config->samplerate, 2);
|
||||||
|
iir_lowpass_init(&sdr->thread_write.lp[1], samplerate / 2.0, sdr_config->samplerate, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* alloc fm modulation buffers */
|
/* alloc fm modulation buffers */
|
||||||
|
@ -397,6 +410,14 @@ static void *sdr_write_child(void *arg)
|
||||||
}
|
}
|
||||||
out = (out + 2) % sdr->thread_write.buffer_size;
|
out = (out + 2) % sdr->thread_write.buffer_size;
|
||||||
}
|
}
|
||||||
|
sdr->thread_write.out = out;
|
||||||
|
#ifndef DISABLE_FILTER
|
||||||
|
/* filter spectrum */
|
||||||
|
if (sdr->oversample > 1) {
|
||||||
|
iir_process_baseband(&sdr->thread_write.lp[0], sdr->thread_write.buffer2, num * sdr->oversample);
|
||||||
|
iir_process_baseband(&sdr->thread_write.lp[1], sdr->thread_write.buffer2 + 1, num * sdr->oversample);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_UHD
|
#ifdef HAVE_UHD
|
||||||
if (sdr_config->uhd)
|
if (sdr_config->uhd)
|
||||||
uhd_send(sdr->thread_write.buffer2, num * sdr->oversample);
|
uhd_send(sdr->thread_write.buffer2, num * sdr->oversample);
|
||||||
|
@ -405,7 +426,6 @@ static void *sdr_write_child(void *arg)
|
||||||
if (sdr_config->soapy)
|
if (sdr_config->soapy)
|
||||||
soapy_send(sdr->thread_write.buffer2, num * sdr->oversample);
|
soapy_send(sdr->thread_write.buffer2, num * sdr->oversample);
|
||||||
#endif
|
#endif
|
||||||
sdr->thread_write.out = out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* delay some time */
|
/* delay some time */
|
||||||
|
@ -440,6 +460,13 @@ static void *sdr_read_child(void *arg)
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
#ifdef DEBUG_BUFFER
|
#ifdef DEBUG_BUFFER
|
||||||
printf("Thread read %d samples from SDR and writes them to read buffer.\n", count);
|
printf("Thread read %d samples from SDR and writes them to read buffer.\n", count);
|
||||||
|
#endif
|
||||||
|
#ifndef DISABLE_FILTER
|
||||||
|
/* filter spectrum */
|
||||||
|
if (sdr->oversample > 1) {
|
||||||
|
iir_process_baseband(&sdr->thread_read.lp[0], sdr->thread_read.buffer2, count);
|
||||||
|
iir_process_baseband(&sdr->thread_read.lp[1], sdr->thread_read.buffer2 + 1, count);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
in = sdr->thread_read.in;
|
in = sdr->thread_read.in;
|
||||||
for (s = 0, ss = 0; s < count; s++) {
|
for (s = 0, ss = 0; s < count; s++) {
|
||||||
|
|
Loading…
Reference in New Issue