1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-09-02 13:17:48 -04:00

Tx ph.1: new AM modulator plugin (3). Implemented actual modulation code.

This commit is contained in:
f4exb 2016-10-20 19:34:30 +02:00
parent c28751124c
commit 9fff2b8477
5 changed files with 74 additions and 29 deletions

View File

@ -18,6 +18,7 @@
#include <QTime> #include <QTime>
#include <QDebug> #include <QDebug>
#include <QMutexLocker>
#include <stdio.h> #include <stdio.h>
#include <complex.h> #include <complex.h>
#include <dsp/upchannelizer.h> #include <dsp/upchannelizer.h>
@ -35,7 +36,7 @@ AMMod::AMMod() :
m_config.m_inputFrequencyOffset = 0; m_config.m_inputFrequencyOffset = 0;
m_config.m_rfBandwidth = 12500; m_config.m_rfBandwidth = 12500;
m_config.m_afBandwidth = 3000; m_config.m_afBandwidth = 3000;
m_config.m_modPercent = 20; m_config.m_modFactor = 20;
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
apply(); apply();
@ -46,6 +47,8 @@ AMMod::AMMod() :
m_movingAverage.resize(16, 0); m_movingAverage.resize(16, 0);
m_volumeAGC.resize(4096, 0.003, 0); m_volumeAGC.resize(4096, 0.003, 0);
m_magsq = 0.0; m_magsq = 0.0;
m_toneNco.setFreq(1000.0, m_config.m_audioSampleRate);
} }
AMMod::~AMMod() AMMod::~AMMod()
@ -60,7 +63,30 @@ void AMMod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandw
void AMMod::pull(Sample& sample) 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() void AMMod::start()
@ -100,7 +126,7 @@ bool AMMod::handleMessage(const Message& cmd)
m_config.m_rfBandwidth = cfg.getRFBandwidth(); m_config.m_rfBandwidth = cfg.getRFBandwidth();
m_config.m_afBandwidth = cfg.getAFBandwidth(); m_config.m_afBandwidth = cfg.getAFBandwidth();
m_config.m_modPercent = cfg.getModPercent(); m_config.m_modFactor = cfg.getModFactor();
m_config.m_audioMute = cfg.getAudioMute(); m_config.m_audioMute = cfg.getAudioMute();
apply(); apply();
@ -108,7 +134,7 @@ bool AMMod::handleMessage(const Message& cmd)
qDebug() << "AMMod::handleMessage: MsgConfigureAMMod:" qDebug() << "AMMod::handleMessage: MsgConfigureAMMod:"
<< " m_rfBandwidth: " << m_config.m_rfBandwidth << " m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_afBandwidth: " << m_config.m_afBandwidth << " m_afBandwidth: " << m_config.m_afBandwidth
<< " m_modPercent: " << m_config.m_modPercent << " m_modFactor: " << m_config.m_modFactor
<< " m_audioMute: " << m_config.m_audioMute; << " m_audioMute: " << m_config.m_audioMute;
return true; return true;
@ -122,10 +148,9 @@ bool AMMod::handleMessage(const Message& cmd)
void AMMod::apply() void AMMod::apply()
{ {
if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || if(m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset)
(m_config.m_outputSampleRate != m_running.m_outputSampleRate))
{ {
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) || 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_inputFrequencyOffset = m_config.m_inputFrequencyOffset;
m_running.m_rfBandwidth = m_config.m_rfBandwidth; m_running.m_rfBandwidth = m_config.m_rfBandwidth;
m_running.m_afBandwidth = m_config.m_afBandwidth; 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_audioSampleRate = m_config.m_audioSampleRate;
m_running.m_audioMute = m_config.m_audioMute; m_running.m_audioMute = m_config.m_audioMute;
} }

View File

