diff --git a/plugins/samplesource/testsource/testsourcegui.cpp b/plugins/samplesource/testsource/testsourcegui.cpp
index ce15db692..80500ed4c 100644
--- a/plugins/samplesource/testsource/testsourcegui.cpp
+++ b/plugins/samplesource/testsource/testsourcegui.cpp
@@ -236,6 +236,13 @@ void TestSourceGui::on_qBias_valueChanged(int value)
sendSettings();
}
+void TestSourceGui::on_phaseImbalance_valueChanged(int value)
+{
+ ui->phaseImbalanceText->setText(QString(tr("%1 %").arg(value)));
+ m_settings.m_phaseImbalance = value / 100.0f;
+ sendSettings();
+}
+
void TestSourceGui::on_record_toggled(bool checked)
{
if (checked) {
diff --git a/plugins/samplesource/testsource/testsourcegui.h b/plugins/samplesource/testsource/testsourcegui.h
index ccbab9835..f66eba45d 100644
--- a/plugins/samplesource/testsource/testsourcegui.h
+++ b/plugins/samplesource/testsource/testsourcegui.h
@@ -92,6 +92,7 @@ private slots:
void on_dcBias_valueChanged(int value);
void on_iBias_valueChanged(int value);
void on_qBias_valueChanged(int value);
+ void on_phaseImbalance_valueChanged(int value);
void on_record_toggled(bool checked);
void updateStatus();
void updateHardware();
diff --git a/plugins/samplesource/testsource/testsourcegui.ui b/plugins/samplesource/testsource/testsourcegui.ui
index c8b5f40dc..2479b89ba 100644
--- a/plugins/samplesource/testsource/testsourcegui.ui
+++ b/plugins/samplesource/testsource/testsourcegui.ui
@@ -624,12 +624,6 @@
-
-
-
- 45
- 0
-
-
-100 %
@@ -688,12 +682,6 @@
-
-
-
- 45
- 0
-
-
-100 %
@@ -745,6 +733,37 @@
-
+
+ -100 %
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Phase
+
+
+
+ -
+
+
+ -
+
+
+
+ -
+
+
+ +
+
+
+
+ -
+
45
@@ -759,24 +778,23 @@
+ -
+
+
+ -99
+
+
+ 1
+
+
+ Qt::Horizontal
+
+
+
-
-
-
-
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
+
diff --git a/plugins/samplesource/testsource/testsourceinput.cpp b/plugins/samplesource/testsource/testsourceinput.cpp
index 213176a3b..8a8ea5880 100644
--- a/plugins/samplesource/testsource/testsourceinput.cpp
+++ b/plugins/samplesource/testsource/testsourceinput.cpp
@@ -316,6 +316,13 @@ bool TestSourceInput::applySettings(const TestSourceSettings& settings, bool for
}
}
+ if ((m_settings.m_phaseImbalance != settings.m_phaseImbalance) || force)
+ {
+ if (m_testSourceThread != 0) {
+ m_testSourceThread->setPhaseImbalance(settings.m_phaseImbalance);
+ }
+ }
+
if ((m_settings.m_sampleSizeIndex != settings.m_sampleSizeIndex) || force)
{
if (m_testSourceThread != 0) {
diff --git a/plugins/samplesource/testsource/testsourceplugin.cpp b/plugins/samplesource/testsource/testsourceplugin.cpp
index 13bcacc88..618fb408d 100644
--- a/plugins/samplesource/testsource/testsourceplugin.cpp
+++ b/plugins/samplesource/testsource/testsourceplugin.cpp
@@ -29,7 +29,7 @@
const PluginDescriptor TestSourcePlugin::m_pluginDescriptor = {
QString("Test Source input"),
- QString("3.11.0"),
+ QString("3.12.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
diff --git a/plugins/samplesource/testsource/testsourcesettings.cpp b/plugins/samplesource/testsource/testsourcesettings.cpp
index 6fe1aac82..0b234557f 100644
--- a/plugins/samplesource/testsource/testsourcesettings.cpp
+++ b/plugins/samplesource/testsource/testsourcesettings.cpp
@@ -37,6 +37,7 @@ void TestSourceSettings::resetToDefaults()
m_dcFactor = 0.0f;
m_iFactor = 0.0f;
m_qFactor = 0.0f;
+ m_phaseImbalance = 0.0f;
}
QByteArray TestSourceSettings::serialize() const
@@ -54,6 +55,7 @@ QByteArray TestSourceSettings::serialize() const
s.writeFloat(10, m_dcFactor);
s.writeFloat(11, m_iFactor);
s.writeFloat(12, m_qFactor);
+ s.writeFloat(13, m_phaseImbalance);
return s.final();
}
@@ -84,6 +86,7 @@ bool TestSourceSettings::deserialize(const QByteArray& data)
d.readFloat(10, &m_dcFactor, 0.0f);
d.readFloat(11, &m_iFactor, 0.0f);
d.readFloat(12, &m_qFactor, 0.0f);
+ d.readFloat(13, &m_phaseImbalance, 0.0f);
return true;
}
diff --git a/plugins/samplesource/testsource/testsourcesettings.h b/plugins/samplesource/testsource/testsourcesettings.h
index 883746a62..9c348e1fb 100644
--- a/plugins/samplesource/testsource/testsourcesettings.h
+++ b/plugins/samplesource/testsource/testsourcesettings.h
@@ -33,9 +33,10 @@ struct TestSourceSettings {
qint32 m_amplitudeBits;
bool m_dcBlock;
bool m_iqImbalance;
- float m_dcFactor; //!< -1.0 < x < 1.0
- float m_iFactor; //!< -1.0 < x < 1.0
- float m_qFactor; //!< -1.0 < x < 1.0
+ float m_dcFactor; //!< -1.0 < x < 1.0
+ float m_iFactor; //!< -1.0 < x < 1.0
+ float m_qFactor; //!< -1.0 < x < 1.0
+ float m_phaseImbalance; //!< -1.0 < x < 1.0
TestSourceSettings();
void resetToDefaults();
diff --git a/plugins/samplesource/testsource/testsourcethread.cpp b/plugins/samplesource/testsource/testsourcethread.cpp
index b88a03271..5267fe58c 100644
--- a/plugins/samplesource/testsource/testsourcethread.cpp
+++ b/plugins/samplesource/testsource/testsourcethread.cpp
@@ -40,6 +40,7 @@ TestSourceThread::TestSourceThread(SampleSinkFifo* sampleFifo, QObject* parent)
m_dcBias(0.0f),
m_iBias(0.0f),
m_qBias(0.0f),
+ m_phaseImbalance(0.0f),
m_amplitudeBitsDC(0),
m_amplitudeBitsI(127),
m_amplitudeBitsQ(127),
@@ -138,6 +139,11 @@ void TestSourceThread::setQFactor(float iFactor)
m_amplitudeBitsQ = (1.0f + m_qBias) * m_amplitudeBits;
}
+void TestSourceThread::setPhaseImbalance(float phaseImbalance)
+{
+ m_phaseImbalance = phaseImbalance;
+}
+
void TestSourceThread::setFrequencyShift(int shift)
{
m_nco.setFreq(shift, m_samplerate);
@@ -189,7 +195,7 @@ void TestSourceThread::generate(quint32 chunksize)
for (int i = 0; i < n-1;)
{
- Complex c = m_nco.nextIQ();
+ 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);
}
diff --git a/plugins/samplesource/testsource/testsourcethread.h b/plugins/samplesource/testsource/testsourcethread.h
index d8a8f219c..43d64c78f 100644
--- a/plugins/samplesource/testsource/testsourcethread.h
+++ b/plugins/samplesource/testsource/testsourcethread.h
@@ -47,6 +47,7 @@ public:
void setDCFactor(float iFactor);
void setIFactor(float iFactor);
void setQFactor(float qFactor);
+ void setPhaseImbalance(float phaseImbalance);
void setFrequencyShift(int shift);
void connectTimer(const QTimer& timer);
@@ -73,6 +74,7 @@ private:
float m_dcBias;
float m_iBias;
float m_qBias;
+ float m_phaseImbalance;
int32_t m_amplitudeBitsDC;
int32_t m_amplitudeBitsI;
int32_t m_amplitudeBitsQ;
diff --git a/sdrbase/dsp/ncof.cpp b/sdrbase/dsp/ncof.cpp
index 361af4f1e..59ff93b9c 100644
--- a/sdrbase/dsp/ncof.cpp
+++ b/sdrbase/dsp/ncof.cpp
@@ -61,6 +61,14 @@ Complex NCOF::nextIQ()
return Complex(m_table[phase], -m_table[(phase + TableSize / 4) % TableSize]);
}
+Complex NCOF::nextIQ(float imbalance)
+{
+ int phase = nextPhase();
+ int phaseQ = imbalance < 0.0 ? phase + (int) (imbalance*TableSize) : phase;
+ int phaseI = imbalance < 0.0 ? phase : phase + (int) (imbalance*TableSize);
+ return Complex(m_table[phaseI % TableSize], -m_table[(phaseQ + TableSize / 4) % TableSize]);
+}
+
Complex NCOF::nextQI()
{
int phase = nextPhase();
diff --git a/sdrbase/dsp/ncof.h b/sdrbase/dsp/ncof.h
index 349541809..6c4217565 100644
--- a/sdrbase/dsp/ncof.h
+++ b/sdrbase/dsp/ncof.h
@@ -49,14 +49,15 @@ public:
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)
+ Real next(); //!< Return next real sample
+ Complex nextIQ(); //!< Return next complex sample
+ Complex nextIQ(float imbalance); //!< Return next complex sample with an imbalance factor on I
+ 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