/* FM Demodulation Copyright 2019 Ahmet Inan */ #pragma once namespace DSP { template class FMD1 { typedef TYPE complex_type; typedef typename complex_type::value_type value_type; value_type prev; value_type scale; value_type wrap_around(value_type angle) { if (angle < -DSP::Const::Pi()) return angle + DSP::Const::TwoPi(); if (angle > DSP::Const::Pi()) return angle - DSP::Const::TwoPi(); return angle; } public: constexpr FMD1() : prev(0), scale(0) { } void bandwidth(value_type bw) { scale = value_type(1) / (bw * DSP::Const::Pi()); } value_type operator()(complex_type input) { value_type phase = arg(input); value_type delta = phase - prev; delta = wrap_around(delta); prev = phase; return scale * delta; } }; template class FMD2 { typedef TYPE complex_type; typedef typename complex_type::value_type value_type; complex_type prev; value_type scale; public: constexpr FMD2() : prev(1, 0), scale(0) { } void bandwidth(value_type bw) { scale = value_type(1) / (bw * DSP::Const::Pi()); } value_type operator()(complex_type input) { value_type phase = arg(input / prev); prev = input; return scale * phase; } }; template class FMD3 { typedef TYPE complex_type; typedef typename complex_type::value_type value_type; complex_type prev; value_type scale; public: constexpr FMD3() : prev(1, 0), scale(0) { } void bandwidth(value_type bw) { scale = value_type(1) / (bw * DSP::Const::Pi()); } value_type operator()(complex_type input) { value_type phase = arg(input * conj(prev)); prev = input; return scale * phase; } }; template class FMD4 { typedef TYPE complex_type; typedef typename complex_type::value_type value_type; complex_type prev; value_type scale; public: constexpr FMD4() : prev(1, 0), scale(0) { } void bandwidth(value_type bw) { scale = value_type(1) / (bw * DSP::Const::Pi()); } value_type operator()(complex_type input) { value_type phase = prev.real() * input.imag() - prev.imag() * input.real(); phase /= norm(input); prev = input; return scale * phase; } }; template class FMD5 { typedef TYPE complex_type; typedef typename complex_type::value_type value_type; complex_type prev1, prev2; value_type scale; public: constexpr FMD5() : prev1(1, 0), prev2(1, 0), scale(0) { } void bandwidth(value_type bw) { scale = value_type(1) / (bw * DSP::Const::TwoPi()); } value_type operator()(complex_type input) { complex_type diff = input - prev2; value_type phase = prev1.real() * diff.imag() - prev1.imag() * diff.real(); phase /= norm(prev1); prev2 = prev1; prev1 = input; return scale * phase; } }; }