mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-01-28 08:25:45 -05:00
Interferometer (8)
This commit is contained in:
parent
fcc11bbaf8
commit
5bd8d69987
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#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<float>& 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<float>{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<float>{0, 0});
|
||||
m_fft[0]->transform();
|
||||
|
||||
@ -181,6 +256,7 @@ bool InterferometerCorrelator::performFFTCorr(
|
||||
return std::complex<float>{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<float>{0, 0});
|
||||
m_fft[1]->transform();
|
||||
|
||||
@ -201,16 +277,21 @@ bool InterferometerCorrelator::performFFTCorr(
|
||||
m_dataj,
|
||||
m_invFFT->in(),
|
||||
[](std::complex<float>& a, const std::complex<float>& b) -> std::complex<float> {
|
||||
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<float>& 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;
|
||||
}
|
||||
}
|
||||
@ -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<float> *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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -186,6 +186,51 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="phaseCorrectionLabel">
|
||||
<property name="text">
|
||||
<string>Ph</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="phaseCorrection">
|
||||
<property name="toolTip">
|
||||
<string>Phase correction on stream 1</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-180</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>180</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="phaseCorrectionText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Phase correction on stream 1 in degrees</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-180</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user