From 5bd8d69987b772ea68786512f5f003eba1195f44 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 1 Oct 2019 00:21:17 +0200 Subject: [PATCH] Interferometer (8) --- .../interferometer/interferometer.cpp | 5 + .../interferometer/interferometercorr.cpp | 155 +++++++++++++++--- .../interferometer/interferometercorr.h | 7 + .../interferometer/interferometergui.cpp | 9 + .../interferometer/interferometergui.h | 1 + .../interferometer/interferometergui.ui | 45 +++++ .../interferometer/interferometersettings.cpp | 4 + .../interferometer/interferometersettings.h | 1 + .../interferometer/interferometersink.h | 1 + 9 files changed, 208 insertions(+), 20 deletions(-) diff --git a/plugins/channelmimo/interferometer/interferometer.cpp b/plugins/channelmimo/interferometer/interferometer.cpp index 90d26e605..1969908de 100644 --- a/plugins/channelmimo/interferometer/interferometer.cpp +++ b/plugins/channelmimo/interferometer/interferometer.cpp @@ -122,6 +122,7 @@ void Interferometer::applySettings(const InterferometerSettings& settings, bool << "m_filterChainHash: " << settings.m_filterChainHash << "m_log2Decim: " << settings.m_log2Decim << "m_correlationType: " << settings.m_correlationType + << "m_phase: " << settings.m_phase << "m_useReverseAPI: " << settings.m_useReverseAPI << "m_reverseAPIAddress: " << settings.m_reverseAPIAddress << "m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -144,6 +145,10 @@ void Interferometer::applySettings(const InterferometerSettings& settings, bool m_sink->getInputMessageQueue()->push(msg); } + if ((m_settings.m_phase != settings.m_phase) || force) { + m_sink->setPhase(settings.m_phase); + } + m_settings = settings; } diff --git a/plugins/channelmimo/interferometer/interferometercorr.cpp b/plugins/channelmimo/interferometer/interferometercorr.cpp index 73364041a..a12579aef 100644 --- a/plugins/channelmimo/interferometer/interferometercorr.cpp +++ b/plugins/channelmimo/interferometer/interferometercorr.cpp @@ -16,6 +16,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "dsp/fftengine.h" #include "interferometercorr.h" @@ -24,6 +25,10 @@ Sample sAdd(const Sample& a, const Sample& b) { //!< Sample addition return Sample{a.real() + b.real(), a.imag() + b.imag()}; } +Sample sAddInv(const Sample& a, const Sample& b) { //!< Sample addition + return Sample{a.real() - b.real(), a.imag() + b.imag()}; +} + Sample sMulConj(const Sample& a, const Sample& b) { //!< Sample multiply with conjugate Sample s; // Integer processing @@ -33,8 +38,8 @@ Sample sMulConj(const Sample& a, const Sample& b) { //!< Sample multiply with co int64_t by = b.imag(); int64_t x = ax*bx + ay*by; int64_t y = ay*bx - ax*by; - s.setReal(x>>SDR_RX_SAMP_SZ); - s.setImag(y>>SDR_RX_SAMP_SZ); + s.setReal(x>>(SDR_RX_SAMP_SZ-1)); + s.setImag(y>>(SDR_RX_SAMP_SZ-1)); // Floating point processing (in practice there is no significant performance difference) // float ax = a.real() / SDR_RX_SCALEF; // float ay = a.imag() / SDR_RX_SCALEF; @@ -47,10 +52,17 @@ Sample sMulConj(const Sample& a, const Sample& b) { //!< Sample multiply with co return s; } -Sample cf2s(const std::complex& a) { //!< Complex float to Sample +Sample sMulConjInv(const Sample& a, const Sample& b) { //!< Sample multiply with conjugate Sample s; - s.setReal(a.real()*SDR_RX_SCALEF); - s.setImag(a.imag()*SDR_RX_SCALEF); + // Integer processing + int64_t ax = a.real(); + int64_t ay = a.imag(); + int64_t bx = -b.real(); + int64_t by = -b.imag(); + int64_t x = ax*bx + ay*by; + int64_t y = ay*bx - ax*by; + s.setReal(x>>(SDR_RX_SAMP_SZ-1)); + s.setImag(y>>(SDR_RX_SAMP_SZ-1)); return s; } @@ -65,6 +77,11 @@ InterferometerCorrelator::InterferometerCorrelator(int fftSize) : m_corrType(InterferometerSettings::CorrelationAdd), m_fftSize(fftSize) { + setPhase(0); + m_window.create(FFTWindow::Function::Hanning, fftSize); + m_data0w.resize(m_fftSize); + m_data1w.resize(m_fftSize); + for (int i = 0; i < 2; i++) { m_fft[i] = FFTEngine::create(); @@ -98,19 +115,76 @@ bool InterferometerCorrelator::performCorr( { bool results = false; - switch (m_corrType) + if (m_phase == 0) { - case InterferometerSettings::CorrelationAdd: - results = performOpCorr(data0, size0, data1, size1, sAdd); - break; - case InterferometerSettings::CorrelationMultiply: - results = performOpCorr(data0, size0, data1, size1, sMulConj); - break; - case InterferometerSettings::CorrelationFFT: - results = performFFTCorr(data0, size0, data1, size1); - break; - default: - break; + switch (m_corrType) + { + case InterferometerSettings::CorrelationAdd: + results = performOpCorr(data0, size0, data1, size1, sAdd); + break; + case InterferometerSettings::CorrelationMultiply: + results = performOpCorr(data0, size0, data1, size1, sMulConj); + break; + case InterferometerSettings::CorrelationFFT: + results = performFFTCorr(data0, size0, data1, size1); + break; + default: + break; + } + } + else if ((m_phase == -180) || (m_phase == 180)) + { + switch (m_corrType) + { + case InterferometerSettings::CorrelationAdd: + results = performOpCorr(data0, size0, data1, size1, sAddInv); + break; + case InterferometerSettings::CorrelationMultiply: + results = performOpCorr(data0, size0, data1, size1, sMulConjInv); + break; + case InterferometerSettings::CorrelationFFT: + results = performFFTCorr(data0, size0, m_data1p, size1); + break; + default: + break; + } + } + else + { + if (size1 > m_data1p.size()) { + m_data1p.resize(size1); + } + + std::transform( + data1.begin(), + data1.begin() + size1, + m_data1p.begin(), + [this](const Sample& s) -> Sample { + Sample t; + int64_t sx = s.real(); + int64_t sy = s.imag(); + int64_t x = sx*m_cos + sy*m_sin; + int64_t y = sy*m_cos - sx*m_sin; + t.setReal(x>>(SDR_RX_SAMP_SZ-1)); + t.setImag(y>>(SDR_RX_SAMP_SZ-1)); + return t; + } + ); + + switch (m_corrType) + { + case InterferometerSettings::CorrelationAdd: + results = performOpCorr(data0, size0, m_data1p, size1, sAdd); + break; + case InterferometerSettings::CorrelationMultiply: + results = performOpCorr(data0, size0, m_data1p, size1, sMulConj); + break; + case InterferometerSettings::CorrelationFFT: + results = performFFTCorr(data0, size0, m_data1p, size1); + break; + default: + break; + } } return results; @@ -169,6 +243,7 @@ bool InterferometerCorrelator::performFFTCorr( return std::complex{s.real() / SDR_RX_SCALEF, s.imag() / SDR_RX_SCALEF}; } ); + m_window.apply(m_fft[0]->in()); std::fill(m_fft[0]->in() + m_fftSize, m_fft[0]->in() + 2*m_fftSize, std::complex{0, 0}); m_fft[0]->transform(); @@ -181,6 +256,7 @@ bool InterferometerCorrelator::performFFTCorr( return std::complex{s.real() / SDR_RX_SCALEF, s.imag() / SDR_RX_SCALEF}; } ); + m_window.apply(m_fft[1]->in()); std::fill(m_fft[1]->in() + m_fftSize, m_fft[1]->in() + 2*m_fftSize, std::complex{0, 0}); m_fft[1]->transform(); @@ -201,16 +277,21 @@ bool InterferometerCorrelator::performFFTCorr( m_dataj, m_invFFT->in(), [](std::complex& a, const std::complex& b) -> std::complex { - return a*b; + return (a*b); } ); - // copy product to correlation spectrum + // copy product to correlation spectrum - convert and scale to FFT size std::transform( m_invFFT->in(), m_invFFT->in() + 2*m_fftSize, m_scorr.begin(), - cf2s + [this](const std::complex& a) -> Sample { + Sample s; + s.setReal(a.real()*(SDR_RX_SCALEF/m_fftSize)); + s.setImag(a.imag()*(SDR_RX_SCALEF/m_fftSize)); + return s; + } ); // do the inverse FFT to get time correlation @@ -253,3 +334,37 @@ void InterferometerCorrelator::adjustTCorrSize(int size) m_tcorrSize = size; } } + +void InterferometerCorrelator::setPhase(int phase) +{ + m_phase = phase; + + if (phase == 0) + { + m_sin = 0; + m_cos = 1<<(SDR_RX_SAMP_SZ-1); + } + else if (phase == 90) + { + m_sin = 1<<(SDR_RX_SAMP_SZ-1); + m_cos = 0; + } + else if (phase == -90) + { + m_sin = -(1<<(SDR_RX_SAMP_SZ-1)); + m_cos = 0; + } + else if ((phase == -180) || (phase == 180)) + { + m_sin = 0; + m_cos = -(1<<(SDR_RX_SAMP_SZ-1)); + } + else + { + m_phase = phase % 180; + double d_sin = sin(M_PI*(m_phase/180.0)) * (1<<(SDR_RX_SAMP_SZ-1)); + double d_cos = cos(M_PI*(m_phase/180.0)) * (1<<(SDR_RX_SAMP_SZ-1)); + m_sin = d_sin; + m_cos = d_cos; + } +} \ No newline at end of file diff --git a/plugins/channelmimo/interferometer/interferometercorr.h b/plugins/channelmimo/interferometer/interferometercorr.h index 735a2d8d1..d230aa24b 100644 --- a/plugins/channelmimo/interferometer/interferometercorr.h +++ b/plugins/channelmimo/interferometer/interferometercorr.h @@ -44,6 +44,7 @@ public: int size1 ); int getFullFFTSize() const { return 2*m_fftSize; } + void setPhase(int phase); SampleVector m_scorr; //!< raw correlation result (spectrum) - Sample vector expected SampleVector m_tcorr; //!< correlation result (time or spectrum inverse FFT) - Sample vector expected @@ -76,8 +77,14 @@ private: FFTEngine *m_invFFT; //!< Inverse FFT engine FFTWindow m_window; //!< FFT window std::complex *m_dataj; //!< conjuate of FFT transform + SampleVector m_data0w; //!< windowed data 0 + SampleVector m_data1w; //!< windowed data 1 + SampleVector m_data1p; //!< data1 with phase correction int m_scorrSize; //!< spectrum correlations vector size int m_tcorrSize; //!< time correlations vector size + int m_phase; //!< phase correction + int64_t m_sin; //!< scaled sine of phase correction + int64_t m_cos; //!< scaled cosine of phase correction }; #endif // INCLUDE_INTERFEROMETERCORR_H diff --git a/plugins/channelmimo/interferometer/interferometergui.cpp b/plugins/channelmimo/interferometer/interferometergui.cpp index 0206cfc46..e8af0139d 100644 --- a/plugins/channelmimo/interferometer/interferometergui.cpp +++ b/plugins/channelmimo/interferometer/interferometergui.cpp @@ -210,6 +210,8 @@ void InterferometerGUI::displaySettings() blockApplySettings(true); ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim); applyDecimation(); + ui->phaseCorrection->setValue(m_settings.m_phase); + ui->phaseCorrectionText->setText(tr("%1").arg(m_settings.m_phase)); blockApplySettings(false); } @@ -298,6 +300,13 @@ void InterferometerGUI::on_position_valueChanged(int value) applyPosition(); } +void InterferometerGUI::on_phaseCorrection_valueChanged(int value) +{ + m_settings.m_phase = value; + ui->phaseCorrectionText->setText(tr("%1").arg(value)); + applySettings(); +} + void InterferometerGUI::on_correlationType_currentIndexChanged(int index) { m_settings.m_correlationType = (InterferometerSettings::CorrelationType) index; diff --git a/plugins/channelmimo/interferometer/interferometergui.h b/plugins/channelmimo/interferometer/interferometergui.h index 4f4e470b8..7a2a868ef 100644 --- a/plugins/channelmimo/interferometer/interferometergui.h +++ b/plugins/channelmimo/interferometer/interferometergui.h @@ -91,6 +91,7 @@ private slots: void handleSourceMessages(); void on_decimationFactor_currentIndexChanged(int index); void on_position_valueChanged(int value); + void on_phaseCorrection_valueChanged(int value); void on_correlationType_currentIndexChanged(int index); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); diff --git a/plugins/channelmimo/interferometer/interferometergui.ui b/plugins/channelmimo/interferometer/interferometergui.ui index 2a3d4c9e5..999dd2038 100644 --- a/plugins/channelmimo/interferometer/interferometergui.ui +++ b/plugins/channelmimo/interferometer/interferometergui.ui @@ -186,6 +186,51 @@ + + + + Ph + + + + + + + Phase correction on stream 1 + + + -180 + + + 180 + + + 1 + + + Qt::Horizontal + + + + + + + + 28 + 0 + + + + Phase correction on stream 1 in degrees + + + -180 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + diff --git a/plugins/channelmimo/interferometer/interferometersettings.cpp b/plugins/channelmimo/interferometer/interferometersettings.cpp index f629f0b68..b67e64965 100644 --- a/plugins/channelmimo/interferometer/interferometersettings.cpp +++ b/plugins/channelmimo/interferometer/interferometersettings.cpp @@ -38,6 +38,7 @@ void InterferometerSettings::resetToDefaults() m_title = "Interferometer"; m_log2Decim = 0; m_filterChainHash = 0; + m_phase = 0; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; @@ -58,6 +59,7 @@ QByteArray InterferometerSettings::serialize() const s.writeU32(9, m_reverseAPIPort); s.writeU32(10, m_reverseAPIDeviceIndex); s.writeU32(11, m_reverseAPIChannelIndex); + s.writeS32(12, m_phase); if (m_spectrumGUI) { s.writeBlob(20, m_spectrumGUI->serialize()); @@ -109,6 +111,8 @@ bool InterferometerSettings::deserialize(const QByteArray& data) m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; d.readU32(11, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readS32(12, &tmp, 0); + m_phase = tmp < -180 ? -180 : tmp > 180 ? 180 : tmp; if (m_spectrumGUI) { d.readBlob(20, &bytetmp); diff --git a/plugins/channelmimo/interferometer/interferometersettings.h b/plugins/channelmimo/interferometer/interferometersettings.h index 652e0610d..491875e85 100644 --- a/plugins/channelmimo/interferometer/interferometersettings.h +++ b/plugins/channelmimo/interferometer/interferometersettings.h @@ -37,6 +37,7 @@ struct InterferometerSettings QString m_title; uint32_t m_log2Decim; uint32_t m_filterChainHash; + int m_phase; bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelmimo/interferometer/interferometersink.h b/plugins/channelmimo/interferometer/interferometersink.h index ad643ad77..b68ed7c7a 100644 --- a/plugins/channelmimo/interferometer/interferometersink.h +++ b/plugins/channelmimo/interferometer/interferometersink.h @@ -104,6 +104,7 @@ public: void setSpectrumSink(BasebandSampleSink *spectrumSink) { m_spectrumSink = spectrumSink; } void setScopeSink(BasebandSampleSink *scopeSink) { m_scopeSink = scopeSink; } + void setPhase(int phase) { m_correlator.setPhase(phase); } void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, unsigned int streamIndex);