From f6bca05bf0ee3ec9e491a3692045b79b3a34f2d7 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Sun, 19 Jan 2014 12:19:19 +0100 Subject: [PATCH] Prepare pilot PLL to produce PPS events. --- FmDecode.cc | 35 ++++++++++++++++++++++++++++++++++- FmDecode.h | 30 +++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/FmDecode.cc b/FmDecode.cc index 566f9ac..9735479 100644 --- a/FmDecode.cc +++ b/FmDecode.cc @@ -134,6 +134,11 @@ PilotPhaseLock::PilotPhaseLock(double freq, double bandwidth, double minsignal) m_phasor_q1 = 0; m_phasor_q2 = 0; m_loopfilter_x1 = 0; + + // Initialize PPS generator. + m_pilot_periods = 0; + m_pps_cnt = 0; + m_sample_cnt = 0; } @@ -145,6 +150,9 @@ void PilotPhaseLock::process(const SampleVector& samples_in, samples_out.resize(n); + bool was_locked = (m_lock_cnt >= m_lock_delay); + m_pps_events.clear(); + if (n > 0) m_pilot_level = 1000.0; @@ -202,8 +210,23 @@ void PilotPhaseLock::process(const SampleVector& samples_in, // Update locked phase. m_phase += m_freq; - if (m_phase > 2.0 * M_PI) + if (m_phase > 2.0 * M_PI) { m_phase -= 2.0 * M_PI; + m_pilot_periods++; + + // Generate pulse-per-second. + if (m_pilot_periods == pilot_frequency) { + 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; + m_pps_events.push_back(ev); + m_pps_cnt++; + } + } + } } // Update lock status. @@ -213,6 +236,16 @@ void PilotPhaseLock::process(const SampleVector& samples_in, } else { m_lock_cnt = 0; } + + // Drop PPS events when pilot not locked. + if (m_lock_cnt < m_lock_delay) { + m_pilot_periods = 0; + m_pps_cnt = 0; + m_pps_events.clear(); + } + + // Update sample counter. + m_sample_cnt += n; } diff --git a/FmDecode.h b/FmDecode.h index 053cb1c..0f645f2 100644 --- a/FmDecode.h +++ b/FmDecode.h @@ -1,6 +1,9 @@ #ifndef SOFTFM_FMDECODE_H #define SOFTFM_FMDECODE_H +#include +#include + #include "SoftFM.h" #include "Filter.h" @@ -36,7 +39,16 @@ class PilotPhaseLock { public: -// TODO : pulse-per-second + /** Expected pilot frequency (used for PPS events). */ + static constexpr int pilot_frequency = 19000; + + /** Timestamp event produced once every 19000 pilot periods. */ + struct PpsEvent + { + std::uint64_t pps_index; + std::uint64_t abs_sample_index; + std::uint64_t block_sample_index; + }; /** * Construct phase-locked loop. @@ -66,6 +78,12 @@ public: return 2 * m_pilot_level; } + /** Return PPS events from the most recently processed block. */ + std::vector get_pps_events() const + { + return m_pps_events; + } + private: Sample m_minfreq, m_maxfreq; Sample m_phasor_b0, m_phasor_a1, m_phasor_a2; @@ -77,6 +95,10 @@ private: Sample m_pilot_level; int m_lock_delay; int m_lock_cnt; + int m_pilot_periods; + std::uint64_t m_pps_cnt; + std::uint64_t m_sample_cnt; + std::vector m_pps_events; }; @@ -163,6 +185,12 @@ public: return m_pilotpll.get_pilot_level(); } + /** Return PPS events from the most recently processed block. */ + std::vector get_pps_events() const + { + return m_pilotpll.get_pps_events(); + } + private: /** Demodulate stereo L-R signal. */ void demod_stereo(const SampleVector& samples_baseband,