rtl_fm: satisfactory squelch

Signed-off-by: Steve Markgraf <steve@steve-m.de>
master
Kyle Keen 13 years ago committed by Steve Markgraf
parent fc390b3224
commit 37f5559d1c
  1. 54
      src/rtl_fm.c

@ -26,8 +26,7 @@
* replace atan2 with a fast approximation * replace atan2 with a fast approximation
* in-place array operations * in-place array operations
* wide band support * wide band support
* squelch * refactor to look like rtl_tcp
* better threading
*/ */
#include <errno.h> #include <errno.h>
@ -63,6 +62,7 @@ struct fm_state
int prev_index; int prev_index;
int downsample; /* min 4, max 256 */ int downsample; /* min 4, max 256 */
int output_scale; int output_scale;
int squelch_level;
int signal[2048]; /* 16 bit signed i/q pairs */ int signal[2048]; /* 16 bit signed i/q pairs */
int16_t signal2[2048]; /* signal has lowpass, signal2 has demod */ int16_t signal2[2048]; /* signal has lowpass, signal2 has demod */
int signal_len; int signal_len;
@ -82,6 +82,7 @@ void usage(void)
"\t[-s samplerate (default: 24000 Hz)]\n" "\t[-s samplerate (default: 24000 Hz)]\n"
"\t[-d device_index (default: 0)]\n" "\t[-d device_index (default: 0)]\n"
"\t[-g tuner_gain (default: -1dB)]\n" "\t[-g tuner_gain (default: -1dB)]\n"
"\t[-l squelch_level (default: 150)]\n"
"\tfilename (a '-' dumps samples to stdout)\n\n" "\tfilename (a '-' dumps samples to stdout)\n\n"
"Produces signed 16 bit ints, use sox to hear them.\n" "Produces signed 16 bit ints, use sox to hear them.\n"
"\trtl_fm ... | play -t raw -r 24k -e signed-integer -b 16 -c 1 -\n\n"); "\trtl_fm ... | play -t raw -r 24k -e signed-integer -b 16 -c 1 -\n\n");
@ -116,9 +117,8 @@ void rotate_90(unsigned char *buf, uint32_t len)
{ {
uint32_t i; uint32_t i;
unsigned char tmp; unsigned char tmp;
for (i=0; i<len; i+=8) for (i=0; i<len; i+=8) {
{ /* uint8_t negation = 255 - x */
/* uint_8 negation = 255 - x */
tmp = 255 - buf[i+3]; tmp = 255 - buf[i+3];
buf[i+3] = buf[i+2]; buf[i+3] = buf[i+2];
buf[i+2] = tmp; buf[i+2] = tmp;
@ -168,9 +168,6 @@ int polar_discriminant(int ar, int aj, int br, int bj)
int cr, cj; int cr, cj;
double angle; double angle;
multiply(ar, aj, br, -bj, &cr, &cj); multiply(ar, aj, br, -bj, &cr, &cj);
/* fake squelch */
//if (abs(cr) + abs(cj) < 50000)
// {return 0;}
angle = atan2((double)cj, (double)cr); angle = atan2((double)cj, (double)cr);
return (int)(angle / 3.14159 * (1<<14)); return (int)(angle / 3.14159 * (1<<14));
} }
@ -190,16 +187,49 @@ void fm_demod(struct fm_state *fm)
fm->pre_j = fm->signal[fm->signal_len - 1]; fm->pre_j = fm->signal[fm->signal_len - 1];
} }
int mad(int *samples, int len, int step)
/* mean average deviation */
{
int i=0, sum=0, ave=0;
for (i=0; i<len; i+=step) {
sum += samples[i];
}
ave = sum / (len * step);
sum = 0;
for (i=0; i<len; i+=step) {
sum += abs(samples[i] - ave);
}
return sum / (len * step);
}
void post_squelch(struct fm_state *fm)
{
int i, i2, dev_r, dev_j, len, sq_l;
/* only for small samples, big samples need chunk processing */
len = fm->signal_len;
sq_l = fm->squelch_level;
dev_r = mad(&(fm->signal[0]), len, 2);
dev_j = mad(&(fm->signal[1]), len, 2);
if ((dev_r > sq_l) || (dev_j > sq_l)) {
return;
}
/* weak signal, kill it entirely */
for (i=0; i<len; i++) {
fm->signal2[i/2] = 0;
}
}
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
{ {
struct fm_state *fm2; struct fm_state *fm2;
if (!ctx) { if (!ctx) {
return; return;
} }
fm2 = (struct fm_struct*)(ctx); // bad conversion? fm2 = (struct fm_struct*)(ctx); // warning?
rotate_90(buf, len); rotate_90(buf, len);
low_pass(fm2, buf, len); low_pass(fm2, buf, len);
fm_demod(fm2); fm_demod(fm2);
post_squelch(fm2);
/* ignore under runs for now */ /* ignore under runs for now */
fwrite(fm2->signal2, 2, fm2->signal_len/2, fm2->file); fwrite(fm2->signal2, 2, fm2->signal_len/2, fm2->file);
} }
@ -246,8 +276,9 @@ int main(int argc, char **argv)
uint32_t out_block_size = DEFAULT_BUF_LENGTH; uint32_t out_block_size = DEFAULT_BUF_LENGTH;
int device_count; int device_count;
char vendor[256], product[256], serial[256]; char vendor[256], product[256], serial[256];
fm.squelch_level = 150;
#ifndef _WIN32 #ifndef _WIN32
while ((opt = getopt(argc, argv, "d:f:g:s:b:S::")) != -1) { while ((opt = getopt(argc, argv, "d:f:g:s:b:l:S::")) != -1) {
switch (opt) { switch (opt) {
case 'd': case 'd':
dev_index = atoi(optarg); dev_index = atoi(optarg);
@ -258,6 +289,9 @@ int main(int argc, char **argv)
case 'g': case 'g':
gain = (int)(atof(optarg) * 10); gain = (int)(atof(optarg) * 10);
break; break;
case 'l':
fm.squelch_level = (int)atof(optarg);
break;
case 's': case 's':
samp_rate = (uint32_t)atof(optarg); samp_rate = (uint32_t)atof(optarg);
break; break;

Loading…
Cancel
Save