From 1d9ab62a4a87c7fcde61a4bab2cb538808df1c2b Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 11 Feb 2018 13:48:17 +0100 Subject: [PATCH] Test source: added AM and FM modulations --- devices/perseus/deviceperseusscan.cpp | 2 +- .../samplesource/testsource/testsourcegui.cpp | 39 ++ .../samplesource/testsource/testsourcegui.h | 4 + .../samplesource/testsource/testsourcegui.ui | 431 ++++++++++++------ .../testsource/testsourceinput.cpp | 28 ++ .../testsource/testsourcesettings.cpp | 19 + .../testsource/testsourcesettings.h | 11 + .../testsource/testsourcethread.cpp | 72 ++- .../testsource/testsourcethread.h | 13 + 9 files changed, 481 insertions(+), 138 deletions(-) diff --git a/devices/perseus/deviceperseusscan.cpp b/devices/perseus/deviceperseusscan.cpp index 39233f17e..a416d75f4 100644 --- a/devices/perseus/deviceperseusscan.cpp +++ b/devices/perseus/deviceperseusscan.cpp @@ -33,7 +33,7 @@ void DevicePerseusScan::scan(int nbDevices) for (int deviceIndex = 0; deviceIndex < nbDevices; deviceIndex++) { if ((descr = perseus_open(deviceIndex)) == 0) { - qCritical("DevicePerseusScan::scan: open error: %s\n", perseus_errorstr()); + qCritical("DevicePerseusScan::scan: open error: %s", perseus_errorstr()); continue; } diff --git a/plugins/samplesource/testsource/testsourcegui.cpp b/plugins/samplesource/testsource/testsourcegui.cpp index f3454f2e5..e9a0e912d 100644 --- a/plugins/samplesource/testsource/testsourcegui.cpp +++ b/plugins/samplesource/testsource/testsourcegui.cpp @@ -57,6 +57,7 @@ TestSourceGui::TestSourceGui(DeviceUISet *deviceUISet, QWidget* parent) : ui->sampleRate->setValueRange(7, 48000, 9999999); ui->frequencyShift->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->frequencyShift->setValueRange(false, 7, -9999999, 9999999); + ui->frequencyShiftLabel->setText(QString("%1").arg(QChar(0x94, 0x03))); displaySettings(); @@ -212,6 +213,37 @@ void TestSourceGui::on_amplitudeFine_valueChanged(int value __attribute__((unuse sendSettings(); } +void TestSourceGui::on_modulation_currentIndexChanged(int index) +{ + if ((index < 0) || (index > TestSourceSettings::ModulationLast)) { + return; + } + + m_settings.m_modulation = (TestSourceSettings::Modulation) index; + sendSettings(); +} + +void TestSourceGui::on_modulationFrequency_valueChanged(int value) +{ + m_settings.m_modulationTone = value; + ui->modulationFrequencyText->setText(QString("%1").arg(m_settings.m_modulationTone / 100.0, 0, 'f', 2)); + sendSettings(); +} + +void TestSourceGui::on_amModulation_valueChanged(int value) +{ + m_settings.m_amModulation = value; + ui->amModulationText->setText(QString("%1").arg(m_settings.m_amModulation)); + sendSettings(); +} + +void TestSourceGui::on_fmDeviation_valueChanged(int value) +{ + m_settings.m_fmDeviation = value; + ui->fmDeviationText->setText(QString("%1").arg(m_settings.m_fmDeviation / 10.0, 0, 'f', 1)); + sendSettings(); +} + void TestSourceGui::on_dcBias_valueChanged(int value) { ui->dcBiasText->setText(QString(tr("%1 %").arg(value))); @@ -354,6 +386,13 @@ void TestSourceGui::displaySettings() ui->qBiasText->setText(QString(tr("%1 %").arg(qBiasPercent))); ui->autoCorr->setCurrentIndex(m_settings.m_autoCorrOptions); ui->sampleSize->blockSignals(false); + ui->modulation->setCurrentIndex((int) m_settings.m_modulation); + ui->modulationFrequency->setValue(m_settings.m_modulationTone); + ui->modulationFrequencyText->setText(QString("%1").arg(m_settings.m_modulationTone / 100.0, 0, 'f', 2)); + ui->amModulation->setValue(m_settings.m_amModulation); + ui->amModulationText->setText(QString("%1").arg(m_settings.m_amModulation)); + ui->fmDeviation->setValue(m_settings.m_fmDeviation); + ui->fmDeviationText->setText(QString("%1").arg(m_settings.m_fmDeviation / 10.0, 0, 'f', 1)); blockApplySettings(false); } diff --git a/plugins/samplesource/testsource/testsourcegui.h b/plugins/samplesource/testsource/testsourcegui.h index eaac26484..3c0432d69 100644 --- a/plugins/samplesource/testsource/testsourcegui.h +++ b/plugins/samplesource/testsource/testsourcegui.h @@ -88,6 +88,10 @@ private slots: void on_sampleSize_currentIndexChanged(int index); void on_amplitudeCoarse_valueChanged(int value); void on_amplitudeFine_valueChanged(int value); + void on_modulation_currentIndexChanged(int index); + void on_modulationFrequency_valueChanged(int value); + void on_amModulation_valueChanged(int value); + void on_fmDeviation_valueChanged(int value); void on_dcBias_valueChanged(int value); void on_iBias_valueChanged(int value); void on_qBias_valueChanged(int value); diff --git a/plugins/samplesource/testsource/testsourcegui.ui b/plugins/samplesource/testsource/testsourcegui.ui index 89a4d59d4..13e13e02d 100644 --- a/plugins/samplesource/testsource/testsourcegui.ui +++ b/plugins/samplesource/testsource/testsourcegui.ui @@ -216,79 +216,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Shift - - - - - - - - 0 - 0 - - - - - 32 - 16 - - - - - DejaVu Sans Mono - 12 - false - - - - PointingHandCursor - - - Shift from center frequency - - - - - - - Hz - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -382,15 +309,66 @@ + + + + Sz + + + + + + + + 45 + 16777215 + + + + Sample size + + + 0 + + + + 8 + + + + + 12 + + + + + 16 + + + + + + + + bits + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + - - - - Qt::Horizontal - - - @@ -409,7 +387,7 @@ - 28 + 16 0 @@ -454,59 +432,7 @@ - - - Qt::Vertical - - - - - - - size - - - - - - - - 45 - 16777215 - - - - Sample size - - - 0 - - - - 8 - - - - - 12 - - - - - 16 - - - - - - - - bits - - - - - + Qt::Horizontal @@ -518,8 +444,245 @@ + + + + Mod + + + + + + + + 50 + 16777215 + + + + Modulation + + + + No + + + + + AM + + + + + FM + + + + + + + + + 22 + 22 + + + + Modulation tone (kHz) + + + 1 + + + 999 + + + 1 + + + + + + + + 35 + 0 + + + + Modulation tone value (kHz) + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 16 + 0 + + + + D + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + DejaVu Sans Mono + 12 + false + + + + PointingHandCursor + + + Shift from center frequency + + + + + + + Hz + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + AM + + + + + + + + 22 + 22 + + + + AM modulation (%) + + + 1 + + + + + + + AM modulation value (%) + + + 00 + + + + + + + Qt::Vertical + + + + + + + FM + + + + + + + + 22 + 22 + + + + FM deviation (kHz) + + + 1 + + + 999 + + + 1 + + + + + + + + 35 + 0 + + + + FM deviation value (kHz) + + + 00.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Horizontal + + + diff --git a/plugins/samplesource/testsource/testsourceinput.cpp b/plugins/samplesource/testsource/testsourceinput.cpp index 605bebe23..5fb5cadcc 100644 --- a/plugins/samplesource/testsource/testsourceinput.cpp +++ b/plugins/samplesource/testsource/testsourceinput.cpp @@ -350,6 +350,34 @@ bool TestSourceInput::applySettings(const TestSourceSettings& settings, bool for m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif); } + if ((m_settings.m_modulationTone != settings.m_modulationTone) || force) + { + if (m_testSourceThread != 0) { + m_testSourceThread->setToneFrequency(settings.m_modulationTone * 10); + } + } + + if ((m_settings.m_modulation != settings.m_modulation) || force) + { + if (m_testSourceThread != 0) { + m_testSourceThread->setModulation(settings.m_modulation); + } + } + + if ((m_settings.m_amModulation != settings.m_amModulation) || force) + { + if (m_testSourceThread != 0) { + m_testSourceThread->setAMModulation(settings.m_amModulation / 100.0f); + } + } + + if ((m_settings.m_fmDeviation != settings.m_fmDeviation) || force) + { + if (m_testSourceThread != 0) { + m_testSourceThread->setFMDeviation(settings.m_fmDeviation * 100.0f); + } + } + m_settings = settings; return true; } diff --git a/plugins/samplesource/testsource/testsourcesettings.cpp b/plugins/samplesource/testsource/testsourcesettings.cpp index 451b76be2..a78d81f92 100644 --- a/plugins/samplesource/testsource/testsourcesettings.cpp +++ b/plugins/samplesource/testsource/testsourcesettings.cpp @@ -33,6 +33,10 @@ void TestSourceSettings::resetToDefaults() m_sampleSizeIndex = 0; m_amplitudeBits = 127; m_autoCorrOptions = AutoCorrNone; + m_modulation = ModulationNone; + m_modulationTone = 44; // 440 Hz + m_amModulation = 50; // 50% + m_fmDeviation = 50; // 5 kHz m_dcFactor = 0.0f; m_iFactor = 0.0f; m_qFactor = 0.0f; @@ -54,6 +58,10 @@ QByteArray TestSourceSettings::serialize() const s.writeFloat(11, m_iFactor); s.writeFloat(12, m_qFactor); s.writeFloat(13, m_phaseImbalance); + s.writeS32(14, (int) m_modulation); + s.writeS32(15, m_modulationTone); + s.writeS32(16, m_amModulation); + s.writeS32(17, m_fmDeviation); return s.final(); } @@ -91,6 +99,17 @@ bool TestSourceSettings::deserialize(const QByteArray& data) d.readFloat(11, &m_iFactor, 0.0f); d.readFloat(12, &m_qFactor, 0.0f); d.readFloat(13, &m_phaseImbalance, 0.0f); + d.readS32(14, &intval, 0); + + if (intval < 0 || intval > (int) ModulationLast) { + m_modulation = ModulationNone; + } else { + m_modulation = (Modulation) intval; + } + + d.readS32(15, &m_modulationTone, 44); + d.readS32(16, &m_amModulation, 50); + d.readS32(17, &m_fmDeviation, 50); return true; } diff --git a/plugins/samplesource/testsource/testsourcesettings.h b/plugins/samplesource/testsource/testsourcesettings.h index f18947ba4..d4c476703 100644 --- a/plugins/samplesource/testsource/testsourcesettings.h +++ b/plugins/samplesource/testsource/testsourcesettings.h @@ -31,6 +31,13 @@ struct TestSourceSettings { AutoCorrLast, } AutoCorrOptions; + typedef enum { + ModulationNone, + ModulationAM, + ModulationFM, + ModulationLast + } Modulation; + quint64 m_centerFrequency; qint32 m_frequencyShift; quint32 m_sampleRate; @@ -39,6 +46,10 @@ struct TestSourceSettings { quint32 m_sampleSizeIndex; qint32 m_amplitudeBits; AutoCorrOptions m_autoCorrOptions; + Modulation m_modulation; + int m_modulationTone; //!< 10'Hz + int m_amModulation; //!< percent + int m_fmDeviation; //!< 100'Hz float m_dcFactor; //!< -1.0 < x < 1.0 float m_iFactor; //!< -1.0 < x < 1.0 float m_qFactor; //!< -1.0 < x < 1.0 diff --git a/plugins/samplesource/testsource/testsourcethread.cpp b/plugins/samplesource/testsource/testsourcethread.cpp index 5267fe58c..5b71b596a 100644 --- a/plugins/samplesource/testsource/testsourcethread.cpp +++ b/plugins/samplesource/testsource/testsourcethread.cpp @@ -31,6 +31,11 @@ TestSourceThread::TestSourceThread(SampleSinkFifo* sampleFifo, QObject* parent) m_convertBuffer(TESTSOURCE_BLOCKSIZE), m_sampleFifo(sampleFifo), m_frequencyShift(0), + m_toneFrequency(440), + m_modulation(TestSourceSettings::ModulationNone), + m_amModulation(0.5f), + m_fmDeviationUnit(0.0f), + m_fmPhasor(0.0f), m_samplerate(48000), m_log2Decim(4), m_fcPos(0), @@ -81,6 +86,7 @@ void TestSourceThread::setSamplerate(int samplerate) m_chunksize = 4 * ((m_samplerate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000); m_throttleToggle = !m_throttleToggle; m_nco.setFreq(m_frequencyShift, m_samplerate); + m_toneNco.setFreq(m_toneFrequency, m_samplerate); } void TestSourceThread::setLog2Decimation(unsigned int log2_decim) @@ -149,6 +155,28 @@ void TestSourceThread::setFrequencyShift(int shift) m_nco.setFreq(shift, m_samplerate); } +void TestSourceThread::setToneFrequency(int toneFrequency) +{ + m_toneNco.setFreq(toneFrequency, m_samplerate); +} + +void TestSourceThread::setModulation(TestSourceSettings::Modulation modulation) +{ + m_modulation = modulation; +} + +void TestSourceThread::setAMModulation(float amModulation) +{ + m_amModulation = amModulation < 0.0f ? 0.0f : amModulation > 1.0f ? 1.0f : amModulation; +} + +void TestSourceThread::setFMDeviation(float deviation) +{ + float fmDeviationUnit = deviation / (float) m_samplerate; + m_fmDeviationUnit = fmDeviationUnit < 0.0f ? 0.0f : fmDeviationUnit > 1.0f ? 1.0f : fmDeviationUnit; + qDebug("TestSourceThread::setFMDeviation: m_fmDeviationUnit: %f", m_fmDeviationUnit); +} + void TestSourceThread::run() { m_running = true; @@ -195,14 +223,52 @@ void TestSourceThread::generate(quint32 chunksize) for (int i = 0; i < n-1;) { - Complex c = m_nco.nextIQ(m_phaseImbalance); - m_buf[i++] = (int16_t) (c.real() * (float) m_amplitudeBitsI) + m_amplitudeBitsDC; - m_buf[i++] = (int16_t) (c.imag() * (float) m_amplitudeBitsQ); + switch (m_modulation) + { + case TestSourceSettings::ModulationAM: + { + Complex c = m_nco.nextIQ(); + Real t, re, im; + pullAF(t); + t = (t*m_amModulation + 1.0f)*0.5f; + re = c.real()*t; + im = c.imag()*t + m_phaseImbalance*re; + m_buf[i++] = (int16_t) (re * (float) m_amplitudeBitsI) + m_amplitudeBitsDC; + m_buf[i++] = (int16_t) (im * (float) m_amplitudeBitsQ); + } + break; + case TestSourceSettings::ModulationFM: + { + Complex c = m_nco.nextIQ(); + Real t, re, im; + pullAF(t); + m_fmPhasor += m_fmDeviationUnit * t; + m_fmPhasor = m_fmPhasor < -1.0f ? -m_fmPhasor - 1.0f : m_fmPhasor > 1.0f ? m_fmPhasor - 1.0f : m_fmPhasor; + re = c.real()*cos(m_fmPhasor*M_PI) - c.imag()*sin(m_fmPhasor*M_PI); + im = (c.real()*sin(m_fmPhasor*M_PI) + c.imag()*cos(m_fmPhasor*M_PI)) + m_phaseImbalance*re; + m_buf[i++] = (int16_t) (re * (float) m_amplitudeBitsI) + m_amplitudeBitsDC; + m_buf[i++] = (int16_t) (im * (float) m_amplitudeBitsQ); + } + break; + case TestSourceSettings::ModulationNone: + default: + { + Complex c = m_nco.nextIQ(m_phaseImbalance); + m_buf[i++] = (int16_t) (c.real() * (float) m_amplitudeBitsI) + m_amplitudeBitsDC; + m_buf[i++] = (int16_t) (c.imag() * (float) m_amplitudeBitsQ); + } + break; + } } callback(m_buf, n); } +void TestSourceThread::pullAF(Real& afSample) +{ + afSample = m_toneNco.next(); +} + // call appropriate conversion (decimation) routine depending on the number of sample bits void TestSourceThread::callback(const qint16* buf, qint32 len) { diff --git a/plugins/samplesource/testsource/testsourcethread.h b/plugins/samplesource/testsource/testsourcethread.h index 43d64c78f..a91b6c010 100644 --- a/plugins/samplesource/testsource/testsourcethread.h +++ b/plugins/samplesource/testsource/testsourcethread.h @@ -28,6 +28,8 @@ #include "dsp/decimators.h" #include "dsp/ncof.h" +#include "testsourcesettings.h" + #define TESTSOURCE_THROTTLE_MS 50 class TestSourceThread : public QThread { @@ -49,6 +51,10 @@ public: void setQFactor(float qFactor); void setPhaseImbalance(float phaseImbalance); void setFrequencyShift(int shift); + void setToneFrequency(int toneFrequency); + void setModulation(TestSourceSettings::Modulation modulation); + void setAMModulation(float amModulation); + void setFMDeviation(float deviation); void connectTimer(const QTimer& timer); @@ -63,7 +69,13 @@ private: SampleVector m_convertBuffer; SampleSinkFifo* m_sampleFifo; NCOF m_nco; + NCOF m_toneNco; int m_frequencyShift; + int m_toneFrequency; + TestSourceSettings::Modulation m_modulation; + float m_amModulation; + float m_fmDeviationUnit; + float m_fmPhasor; int m_samplerate; unsigned int m_log2Decim; @@ -101,6 +113,7 @@ private: void callback(const qint16* buf, qint32 len); void setBuffers(quint32 chunksize); void generate(quint32 chunksize); + void pullAF(Real& afSample); // Decimate according to specified log2 (ex: log2=4 => decim=16) inline void convert_8(SampleVector::iterator* it, const qint16* buf, qint32 len)