From 9fff2b847784b47baeb00ce22e6785e47cada927 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 20 Oct 2016 19:34:30 +0200 Subject: [PATCH] Tx ph.1: new AM modulator plugin (3). Implemented actual modulation code. --- plugins/channeltx/modam/ammod.cpp | 41 ++++++++++++++++++++++------ plugins/channeltx/modam/ammod.h | 13 +++++---- plugins/channeltx/modam/ammodgui.cpp | 2 +- sdrbase/dsp/nco.cpp | 30 ++++++++++++-------- sdrbase/dsp/nco.h | 17 ++++++++++-- 5 files changed, 74 insertions(+), 29 deletions(-) diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index 141e229a0..8242d87e5 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -35,7 +36,7 @@ AMMod::AMMod() : m_config.m_inputFrequencyOffset = 0; m_config.m_rfBandwidth = 12500; m_config.m_afBandwidth = 3000; - m_config.m_modPercent = 20; + m_config.m_modFactor = 20; m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); apply(); @@ -46,6 +47,8 @@ AMMod::AMMod() : m_movingAverage.resize(16, 0); m_volumeAGC.resize(4096, 0.003, 0); m_magsq = 0.0; + + m_toneNco.setFreq(1000.0, m_config.m_audioSampleRate); } AMMod::~AMMod() @@ -60,7 +63,30 @@ void AMMod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandw void AMMod::pull(Sample& sample) { - // TODO + Complex ci; + + if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, m_modSample, &ci)) + { + m_settingsMutex.lock(); + m_carrierNco.nextPhase(); + m_toneNco.nextPhase(); + m_settingsMutex.unlock(); + + m_carrierNco.getIQ(m_modSample); + Real t = m_toneNco.get(); + + m_modSample *= (t+1.0f) * m_running.m_modFactor * 16384.0f; // modulate carrier + + m_interpolatorDistanceRemain += m_interpolatorDistance; + } + + Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag(); + magsq /= (1<<30); + m_movingAverage.feed(magsq); + m_magsq = m_movingAverage.average(); + + sample.m_real = (FixReal) ci.real(); + sample.m_imag = (FixReal) ci.imag(); } void AMMod::start() @@ -100,7 +126,7 @@ bool AMMod::handleMessage(const Message& cmd) m_config.m_rfBandwidth = cfg.getRFBandwidth(); m_config.m_afBandwidth = cfg.getAFBandwidth(); - m_config.m_modPercent = cfg.getModPercent(); + m_config.m_modFactor = cfg.getModFactor(); m_config.m_audioMute = cfg.getAudioMute(); apply(); @@ -108,7 +134,7 @@ bool AMMod::handleMessage(const Message& cmd) qDebug() << "AMMod::handleMessage: MsgConfigureAMMod:" << " m_rfBandwidth: " << m_config.m_rfBandwidth << " m_afBandwidth: " << m_config.m_afBandwidth - << " m_modPercent: " << m_config.m_modPercent + << " m_modFactor: " << m_config.m_modFactor << " m_audioMute: " << m_config.m_audioMute; return true; @@ -122,10 +148,9 @@ bool AMMod::handleMessage(const Message& cmd) void AMMod::apply() { - if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || - (m_config.m_outputSampleRate != m_running.m_outputSampleRate)) + if(m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) { - m_carrierNco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_outputSampleRate); + m_carrierNco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_audioSampleRate); } if((m_config.m_outputSampleRate != m_running.m_outputSampleRate) || @@ -150,7 +175,7 @@ void AMMod::apply() m_running.m_inputFrequencyOffset = m_config.m_inputFrequencyOffset; m_running.m_rfBandwidth = m_config.m_rfBandwidth; m_running.m_afBandwidth = m_config.m_afBandwidth; - m_running.m_modPercent = m_config.m_modPercent; + m_running.m_modFactor = m_config.m_modFactor; m_running.m_audioSampleRate = m_config.m_audioSampleRate; m_running.m_audioMute = m_config.m_audioMute; } diff --git a/plugins/channeltx/modam/ammod.h b/plugins/channeltx/modam/ammod.h index 4af515e35..417894880 100644 --- a/plugins/channeltx/modam/ammod.h +++ b/plugins/channeltx/modam/ammod.h @@ -51,7 +51,7 @@ private: public: Real getRFBandwidth() const { return m_rfBandwidth; } Real getAFBandwidth() const { return m_afBandwidth; } - Real getModPercent() const { return m_modPercent; } + float getModFactor() const { return m_modFactor; } bool getAudioMute() const { return m_audioMute; } static MsgConfigureAMMod* create(Real rfBandwidth, Real afBandwidth, int modPercent, bool audioMute) @@ -62,14 +62,14 @@ private: private: Real m_rfBandwidth; Real m_afBandwidth; - Real m_modPercent; + float m_modFactor; bool m_audioMute; - MsgConfigureAMMod(Real rfBandwidth, Real afBandwidth, int modPercent, bool audioMute) : + MsgConfigureAMMod(Real rfBandwidth, Real afBandwidth, float modFactor, bool audioMute) : Message(), m_rfBandwidth(rfBandwidth), m_afBandwidth(afBandwidth), - m_modPercent(modPercent), + m_modFactor(modFactor), m_audioMute(audioMute) { } }; @@ -90,7 +90,7 @@ private: qint64 m_inputFrequencyOffset; Real m_rfBandwidth; Real m_afBandwidth; - int m_modPercent; + float m_modFactor; quint32 m_audioSampleRate; bool m_audioMute; @@ -99,7 +99,7 @@ private: m_inputFrequencyOffset(0), m_rfBandwidth(-1), m_afBandwidth(-1), - m_modPercent(20), + m_modFactor(0.2f), m_audioSampleRate(0), m_audioMute(false) { } @@ -110,6 +110,7 @@ private: NCO m_carrierNco; NCO m_toneNco; + Complex m_modSample; Interpolator m_interpolator; Real m_interpolatorDistance; Real m_interpolatorDistanceRemain; diff --git a/plugins/channeltx/modam/ammodgui.cpp b/plugins/channeltx/modam/ammodgui.cpp index a5c223d68..19f5821d0 100644 --- a/plugins/channeltx/modam/ammodgui.cpp +++ b/plugins/channeltx/modam/ammodgui.cpp @@ -278,7 +278,7 @@ void AMModGUI::applySettings() m_amMod->configure(m_amMod->getInputMessageQueue(), m_rfBW[ui->rfBW->value()], ui->afBW->value() * 1000.0, - ui->modPercent->value(), + ui->modPercent->value() / 100.0f, ui->audioMute->isChecked()); } } diff --git a/sdrbase/dsp/nco.cpp b/sdrbase/dsp/nco.cpp index 1143cf89f..5b0ebb90d 100644 --- a/sdrbase/dsp/nco.cpp +++ b/sdrbase/dsp/nco.cpp @@ -49,22 +49,28 @@ void NCO::setFreq(Real freq, Real sampleRate) float NCO::next() { - m_phase += m_phaseIncrement; - while(m_phase >= TableSize) - m_phase -= TableSize; - while(m_phase < 0) - m_phase += TableSize; - + nextPhase(); return m_table[m_phase]; } Complex NCO::nextIQ() { - m_phase += m_phaseIncrement; - while(m_phase >= TableSize) - m_phase -= TableSize; - while(m_phase < 0) - m_phase += TableSize; - + nextPhase(); return Complex(m_table[m_phase], -m_table[(m_phase + TableSize / 4) % TableSize]); } + +float NCO::get() +{ + return m_table[m_phase]; +} + +Complex NCO::getIQ() +{ + return Complex(m_table[m_phase], -m_table[(m_phase + TableSize / 4) % TableSize]); +} + +void NCO::getIQ(Complex& c) +{ + c.real(m_table[m_phase]); + c.imag(-m_table[(m_phase + TableSize / 4) % TableSize]); +} diff --git a/sdrbase/dsp/nco.h b/sdrbase/dsp/nco.h index 7a0ed9c81..8b3f0317d 100644 --- a/sdrbase/dsp/nco.h +++ b/sdrbase/dsp/nco.h @@ -38,8 +38,21 @@ public: NCO(); void setFreq(Real freq, Real sampleRate); - Real next(); - Complex nextIQ(); + + void nextPhase() //!< Increment phase + { + m_phase += m_phaseIncrement; + while(m_phase >= TableSize) + m_phase -= TableSize; + while(m_phase < 0) + m_phase += TableSize; + } + + Real next(); //!< Return next real sample + Complex nextIQ(); //!< Return next complex sample + 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) }; #endif // INCLUDE_NCO_H