From 6d735bb0f017038a9b9d1201e424278cec40d57e Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Sun, 19 Jan 2014 15:49:43 +0100 Subject: [PATCH] Pilot PPS logging works. --- FmDecode.cc | 6 ++--- FmDecode.h | 4 ++-- TODO.txt | 1 - main.cc | 68 +++++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/FmDecode.cc b/FmDecode.cc index 9735479..a8ac7c9 100644 --- a/FmDecode.cc +++ b/FmDecode.cc @@ -219,9 +219,9 @@ void PilotPhaseLock::process(const SampleVector& samples_in, m_pilot_periods = 0; if (was_locked) { struct PpsEvent ev; - ev.pps_index = m_pps_cnt; - ev.abs_sample_index = m_sample_cnt + i; - ev.block_sample_index = i; + ev.pps_index = m_pps_cnt; + ev.sample_index = m_sample_cnt + i; + ev.block_position = double(i) / double(n); m_pps_events.push_back(ev); m_pps_cnt++; } diff --git a/FmDecode.h b/FmDecode.h index 0f645f2..f41e33a 100644 --- a/FmDecode.h +++ b/FmDecode.h @@ -46,8 +46,8 @@ public: struct PpsEvent { std::uint64_t pps_index; - std::uint64_t abs_sample_index; - std::uint64_t block_sample_index; + std::uint64_t sample_index; + double block_position; }; /** diff --git a/TODO.txt b/TODO.txt index 6938810..e13f8b7 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,4 +1,3 @@ -* (feature) implement stereo pilot pulse-per-second * (speedup) maybe replace high-order FIR downsampling filter with 2nd order butterworth followed by lower order FIR filter * figure out why we sometimes lose stereo lock * (feature) implement RDS decoding diff --git a/main.cc b/main.cc index 0736f01..37a3353 100644 --- a/main.cc +++ b/main.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include "SoftFM.h" #include "RtlSdrSource.h" @@ -212,7 +213,7 @@ static void handle_sigterm(int sig) void usage() { fprintf(stderr, - "Usage: softfm -f freq [options]\n" + "Usage: softfm -f freq [options]\n" " -f freq Frequency of radio station in Hz\n" " -d devidx RTL-SDR device index, 'list' to show device list (default 0)\n" " -s ifrate IF sample rate in Hz (default 1000000, min 900001)\n" @@ -223,6 +224,8 @@ void usage() " use filename '-' to write to stdout\n" " -W filename Write audio data to .WAV file\n" " -P [device] Play audio via ALSA device (default 'default')\n" + " -T filename Write pulse-per-second timestamps\n" + " use filename '-' to write to stdout\n" " -b seconds Set audio buffer size in seconds\n" "\n"); } @@ -274,6 +277,15 @@ bool parse_dbl(const char *s, double& v) } +/** Return Unix time stamp in seconds. */ +double get_time() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + 1.0e-6 * tv.tv_usec; +} + + int main(int argc, char **argv) { double freq = -1; @@ -285,6 +297,8 @@ int main(int argc, char **argv) OutputMode outmode = MODE_ALSA; string filename; string alsadev("default"); + string ppsfilename; + FILE * ppsfile = NULL; double bufsecs = -1; int agcmode = 1; @@ -301,12 +315,13 @@ int main(int argc, char **argv) { "raw", 1, NULL, 'R' }, { "wav", 1, NULL, 'W' }, { "play", 2, NULL, 'P' }, + { "pps", 1, NULL, 'T' }, { "buffer", 1, NULL, 'b' }, { NULL, 0, NULL, 0 } }; int c, longindex; while ((c = getopt_long(argc, argv, - "f:d:s:r:MR:W:P::b:a:", + "f:d:s:r:MR:W:P::T:b:a:", longopts, &longindex)) >= 0) { switch (c) { case 'f': @@ -345,6 +360,9 @@ int main(int argc, char **argv) if (optarg != NULL) alsadev = optarg; break; + case 'T': + ppsfilename = optarg; + break; case 'b': if (!parse_dbl(optarg, bufsecs) || bufsecs < 0) { badarg("-b"); @@ -469,6 +487,25 @@ int main(int argc, char **argv) outputbuf_samples / double(pcmrate)); } + // Open PPS file. + if (!ppsfilename.empty()) { + if (ppsfilename == "-") { + fprintf(stderr, "Writing pulse-per-second markers to stdout\n"); + ppsfile = stdout; + } else { + fprintf(stderr, "Writing pulse-per-second markers to '%s'\n", + ppsfilename.c_str()); + ppsfile = fopen(ppsfilename.c_str(), "w"); + if (ppsfile == NULL) { + fprintf(stderr, "ERROR: can not open '%s' (%s)\n", + ppsfilename.c_str(), strerror(errno)); + exit(1); + } + } + fprintf(ppsfile, "#pps_index sample_index unix_time\n"); + fflush(ppsfile); + } + // Prepare output writer. unique_ptr audio_output; switch (outmode) { @@ -511,6 +548,8 @@ int main(int argc, char **argv) double audio_level = 0; bool got_stereo = false; + double block_time = get_time(); + // Main loop. for (unsigned int block = 0; !stop_flag.load(); block++) { @@ -527,6 +566,9 @@ int main(int argc, char **argv) if (iqsamples.empty()) break; + double prev_block_time = block_time; + block_time = get_time(); + // Decode FM signal. fm.process(iqsamples, audiosamples); @@ -535,10 +577,10 @@ int main(int argc, char **argv) samples_mean_rms(audiosamples, audio_mean, audio_rms); audio_level = 0.95 * audio_level + 0.05 * audio_rms; + // Set nominal audio volume. adjust_gain(audiosamples, 0.5); -// TODO : investigate I/Q imbalance to fix Radio4 noise - + // Show statistics. fprintf(stderr, "\rblk=%6d freq=%8.4fMHz IF=%+5.1fdB BB=%+5.1fdB audio=%+5.1fdB ", block, @@ -555,6 +597,7 @@ int main(int argc, char **argv) } fflush(stderr); + // Show stereo status. if (fm.stereo_detected() != got_stereo) { got_stereo = fm.stereo_detected(); if (got_stereo) @@ -564,6 +607,23 @@ int main(int argc, char **argv) fprintf(stderr, "\nlost stereo signal\n"); } + // Write PPS markers. + if (ppsfile != NULL) { + for (const PilotPhaseLock::PpsEvent& ev : fm.get_pps_events()) { + double ts = prev_block_time; + ts += ev.block_position * (block_time - prev_block_time); + if (ppsfile == stdout && isatty(fileno(ppsfile))) { + fprintf(stderr, "\n"); + fflush(stderr); + } + fprintf(ppsfile, "%8s %14s %18.6f\n", + to_string(ev.pps_index).c_str(), + to_string(ev.sample_index).c_str(), + ts); + fflush(ppsfile); + } + } + // Throw away first block. It is noisy because IF filters // are still starting up. if (block > 0) {