This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/osmocom-sdr@lists.osmocom.org/.
Hayati Ayguen h_ayguen at web.deHi Osmocom guys, please consider merging the 2 attached patches. The first patch: added option -L to print current level values added option -c to configure de-emphasis time constant for wbfm added option -v to print verbose (debug) output added alias modulation names nbfm, nfm, wfm now the options in detail: option -L: "rtl_fm -L 10 -M fm": prints current level to stderr, every 10th calculation. This allows monitoring of the noise (or signal) level, to help setting an optimal squelch threshold. option -c: "rtl_fm -M wbfm -c 50" uses de-emphasis time constant for europe. One might also write "-c us" to use the north american 75 microSec standard. "-c eu" will use the european 50 microSec standard. option -v: "rtl_fm -v 1 -f 99.3M" displays verbose debug information on calculation of frequency, so that user might understand how/what frequency is tuned to. modulation names: found myself writing "wfm" instead of "wbfm". now the aliases are also accepted. The second patch: added dc filter on raw data (after decimation) with option "-E rdc" added option "-q" for setting averaging speed for "rdc" added option "-E adc" in addition to "-E dc" Please have a look in my previous mail with subject "rtl_fm: degraded demodulation caused by self-introduced DC !?" to understand the reason for a second dc filter. kind regards, Hayati Am 18.07.2015 um 16:26 schrieb Marcus Müller: > Hi Hayati, > > I'm pretty sure git.osmocom.org is the upstream; to ask steve-m to merge > your changes into his repository, just log on to github, go to > https://github.com/hayguen/librtlsdr, and you should see something like > "This branch is 2 commits ahead of steve-m:master Pull Request" > right at the top, just under the header where you can select your branch. > > The Impressum of osmocom.org said to send in patches via this mailing > list, so that's what I did once, and that worked too :), so assuming > steve-m's repo is called "steve-m" in your git ("git remote -v" will > tell), and the modified master branch being currently checked out > > git format-patch steve-m/master > > will generate a patch file for each commit between your master's HEAD > and steve-m/master. > > Greetings, > Marcus > > > On 18.07.2015 16:06, Hayati Ayguen wrote: >> Hi, >> >> just wanted to ask, what to do, so that my changes on >> https://github.com/hayguen/librtlsdr get merged into >> https://github.com/steve-m/librtlsdr ? >> >> Just now, in this moment, i realize, that there's alos >> git://git.osmocom.org/rtl-sdr.git referenced at >> http://sdr.osmocom.org/trac/wiki/rtl-sdr >> >> Ok, which is the real origin for rtl-sdr? >> What is needed to get the changes there? >> >> >> Besides the changes on rtl_fm i've developed a small tool, i called >> "stdin2wav". It's used by piping rtl_fm's output into stdin2wav, which >> then saves the output into wave files using libsndfile. >> Besides saving, it can be combined with the squelch function of rtl_fm. >> stdin2wav closes the wave file when no more data comes from stdin .. and >> re-opens a new wave file when new data arrives, cause the squelch >> opened .. >> >> Can/should this small tool also merged to rtl-sdr? Someone has a better >> place? >> By the way: someone has a better name? >> >> >> kind regards, >> Hayati >> > -------------- next part -------------- From 4a0e25ba41fc81f29ddd84aa5dbf2bbc1358dbbb Mon Sep 17 00:00:00 2001 From: Hayati Ayguen <h_ayguen at web.de> Date: Sun, 14 Jun 2015 02:17:40 +0200 Subject: [PATCH 1/2] added option -L to print current level values added option -c to configure de-emphasis time constant for wbfm added option -v to print verbose (debug) output added alias modulation names nbfm, nfm, wfm --- src/rtl_fm.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/src/rtl_fm.c b/src/rtl_fm.c index 0f7ac38..8cf95f0 100644 --- a/src/rtl_fm.c +++ b/src/rtl_fm.c @@ -4,6 +4,7 @@ * Copyright (C) 2012 by Hoernchen <la at tfc-server.de> * Copyright (C) 2012 by Kyle Keen <keenerd at gmail.com> * Copyright (C) 2013 by Elias Oenal <EliasOenal at gmail.com> + * Copyright (C) 2015 by Hayati Ayguen <h_ayguen at web.de> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -92,6 +93,13 @@ static int *atan_lut = NULL; static int atan_lut_size = 131072; /* 512 KB */ static int atan_lut_coef = 8; +static int verbosity = 0; +static int printLevels = 0; +static int printLevelNo = 1; +static int levelMax = 0; +static int levelMaxMax = 0; +static double levelSum = 0.0; + struct dongle_state { int exit_flag; @@ -187,16 +195,21 @@ void usage(void) "\t-f frequency_to_tune_to [Hz]\n" "\t use multiple -f for scanning (requires squelch)\n" "\t ranges supported, -f 118M:137M:25k\n" + "\t[-v verbosity (default: 0)]\n" "\t[-M modulation (default: fm)]\n" - "\t fm, wbfm, raw, am, usb, lsb\n" + "\t fm or nbfm or nfm, wbfm or wfm, raw or iq, am, usb, lsb\n" "\t wbfm == -M fm -s 170k -o 4 -A fast -r 32k -l 0 -E deemp\n" "\t raw mode outputs 2x16 bit IQ pairs\n" "\t[-s sample_rate (default: 24k)]\n" "\t[-d device_index (default: 0)]\n" "\t[-g tuner_gain (default: automatic)]\n" "\t[-l squelch_level (default: 0/off)]\n" + "\t[-L N prints levels every N calculations]\n" + "\t output are comma separated values (csv):\n" + "\t mean since last output, max since last output, overall max, squelch\n" + "\t[-c de-emphasis_time_constant in us for wbfm. 'us' or 'eu' for 75/50 us (default: us)]\n" //"\t for fm squelch is inverted\n" - //"\t[-o oversampling (default: 1, 4 recommended)]\n" + "\t[-o oversampling (default: 1, 4 recommended)]\n" "\t[-p ppm_error (default: 0)]\n" "\t[-E enable_option (default: none)]\n" "\t use multiple -E to enable multiple options\n" @@ -759,6 +772,24 @@ void full_demod(struct demod_state *d) } else { d->squelch_hits = 0;} } + + if (printLevels) { + if (!sr) + sr = rms(d->lowpassed, d->lp_len, 1); + --printLevelNo; + if (printLevels) { + levelSum += sr; + if (levelMax < sr) levelMax = sr; + if (levelMaxMax < sr) levelMaxMax = sr; + if (!printLevelNo) { + printLevelNo = printLevels; + fprintf(stderr, "%f, %d, %d, %d\n", (levelSum / printLevels), levelMax, levelMaxMax, d->squelch_level ); + levelMax = 0; + levelSum = 0; + } + } + } + d->mode_demod(d); /* lowpassed -> result */ if (d->mode_demod == &raw_demod) { return; @@ -864,9 +895,16 @@ static void optimal_settings(int freq, int rate) } capture_freq = freq; capture_rate = dm->downsample * dm->rate_in; + if (verbosity) + fprintf(stderr, "capture_rate = dm->downsample * dm->rate_in = %d * %d = %d\n", dm->downsample, dm->rate_in, capture_rate ); if (!d->offset_tuning) { - capture_freq = freq + capture_rate/4;} + capture_freq = freq + capture_rate/4; + if (verbosity) + fprintf(stderr, "optimal_settings(freq = %d): capture_freq = freq + capture_rate/4 = %d\n", freq, capture_freq ); + } capture_freq += cs->edge * dm->rate_in / 2; + if (verbosity) + fprintf(stderr, "optimal_settings(freq = %d): capture_freq += cs->edge * dm->rate_in / 2 = %d * %d / 2 = %d\n", freq, cs->edge, dm->rate_in, capture_freq ); dm->output_scale = (1<<15) / (128 * dm->downsample); if (dm->output_scale < 1) { dm->output_scale = 1;} @@ -874,6 +912,8 @@ static void optimal_settings(int freq, int rate) dm->output_scale = 1;} d->freq = (uint32_t)capture_freq; d->rate = (uint32_t)capture_rate; + if (verbosity) + fprintf(stderr, "optimal_settings(freq = %d) delivers freq %.0f, rate %.0f\n", freq, (double)d->freq, (double)d->rate ); } static void *controller_thread_fn(void *arg) @@ -884,6 +924,8 @@ static void *controller_thread_fn(void *arg) struct controller_state *s = arg; if (s->wb_mode) { + if (verbosity) + fprintf(stderr, "wbfm: adding 16000 Hz to every intput frequency\n"); for (i=0; i < s->freq_len; i++) { s->freqs[i] += 16000;} } @@ -896,6 +938,10 @@ static void *controller_thread_fn(void *arg) verbose_offset_tuning(dongle.dev);} /* Set the frequency */ + if (verbosity) { + fprintf(stderr, "verbose_set_frequency(%.0f Hz)\n", (double)dongle.freq); + fprintf(stderr, " frequency is away from parametrized one, to avoid negative impact from dc\n"); + } verbose_set_frequency(dongle.dev, dongle.freq); fprintf(stderr, "Oversampling input by: %ix.\n", demod.downsample); fprintf(stderr, "Oversampling output by: %ix.\n", demod.post_downsample); @@ -903,6 +949,8 @@ static void *controller_thread_fn(void *arg) 1000 * 0.5 * (float)ACTUAL_BUF_LENGTH / (float)dongle.rate); /* Set the sample rate */ + if (verbosity) + fprintf(stderr, "verbose_set_sample_rate(%.0f Hz)\n", (double)dongle.rate); verbose_set_sample_rate(dongle.dev, dongle.rate); fprintf(stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample); @@ -1042,12 +1090,13 @@ int main(int argc, char **argv) int r, opt; int dev_given = 0; int custom_ppm = 0; + int timeConstant = 75; /* default: U.S. 75 uS */ dongle_init(&dongle); demod_init(&demod); output_init(&output); controller_init(&controller); - while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:E:F:A:M:h")) != -1) { + while ((opt = getopt(argc, argv, "d:f:g:s:b:l:L:o:t:r:p:E:F:A:M:c:v:h")) != -1) { switch (opt) { case 'd': dongle.dev_index = verbose_device_search(optarg); @@ -1070,6 +1119,9 @@ int main(int argc, char **argv) case 'l': demod.squelch_level = (int)atof(optarg); break; + case 'L': + printLevels = (int)atof(optarg); + break; case 's': demod.rate_in = (uint32_t)atofs(optarg); demod.rate_out = (uint32_t)atofs(optarg); @@ -1121,9 +1173,9 @@ int main(int argc, char **argv) demod.custom_atan = 2;} break; case 'M': - if (strcmp("fm", optarg) == 0) { + if (strcmp("nbfm", optarg) == 0 || strcmp("nfm", optarg) == 0 || strcmp("fm", optarg) == 0) { demod.mode_demod = &fm_demod;} - if (strcmp("raw", optarg) == 0) { + if (strcmp("raw", optarg) == 0 || strcmp("iq", optarg) == 0) { demod.mode_demod = &raw_demod;} if (strcmp("am", optarg) == 0) { demod.mode_demod = &am_demod;} @@ -1131,7 +1183,7 @@ int main(int argc, char **argv) demod.mode_demod = &usb_demod;} if (strcmp("lsb", optarg) == 0) { demod.mode_demod = &lsb_demod;} - if (strcmp("wbfm", optarg) == 0) { + if (strcmp("wbfm", optarg) == 0 || strcmp("wfm", optarg) == 0) { controller.wb_mode = 1; demod.mode_demod = &fm_demod; demod.rate_in = 170000; @@ -1142,6 +1194,17 @@ int main(int argc, char **argv) demod.deemph = 1; demod.squelch_level = 0;} break; + case 'c': + if (strcmp("us", optarg) == 0) + timeConstant = 75; + else if (strcmp("eu", optarg) == 0) + timeConstant = 50; + else + timeConstant = (int)atof(optarg); + break; + case 'v': + verbosity = (int)atof(optarg); + break; case 'h': default: usage(); @@ -1194,7 +1257,10 @@ int main(int argc, char **argv) #endif if (demod.deemph) { - demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6))))); + double tc = (double)timeConstant * 1e-6; + demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * tc))))); + if (verbosity) + fprintf(stderr, "using wbfm deemphasis filter with time constant %d us\n", timeConstant ); } /* Set the tuner gain */ -- 1.9.5.msysgit.1 -------------- next part -------------- From f5c7ad917134cdf7961ad801685d120521ab1d3d Mon Sep 17 00:00:00 2001 From: Hayati Ayguen <h_ayguen at web.de> Date: Sat, 18 Jul 2015 15:40:33 +0200 Subject: [PATCH 2/2] added dc filter on raw data (after decimation) with option "-E rdc" added option "-q" for setting averaging speed added option "-E adc" in addition to "-E dc" --- src/rtl_fm.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/src/rtl_fm.c b/src/rtl_fm.c index 8cf95f0..f607e4e 100644 --- a/src/rtl_fm.c +++ b/src/rtl_fm.c @@ -146,7 +146,8 @@ struct demod_state int deemph, deemph_a; int now_lpr; int prev_lpr_index; - int dc_block, dc_avg; + int dc_block_audio, dc_avg, adc_block_const; + int dc_block_raw, dc_avgI, dc_avgQ, rdc_block_const; void (*mode_demod)(struct demod_state*); pthread_rwlock_t rw; pthread_cond_t ready; @@ -214,10 +215,13 @@ 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 rdc: enable dc blocking filter on raw I/Q data\n" + "\t adc: enable dc blocking filter on demodulated audio\n" + "\t dc: same as adc\n" "\t deemp: enable de-emphasis filter\n" "\t direct: enable direct sampling\n" "\t offset: enable offset tuning\n" + "\t[-q dc_avg_factor for option rdc (default: 9)]\n" "\tfilename ('-' means stdout)\n" "\t omitting the filename also uses stdout\n\n" "Experimental options:\n" @@ -623,7 +627,7 @@ void deemph_filter(struct demod_state *fm) } } -void dc_block_filter(struct demod_state *fm) +void dc_block_audio_filter(struct demod_state *fm) { int i, avg; int64_t sum = 0; @@ -631,13 +635,37 @@ void dc_block_filter(struct demod_state *fm) sum += fm->result[i]; } avg = sum / fm->result_len; - avg = (avg + fm->dc_avg * 9) / 10; + avg = (avg + fm->dc_avg * fm->adc_block_const) / ( fm->adc_block_const + 1 ); for (i=0; i < fm->result_len; i++) { fm->result[i] -= avg; } fm->dc_avg = avg; } +void dc_block_raw_filter(struct demod_state *fm) +{ + /* derived from dc_block_audio_filter, + running over the raw I/Q components + */ + int16_t *lp = fm->lowpassed; + int i, avgI, avgQ; + int64_t sumI = 0; + int64_t sumQ = 0; + for (i = 0; i < fm->lp_len; i += 2) { + sumI += lp[i]; + sumQ += lp[i+1]; + } + avgI = sumI / ( fm->lp_len / 2 ); + avgQ = sumQ / ( fm->lp_len / 2 ); + avgI = (avgI + fm->dc_avgI * fm->rdc_block_const) / ( fm->rdc_block_const + 1 ); + avgQ = (avgQ + fm->dc_avgQ * fm->rdc_block_const) / ( fm->rdc_block_const + 1 ); + for (i = 0; i < fm->lp_len; i += 2) { + lp[i] -= avgI; + lp[i+1] -= avgQ; + } + fm->dc_avgI = avgI; + fm->dc_avgQ = avgQ; +} int mad(int16_t *samples, int len, int step) /* mean average deviation */ { @@ -789,7 +817,9 @@ void full_demod(struct demod_state *d) } } } - + if (d->dc_block_raw) { + dc_block_raw_filter(d); + } d->mode_demod(d); /* lowpassed -> result */ if (d->mode_demod == &raw_demod) { return; @@ -800,8 +830,8 @@ void full_demod(struct demod_state *d) d->result_len = low_pass_simple(d->result, d->result_len, d->post_downsample);} if (d->deemph) { deemph_filter(d);} - if (d->dc_block) { - dc_block_filter(d);} + if (d->dc_block_audio) { + dc_block_audio_filter(d);} if (d->rate_out2 > 0) { low_pass_real(d); //arbitrary_resample(d->result, d->result, d->result_len, d->result_len * d->rate_out2 / d->rate_out); @@ -1017,8 +1047,13 @@ 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_audio = 0; s->dc_avg = 0; + s->adc_block_const = 9; + s->dc_block_raw = 0; + s->dc_avgI = 0; + s->dc_avgQ = 0; + s->rdc_block_const = 9; pthread_rwlock_init(&s->rw, NULL); pthread_cond_init(&s->ready, NULL); pthread_mutex_init(&s->ready_m, NULL); @@ -1096,7 +1131,7 @@ int main(int argc, char **argv) output_init(&output); controller_init(&controller); - while ((opt = getopt(argc, argv, "d:f:g:s:b:l:L:o:t:r:p:E:F:A:M:c:v:h")) != -1) { + while ((opt = getopt(argc, argv, "d:f:g:s:b:l:L:o:t:r:p:E:q:F:A:M:c:v:h")) != -1) { switch (opt) { case 'd': dongle.dev_index = verbose_device_search(optarg); @@ -1150,8 +1185,10 @@ 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("dc", optarg) == 0 || strcmp("adc", optarg) == 0) { + demod.dc_block_audio = 1;} + if (strcmp("rdc", optarg) == 0) { + demod.dc_block_raw = 1;} if (strcmp("deemp", optarg) == 0) { demod.deemph = 1;} if (strcmp("direct", optarg) == 0) { @@ -1159,6 +1196,9 @@ int main(int argc, char **argv) if (strcmp("offset", optarg) == 0) { dongle.offset_tuning = 1;} break; + case 'q': + demod.rdc_block_const = atoi(optarg); + break; case 'F': demod.downsample_passes = 1; /* truthy placeholder */ demod.comp_fir_size = atoi(optarg); -- 1.9.5.msysgit.1