diff --git a/plugins/samplesource/testsource/testsourcegui.cpp b/plugins/samplesource/testsource/testsourcegui.cpp index 1b760e8ee..f3454f2e5 100644 --- a/plugins/samplesource/testsource/testsourcegui.cpp +++ b/plugins/samplesource/testsource/testsourcegui.cpp @@ -141,7 +141,7 @@ void TestSourceGui::on_centerFrequency_changed(quint64 value) void TestSourceGui::on_autoCorr_currentIndexChanged(int index) { - if ((index < 0) || (index > TestSourceSettings::AutoCorrDCAndIQ)) { + if ((index < 0) || (index > TestSourceSettings::AutoCorrLast)) { return; } diff --git a/plugins/samplesource/testsource/testsourcesettings.cpp b/plugins/samplesource/testsource/testsourcesettings.cpp index 0ae95af3c..451b76be2 100644 --- a/plugins/samplesource/testsource/testsourcesettings.cpp +++ b/plugins/samplesource/testsource/testsourcesettings.cpp @@ -81,7 +81,7 @@ bool TestSourceSettings::deserialize(const QByteArray& data) d.readS32(7, &m_amplitudeBits, 128); d.readS32(8, &intval, 0); - if (intval < 0 || intval > (int) AutoCorrDCAndIQ) { + if (intval < 0 || intval > (int) AutoCorrLast) { m_autoCorrOptions = AutoCorrNone; } else { m_autoCorrOptions = (AutoCorrOptions) intval; diff --git a/plugins/samplesource/testsource/testsourcesettings.h b/plugins/samplesource/testsource/testsourcesettings.h index 7ebb06894..f18947ba4 100644 --- a/plugins/samplesource/testsource/testsourcesettings.h +++ b/plugins/samplesource/testsource/testsourcesettings.h @@ -27,7 +27,8 @@ struct TestSourceSettings { typedef enum { AutoCorrNone, AutoCorrDC, - AutoCorrDCAndIQ + AutoCorrDCAndIQ, + AutoCorrLast, } AutoCorrOptions; quint64 m_centerFrequency; diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index da3469fc7..4f8d3eebe 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -95,6 +95,7 @@ set(sdrbase_HEADERS commands/command.h dsp/afsquelch.h + dsp/autocorrector.h dsp/downchannelizer.h dsp/upchannelizer.h dsp/channelmarker.h diff --git a/sdrbase/dsp/autocorrector.h b/sdrbase/dsp/autocorrector.h new file mode 100644 index 000000000..99c50e6d1 --- /dev/null +++ b/sdrbase/dsp/autocorrector.h @@ -0,0 +1,105 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 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 SDRBASE_DSP_AUTOCORRECTOR_H_ +#define SDRBASE_DSP_AUTOCORRECTOR_H_ + +#include "util/movingaverage.h" + +template +class AutoCorrector +{ +public: + AutoCorrector(qint32 intBits); + void process(const T& inreal, const T& inimag, qint32& outreal, qint32& outimag); + void process(qint32& xreal, qint32& ximag); + void setIQCorrection(bool iqCorrection) { m_iqCorrection = iqCorrection; } +private: + bool m_iqCorrection; + float m_scalef; + MovingAverageUtil m_iBeta; + MovingAverageUtil m_qBeta; + MovingAverageUtil m_avgII; + MovingAverageUtil m_avgIQ; + MovingAverageUtil m_avgII2; + MovingAverageUtil m_avgQQ2; + MovingAverageUtil m_avgPhi; + MovingAverageUtil m_avgAmp; +}; + +template +AutoCorrector::AutoCorrector(qint32 intBits) : + m_iqCorrection(false), + m_scalef((float) (1<<(intBits-1))) +{ +} + +template +void AutoCorrector::process(const T& inreal, const T& inimag, qint32& outreal, qint32& outimag) +{ + outreal = inreal; + outimag = inimag; + process(outreal, outimag); +} + +template +void AutoCorrector::process(qint32& xreal, qint32& ximag) +{ + m_iBeta(xreal); + m_qBeta(ximag); + + if (m_iqCorrection) + { + // DC correction and conversion + float xi = (xreal - (int32_t) m_iBeta) / m_scalef; + float xq = (ximag - (int32_t) m_qBeta) / m_scalef; + + // phase imbalance + m_avgII(xi*xi); // + m_avgIQ(xi*xq); // + + + if (m_avgII.asDouble() != 0) { + m_avgPhi(m_avgIQ.asDouble()/m_avgII.asDouble()); + } + + float yi = xi - m_avgPhi.asDouble()*xq; + float yq = xq; + + // amplitude I/Q imbalance + m_avgII2(yi*yi); // + m_avgQQ2(yq*yq); // + + if (m_avgQQ2.asDouble() != 0) { + m_avgAmp(sqrt(m_avgII2.asDouble() / m_avgQQ2.asDouble())); + } + + // final correction + float zi = yi; + float zq = m_avgAmp.asDouble() * yq; + + // convert and store + xreal = zi * m_scalef; + ximag = zq * m_scalef; + } + else + { + xreal -= (int32_t) m_iBeta; + ximag -= (int32_t) m_qBeta; + } +} + +#endif /* SDRBASE_DSP_AUTOCORRECTOR_H_ */