@ -51,7 +51,7 @@ private:
public: public:
Real getRFBandwidth() const { return m_rfBandwidth; } Real getRFBandwidth() const { return m_rfBandwidth; }
Real getAFBandwidth() const { return m_afBandwidth; } Real getAFBandwidth() const { return m_afBandwidth; }
Real getModPercent() const { return m_modPercent; } float getModFactor() const { return m_modFactor; }
bool getAudioMute() const { return m_audioMute; } bool getAudioMute() const { return m_audioMute; }
static MsgConfigureAMMod* create(Real rfBandwidth, Real afBandwidth, int modPercent, bool audioMute) static MsgConfigureAMMod* create(Real rfBandwidth, Real afBandwidth, int modPercent, bool audioMute)
@ -62,14 +62,14 @@ private:
private: private:
Real m_rfBandwidth; Real m_rfBandwidth;
Real m_afBandwidth; Real m_afBandwidth;
Real m_modPercent; float m_modFactor;
bool m_audioMute; bool m_audioMute;
MsgConfigureAMMod(Real rfBandwidth, Real afBandwidth, int modPercent, bool audioMute) : MsgConfigureAMMod(Real rfBandwidth, Real afBandwidth, float modFactor, bool audioMute) :
Message(), Message(),
m_rfBandwidth(rfBandwidth), m_rfBandwidth(rfBandwidth),
m_afBandwidth(afBandwidth), m_afBandwidth(afBandwidth),
m_modPercent(modPercent), m_modFactor(modFactor),
m_audioMute(audioMute) m_audioMute(audioMute)
{ } { }
}; };
@ -90,7 +90,7 @@ private:
qint64 m_inputFrequencyOffset; qint64 m_inputFrequencyOffset;
Real m_rfBandwidth; Real m_rfBandwidth;
Real m_afBandwidth; Real m_afBandwidth;
int m_modPercent; float m_modFactor;
quint32 m_audioSampleRate; quint32 m_audioSampleRate;
bool m_audioMute; bool m_audioMute;
@ -99,7 +99,7 @@ private:
m_inputFrequencyOffset(0), m_inputFrequencyOffset(0),
m_rfBandwidth(-1), m_rfBandwidth(-1),
m_afBandwidth(-1), m_afBandwidth(-1),
m_modPercent(20), m_modFactor(0.2f),
m_audioSampleRate(0), m_audioSampleRate(0),
m_audioMute(false) m_audioMute(false)
{ } { }
@ -110,6 +110,7 @@ private:
NCO m_carrierNco; NCO m_carrierNco;
NCO m_toneNco; NCO m_toneNco;
Complex m_modSample;
Interpolator m_interpolator; Interpolator m_interpolator;
Real m_interpolatorDistance; Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain; Real m_interpolatorDistanceRemain;

View File

@ -278,7 +278,7 @@ void AMModGUI::applySettings()
m_amMod->configure(m_amMod->getInputMessageQueue(), m_amMod->configure(m_amMod->getInputMessageQueue(),
m_rfBW[ui->rfBW->value()], m_rfBW[ui->rfBW->value()],
ui->afBW->value() * 1000.0, ui->afBW->value() * 1000.0,
ui->modPercent->value(), ui->modPercent->value() / 100.0f,
ui->audioMute->isChecked()); ui->audioMute->isChecked());
} }
} }

View File

@ -49,22 +49,28 @@ void NCO::setFreq(Real freq, Real sampleRate)
float NCO::next() float NCO::next()
{ {
m_phase += m_phaseIncrement; nextPhase();
while(m_phase >= TableSize)
m_phase -= TableSize;
while(m_phase < 0)
m_phase += TableSize;
return m_table[m_phase]; return m_table[m_phase];
} }
Complex NCO::nextIQ() Complex NCO::nextIQ()
{ {
m_phase += m_phaseIncrement; nextPhase();
while(m_phase >= TableSize)
m_phase -= TableSize;
while(m_phase < 0)
m_phase += TableSize;
return Complex(m_table[m_phase], -m_table[(m_phase + TableSize / 4) % TableSize]); 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]);
}

View File

@ -38,8 +38,21 @@ public:
NCO(); NCO();
void setFreq(Real freq, Real sampleRate); 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 #endif // INCLUDE_NCO_H