From 1e881703e8f17d17399cbad1fdc28fe87da23501 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 19 Dec 2016 02:41:31 +0100 Subject: [PATCH] Added a NCO with floating point phase calculation before conversion to int for table indexing. This increases frequency precision and is mandatory for CTCSS tone generator --- CMakeLists.txt | 2 + sdrbase/dsp/ncof.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++ sdrbase/dsp/ncof.h | 62 +++++++++++++++++++++++++++++ sdrbase/sdrbase.pro | 2 + 4 files changed, 158 insertions(+) create mode 100644 sdrbase/dsp/ncof.cpp create mode 100644 sdrbase/dsp/ncof.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b39960963..6c380de0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,7 @@ set(sdrbase_SOURCES sdrbase/dsp/lowpass.cpp sdrbase/dsp/movingaverage.cpp sdrbase/dsp/nco.cpp + sdrbase/dsp/ncof.cpp sdrbase/dsp/pidcontroller.cpp sdrbase/dsp/phaselock.cpp sdrbase/dsp/samplesinkfifo.cpp @@ -225,6 +226,7 @@ set(sdrbase_HEADERS sdrbase/dsp/misc.h sdrbase/dsp/movingaverage.h sdrbase/dsp/nco.h + sdrbase/dsp/ncof.h sdrbase/dsp/phasediscri.h sdrbase/dsp/phaselock.h sdrbase/dsp/pidcontroller.h diff --git a/sdrbase/dsp/ncof.cpp b/sdrbase/dsp/ncof.cpp new file mode 100644 index 000000000..c63206c81 --- /dev/null +++ b/sdrbase/dsp/ncof.cpp @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// // +// 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 // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#define _USE_MATH_DEFINES +#include +#include "dsp/ncof.h" + +Real NCOF::m_table[NCOF::TableSize]; +bool NCOF::m_tableInitialized = false; + +void NCOF::initTable() +{ + if(m_tableInitialized) + return; + + for(int i = 0; i < TableSize; i++) + m_table[i] = cos((2.0 * M_PI * i) / TableSize); + + m_tableInitialized = true; +} + +NCOF::NCOF() +{ + initTable(); + m_phase = 0.0f; +} + +void NCOF::setFreq(Real freq, Real sampleRate) +{ + m_phaseIncrement = (freq * TableSize) / sampleRate; + qDebug("NCO freq: %f phase inc %f", freq, m_phaseIncrement); +} + +float NCOF::next() +{ + int phase = nextPhase(); + return m_table[phase]; +} + +Complex NCOF::nextIQ() +{ + int phase = nextPhase(); + return Complex(m_table[phase], -m_table[(phase + TableSize / 4) % TableSize]); +} + +Complex NCOF::nextQI() +{ + int phase = nextPhase(); + return Complex(-m_table[(phase + TableSize / 4) % TableSize], m_table[phase]); +} + +float NCOF::get() +{ + return m_table[(int) m_phase]; +} + +Complex NCOF::getIQ() +{ + return Complex(m_table[(int) m_phase], -m_table[((int) m_phase + TableSize / 4) % TableSize]); +} + +void NCOF::getIQ(Complex& c) +{ + c.real(m_table[(int) m_phase]); + c.imag(-m_table[((int) m_phase + TableSize / 4) % TableSize]); +} + +Complex NCOF::getQI() +{ + return Complex(-m_table[((int) m_phase + TableSize / 4) % TableSize], m_table[(int) m_phase]); +} + +void NCOF::getQI(Complex& c) +{ + c.imag(m_table[(int) m_phase]); + c.real(-m_table[((int) m_phase + TableSize / 4) % TableSize]); +} diff --git a/sdrbase/dsp/ncof.h b/sdrbase/dsp/ncof.h new file mode 100644 index 000000000..349541809 --- /dev/null +++ b/sdrbase/dsp/ncof.h @@ -0,0 +1,62 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// // +// 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 // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_NCOF_H +#define INCLUDE_NCOF_H + +#include "dsp/dsptypes.h" +#include "util/export.h" + +class SDRANGEL_API NCOF { +private: + enum { + TableSize = (1 << 12), + }; + static Real m_table[TableSize]; + static bool m_tableInitialized; + + static void initTable(); + + Real m_phaseIncrement; + Real m_phase; + +public: + NCOF(); + + void setFreq(Real freq, Real sampleRate); + void setPhase(Real phase) { m_phase = phase; } + + int nextPhase() //!< Increment phase and return its integer value + { + m_phase += m_phaseIncrement; + while(m_phase >= TableSize) + m_phase -= TableSize; + while(m_phase < 0) + m_phase += TableSize; + return (int) m_phase; + } + + Real next(); //!< Return next real sample + Complex nextIQ(); //!< Return next complex sample + Complex nextQI(); //!< Return next complex sample (reversed) + Real get(); //!< Return current real sample (no phase increment) + Complex getIQ(); //!< Return current complex sample (no phase increment) + void getIQ(Complex& c); //!< Sets to the current complex sample (no phase increment) + Complex getQI(); //!< Return current complex sample (no phase increment, reversed) + void getQI(Complex& c); //!< Sets to the current complex sample (no phase increment, reversed) +}; + +#endif // INCLUDE_NCO_H diff --git a/sdrbase/sdrbase.pro b/sdrbase/sdrbase.pro index 801126768..3423cf11c 100644 --- a/sdrbase/sdrbase.pro +++ b/sdrbase/sdrbase.pro @@ -62,6 +62,7 @@ SOURCES += mainwindow.cpp\ dsp/lowpass.cpp\ dsp/movingaverage.cpp\ dsp/nco.cpp\ + dsp/ncof.cpp\ dsp/pidcontroller.cpp\ dsp/phaselock.cpp\ dsp/samplesinkfifo.cpp\ @@ -159,6 +160,7 @@ HEADERS += mainwindow.h\ dsp/misc.h\ dsp/movingaverage.h\ dsp/nco.h\ + dsp/ncof.h\ dsp/phasediscri.h\ dsp/phaselock.h\ dsp/pidcontroller.h\