1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-12-03 17:43:52 -05:00

Interferometer (4)

This commit is contained in:
f4exb 2019-09-12 18:20:25 +02:00
parent df841e47a7
commit 8c8c05653d
15 changed files with 472 additions and 235 deletions

View File

@ -33,35 +33,41 @@
#include "interferometer.h"
MESSAGE_CLASS_DEFINITION(Interferometer::MsgConfigureInterferometer, Message)
MESSAGE_CLASS_DEFINITION(Interferometer::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(Interferometer::MsgSampleRateNotification, Message)
MESSAGE_CLASS_DEFINITION(Interferometer::MsgBasebandNotification, Message)
const QString Interferometer::m_channelIdURI = "sdrangel.channel.interferometer";
const QString Interferometer::m_channelId = "Interferometer";
const int Interferometer::m_fftSize = 4096;
Interferometer::Interferometer(DeviceAPI *deviceAPI) :
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
ChannelAPI(m_channelIdURI, ChannelAPI::StreamMIMO),
m_deviceAPI(deviceAPI),
m_spectrumSink(nullptr),
m_scopeSink(nullptr),
m_guiMessageQueue(nullptr),
m_frequencyOffset(0),
m_deviceSampleRate(48000)
{
m_deviceAPI->addChannelSinkAPI(this);
setObjectName(m_channelId);
m_thread = new QThread(this);
m_sink = new InterferometerSink();
m_sink = new InterferometerSink(m_fftSize);
m_sink->moveToThread(m_thread);
start();
m_deviceAPI->addMIMOChannel(this);
m_deviceAPI->addMIMOChannelAPI(this);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_networkManager = new QNetworkAccessManager();
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
}
Interferometer::~Interferometer()
{
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager;
m_deviceAPI->removeChannelSinkAPI(this);
if (m_thread->isRunning()) {
stop();
}
m_deviceAPI->removeMIMOChannel(this);
delete m_sink;
delete m_thread;
}
@ -94,8 +100,26 @@ void Interferometer::feed(const SampleVector::const_iterator& begin, const Sampl
m_sink->feed(begin, end, sinkIndex);
}
void Interferometer::pull(Sample& sample, unsigned int sourceIndex)
{
(void) sample;
(void) sourceIndex;
}
void Interferometer::applySettings(const InterferometerSettings& settings, bool force)
{
qDebug() << "Interferometer::applySettings: "
<< "m_correlationType: " << settings.m_correlationType
<< "m_filterChainHash: " << settings.m_filterChainHash
<< "m_log2Decim: " << settings.m_log2Decim
<< "m_correlationType: " << settings.m_correlationType
<< "m_useReverseAPI: " << settings.m_useReverseAPI
<< "m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< "m_reverseAPIPort: " << settings.m_reverseAPIPort
<< "m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
<< "m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
<< "m_title: " << settings.m_title;
if ((m_settings.m_log2Decim != settings.m_log2Decim)
|| (m_settings.m_filterChainHash != settings.m_filterChainHash) || force)
{
@ -103,6 +127,28 @@ void Interferometer::applySettings(const InterferometerSettings& settings, bool
settings.m_log2Decim, settings.m_filterChainHash);
m_sink->getInputMessageQueue()->push(msg);
}
if ((m_settings.m_correlationType != settings.m_correlationType) || force)
{
InterferometerSink::MsgConfigureCorrelation *msg = InterferometerSink::MsgConfigureCorrelation::create(
settings.m_correlationType);
m_sink->getInputMessageQueue()->push(msg);
}
m_settings = settings;
}
void Interferometer::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
if (handleMessage(*message))
{
delete message;
}
}
}
bool Interferometer::handleMessage(const Message& cmd)
@ -114,27 +160,39 @@ bool Interferometer::handleMessage(const Message& cmd)
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (DSPSignalNotification::match(cmd))
else if (DSPMIMOSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
DSPMIMOSignalNotification& notif = (DSPMIMOSignalNotification&) cmd;
qDebug() << "Interferometer::handleMessage: DSPSignalNotification:"
qDebug() << "Interferometer::handleMessage: DSPMIMOSignalNotification:"
<< " inputSampleRate: " << notif.getSampleRate()
<< " centerFrequency: " << notif.getCenterFrequency();
<< " centerFrequency: " << notif.getCenterFrequency()
<< " sourceElseSink: " << notif.getSourceOrSink()
<< " streamIndex: " << notif.getIndex();
m_deviceSampleRate = notif.getSampleRate();
calculateFrequencyOffset(); // This is when device sample rate changes
// Redo the channelizer stuff with the new sample rate to re-synchronize everything
InterferometerSink::MsgConfigureChannelizer *msg = InterferometerSink::MsgConfigureChannelizer::create(
m_settings.m_log2Decim,
m_settings.m_filterChainHash);
m_sink->getInputMessageQueue()->push(msg);
if (m_guiMessageQueue)
if (notif.getSourceOrSink()) // deals with source messages only
{
MsgSampleRateNotification *msg = MsgSampleRateNotification::create(notif.getSampleRate());
m_guiMessageQueue->push(msg);
m_deviceSampleRate = notif.getSampleRate();
calculateFrequencyOffset(); // This is when device sample rate changes
// Notify sink of input sample rate change
InterferometerSink::MsgSignalNotification *sig = InterferometerSink::MsgSignalNotification::create(
m_deviceSampleRate, notif.getCenterFrequency(), notif.getIndex()
);
m_sink->getInputMessageQueue()->push(sig);
// Redo the channelizer stuff with the new sample rate to re-synchronize everything
InterferometerSink::MsgConfigureChannelizer *msg = InterferometerSink::MsgConfigureChannelizer::create(
m_settings.m_log2Decim,
m_settings.m_filterChainHash);
m_sink->getInputMessageQueue()->push(msg);
if (m_guiMessageQueue)
{
MsgBasebandNotification *msg = MsgBasebandNotification::create(
notif.getSampleRate(), notif.getCenterFrequency());
m_guiMessageQueue->push(msg);
}
}
return true;
@ -185,6 +243,12 @@ void Interferometer::calculateFrequencyOffset()
m_frequencyOffset = m_deviceSampleRate * shiftFactor;
}
void Interferometer::applyChannelSettings(uint32_t log2Decim, uint32_t filterChainHash)
{
InterferometerSink::MsgConfigureChannelizer *msg = InterferometerSink::MsgConfigureChannelizer::create(log2Decim, filterChainHash);
m_sink->getInputMessageQueue()->push(msg);
}
int Interferometer::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)

View File

@ -21,7 +21,7 @@
#include <vector>
#include <QNetworkRequest>
#include "dsp/mimosamplesink.h"
#include "dsp/mimochannel.h"
#include "channel/channelapi.h"
#include "util/messagequeue.h"
#include "util/message.h"
@ -35,7 +35,7 @@ class QNetworkReply;
class QNetworkAccessManager;
class BasebandSampleSink;
class Interferometer: public MIMOSampleSink, public ChannelAPI
class Interferometer: public MIMOChannel, public ChannelAPI
{
Q_OBJECT
public:
@ -62,46 +62,27 @@ public:
{ }
};
class MsgConfigureChannelizer : public Message {
class MsgBasebandNotification : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getLog2Decim() const { return m_log2Decim; }
int getFilterChainHash() const { return m_filterChainHash; }
static MsgConfigureChannelizer* create(unsigned int log2Decim, unsigned int filterChainHash) {
return new MsgConfigureChannelizer(log2Decim, filterChainHash);
}
private:
unsigned int m_log2Decim;
unsigned int m_filterChainHash;
MsgConfigureChannelizer(unsigned int log2Decim, unsigned int filterChainHash) :
Message(),
m_log2Decim(log2Decim),
m_filterChainHash(filterChainHash)
{ }
};
class MsgSampleRateNotification : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgSampleRateNotification* create(int sampleRate) {
return new MsgSampleRateNotification(sampleRate);
static MsgBasebandNotification* create(int sampleRate, qint64 centerFrequency) {
return new MsgBasebandNotification(sampleRate, centerFrequency);
}
int getSampleRate() const { return m_sampleRate; }
qint64 getCenterFrequency() const { return m_centerFrequency; }
private:
MsgSampleRateNotification(int sampleRate) :
MsgBasebandNotification(int sampleRate, qint64 centerFrequency) :
Message(),
m_sampleRate(sampleRate)
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
int m_sampleRate;
qint64 m_centerFrequency;
};
Interferometer(DeviceAPI *deviceAPI);
@ -111,6 +92,7 @@ public:
virtual void start(); //!< thread start()
virtual void stop(); //!< thread exit() and wait()
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, unsigned int sinkIndex);
virtual void pull(Sample& sample, unsigned int sourceIndex);
virtual bool handleMessage(const Message& cmd); //!< Processing of a message. Returns true if message has actually been processed
virtual void getIdentifier(QString& id) { id = objectName(); }
@ -136,6 +118,7 @@ public:
void setSpectrumSink(BasebandSampleSink *spectrumSink);
void setScopeSink(BasebandSampleSink *scopeSink);
void applyChannelSettings(uint32_t log2Decim, uint32_t filterChainHash);
virtual int webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
@ -158,6 +141,7 @@ public:
static const QString m_channelIdURI;
static const QString m_channelId;
static const int m_fftSize;
private:
DeviceAPI *m_deviceAPI;
@ -181,6 +165,7 @@ private:
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const InterferometerSettings& settings, bool force);
private slots:
void handleInputMessages();
void networkManagerFinished(QNetworkReply *reply);
void handleData(int start, int stop);
};

View File

@ -25,7 +25,10 @@ Sample sAdd(const Sample& a, const Sample& b) { //!< Sample addition
}
Sample sMulConj(const Sample& a, const Sample& b) { //!< Sample multiply with conjugate
return Sample{a.real()*b.real() + a.imag()*b.imag(), a.imag()*b.real() - a.real()*b.imag()};
Sample s;
s.setReal((a.real()*b.real() + a.imag()*b.imag()) / (1<<(SDR_RX_SAMP_SZ - 16 + 1)));
s.setImag((a.imag()*b.real() - a.real()*b.imag()) / (1<<(SDR_RX_SAMP_SZ - 16 + 1)));
return s;
}
Sample cf2s(const std::complex<float>& a) { //!< Complex float to Sample
@ -35,6 +38,13 @@ Sample cf2s(const std::complex<float>& a) { //!< Complex float to Sample
return s;
}
Sample invfft2s(const std::complex<float>& a) { //!< Complex float to Sample
Sample s;
s.setReal(a.real());
s.setImag(a.imag());
return s;
}
InterferometerCorrelator::InterferometerCorrelator(int fftSize) :
m_corrType(InterferometerSettings::CorrelationAdd),
m_fftSize(fftSize)
@ -55,35 +65,50 @@ InterferometerCorrelator::InterferometerCorrelator(int fftSize) :
InterferometerCorrelator::~InterferometerCorrelator()
{
for (int i = 0; i < 2; i++)
{
delete[] m_fft[i];
}
delete[] m_dataj;
delete m_invFFT;
for (int i = 0; i < 2; i++) {
delete m_fft[i];
}
}
void InterferometerCorrelator::performCorr(const SampleVector& data0, const SampleVector& data1)
bool InterferometerCorrelator::performCorr(
const SampleVector& data0,
int size0,
const SampleVector& data1,
int size1
)
{
bool results = false;
switch (m_corrType)
{
case InterferometerSettings::CorrelationAdd:
performOpCorr(data0, data1, sAdd);
results = performOpCorr(data0, size0, data1, size1, sAdd);
break;
case InterferometerSettings::CorrelationMultiply:
performOpCorr(data0, data1, sMulConj);
results = performOpCorr(data0, size0, data1, size1, sMulConj);
break;
case InterferometerSettings::CorrelationCorrelation:
performFFTCorr(data0, data1);
case InterferometerSettings::CorrelationFFT:
results = performFFTCorr(data0, size0, data1, size1);
break;
default:
break;
}
return results;
}
void InterferometerCorrelator::performOpCorr(const SampleVector& data0, const SampleVector& data1, Sample sampleOp(const Sample& a, const Sample& b))
bool InterferometerCorrelator::performOpCorr(
const SampleVector& data0,
int size0,
const SampleVector& data1,
int size1,
Sample sampleOp(const Sample& a, const Sample& b)
)
{
unsigned int size = std::min(data0.size(), data1.size());
unsigned int size = std::min(size0, size1);
adjustTCorrSize(size);
std::transform(
@ -95,12 +120,20 @@ void InterferometerCorrelator::performOpCorr(const SampleVector& data0, const Sa
);
m_processed = size;
m_remaining = 0;
m_remaining[0] = size0 - size;
m_remaining[1] = size1 - size;
return true;
}
void InterferometerCorrelator::performFFTCorr(const SampleVector& data0, const SampleVector& data1)
bool InterferometerCorrelator::performFFTCorr(
const SampleVector& data0,
int size0,
const SampleVector& data1,
int size1
)
{
unsigned int size = std::min(data0.size(), data1.size());
unsigned int size = std::min(size0, size1);
int nfft = 0;
SampleVector::const_iterator begin0 = data0.begin();
SampleVector::const_iterator begin1 = data1.begin();
adjustSCorrSize(size);
@ -167,18 +200,21 @@ void InterferometerCorrelator::performFFTCorr(const SampleVector& data0, const S
m_invFFT->out(),
m_invFFT->out() + 2*m_fftSize,
m_tcorr.begin(),
cf2s
invfft2s
);
// TODO: do something with the result
size -= m_fftSize;
begin0 += m_fftSize;
begin1 += m_fftSize;
nfft++;
}
// update the samples counters
m_processed = begin0 - data0.begin();
m_remaining = size - m_fftSize;
m_processed = nfft*m_fftSize;
m_remaining[0] = size0 - nfft*m_fftSize;
m_remaining[1] = size1 - nfft*m_fftSize;
return nfft > 0;
}
void InterferometerCorrelator::adjustSCorrSize(int size)

View File

@ -37,20 +37,36 @@ public:
void setCorrType(InterferometerSettings::CorrelationType corrType) { m_corrType = corrType; }
InterferometerSettings::CorrelationType getCorrType() const { return m_corrType; }
void performCorr(const SampleVector& data0, const SampleVector& data1);
bool performCorr( //!< Returns true if results were produced
const SampleVector& data0,
int size0,
const SampleVector& data1,
int size1
);
int getFullFFTSize() const { return 2*m_fftSize; }
SampleVector m_scorr; //!< raw correlation result (spectrum) - Sample vector expected
SampleVector m_tcorr; //!< correlation result (time or spectrum inverse FFT) - Sample vector expected
int m_processed; //!< number of samples processed at the end of correlation
int m_remaining; //!< number of samples remaining at the end of correlation
int m_remaining[2]; //!< number of samples remaining per member at the end of correlation
signals:
void dataReady(int start, int stop);
private:
void performOpCorr(const SampleVector& data0, const SampleVector& data1, Sample sampleOp(const Sample& a, const Sample& b));
void performFFTCorr(const SampleVector& data0, const SampleVector& data1);
bool performOpCorr( //!< Returns true if results were produced
const SampleVector& data0,
int size0,
const SampleVector& data1,
int size1,
Sample sampleOp(const Sample& a, const Sample& b)
);
bool performFFTCorr( //!< Returns true if results were produced
const SampleVector& data0,
int size0,
const SampleVector& data1,
int size1
);
void adjustSCorrSize(int size);
void adjustTCorrSize(int size);

View File

@ -20,12 +20,15 @@
#include "device/deviceuiset.h"
#include "gui/basicchannelsettingsdialog.h"
#include "dsp/hbfilterchainconverter.h"
#include "dsp/scopevis.h"
#include "dsp/spectrumvis.h"
#include "mainwindow.h"
#include "interferometergui.h"
#include "interferometer.h"
#include "ui_interferometergui.h"
InterferometerGUI* InterferometerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *channelMIMO)
InterferometerGUI* InterferometerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *channelMIMO)
{
InterferometerGUI* gui = new InterferometerGUI(pluginAPI, deviceUISet, channelMIMO);
return gui;
@ -47,7 +50,7 @@ QString InterferometerGUI::getName() const
}
qint64 InterferometerGUI::getCenterFrequency() const {
return 0;
return m_centerFrequency;
}
void InterferometerGUI::setCenterFrequency(qint64 centerFrequency)
@ -79,13 +82,18 @@ bool InterferometerGUI::deserialize(const QByteArray& data)
}
}
MessageQueue* InterferometerGUI::getInputMessageQueue()
{
return &m_inputMessageQueue;
}
bool InterferometerGUI::handleMessage(const Message& message)
{
if (Interferometer::MsgSampleRateNotification::match(message))
if (Interferometer::MsgBasebandNotification::match(message))
{
Interferometer::MsgSampleRateNotification& notif = (Interferometer::MsgSampleRateNotification&) message;
m_channelMarker.setBandwidth(notif.getSampleRate());
Interferometer::MsgBasebandNotification& notif = (Interferometer::MsgBasebandNotification&) message;
m_sampleRate = notif.getSampleRate();
m_centerFrequency = notif.getCenterFrequency();
displayRateAndShift();
return true;
}
@ -95,23 +103,42 @@ bool InterferometerGUI::handleMessage(const Message& message)
}
}
InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *channelMIMO, QWidget* parent) :
InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *channelMIMO, QWidget* parent) :
RollupWidget(parent),
ui(new Ui::InterferometerGUI),
m_pluginAPI(pluginAPI),
m_deviceUISet(deviceUISet),
m_sampleRate(0),
m_sampleRate(48000),
m_centerFrequency(435000000),
m_tickCount(0)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
setStreamIndicator("M");
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_spectrumVis = new SpectrumVis(SDR_RX_SCALEF, ui->glSpectrum);
m_scopeVis = new ScopeVis(ui->glScope);
m_interferometer = (Interferometer*) channelMIMO;
m_interferometer->setScopeSink(m_scopeVis);
m_interferometer->setSpectrumSink(m_spectrumVis);
m_interferometer->setMessageQueueToGUI(getInputMessageQueue());
ui->glSpectrum->setDisplayWaterfall(true);
ui->glSpectrum->setDisplayMaxHold(true);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSsbSpectrum(false);
ui->glSpectrum->setLsbDisplay(false);
ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer());
ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer());
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
m_channelMarker.blockSignals(true);
m_channelMarker.addStreamIndex(1);
m_channelMarker.setColor(m_settings.m_rgbColor);
m_channelMarker.setCenterFrequency(0);
m_channelMarker.setTitle("Interferometer");
@ -120,21 +147,30 @@ InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI
m_settings.setChannelMarker(&m_channelMarker);
// m_deviceUISet->registerRxChannelInstance(LocalSink::m_channelIdURI, this);
m_deviceUISet->registerChannelInstance(Interferometer::m_channelIdURI, this);
m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this);
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
m_scopeVis->setTraceChunkSize(Interferometer::m_fftSize); // Set scope trace length unit to FFT size
ui->scopeGUI->traceLengthChange();
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
//connect(&(m_deviceUISet->m_deviceSourceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick()));
displaySettings();
displayRateAndShift();
applySettings(true);
}
InterferometerGUI::~InterferometerGUI()
{
//m_deviceUISet->removeRxChannelInstance(this);
m_deviceUISet->removeChannelInstance(this);
delete m_interferometer; // TODO: check this: when the GUI closes it has to delete the demodulator
delete m_spectrumVis;
delete m_scopeVis;
delete ui;
}
@ -154,17 +190,6 @@ void InterferometerGUI::applySettings(bool force)
}
}
void InterferometerGUI::applyChannelSettings()
{
if (m_doApplySettings)
{
Interferometer::MsgConfigureChannelizer *msgChan = Interferometer::MsgConfigureChannelizer::create(
m_settings.m_log2Decim,
m_settings.m_filterChainHash);
m_interferometer->getInputMessageQueue()->push(msgChan);
}
}
void InterferometerGUI::displaySettings()
{
m_channelMarker.blockSignals(true);
@ -193,6 +218,8 @@ void InterferometerGUI::displayRateAndShift()
ui->channelRateText->setText(tr("%1k").arg(QString::number(channelSampleRate / 1000.0, 'g', 5)));
m_channelMarker.setCenterFrequency(shift);
m_channelMarker.setBandwidth(channelSampleRate);
ui->glSpectrum->setSampleRate(channelSampleRate);
m_scopeVis->setLiveRate(channelSampleRate);
}
void InterferometerGUI::leaveEvent(QEvent*)
@ -267,6 +294,12 @@ void InterferometerGUI::on_position_valueChanged(int value)
applyPosition();
}
void InterferometerGUI::on_correlationType_currentIndexChanged(int index)
{
m_settings.m_correlationType = (InterferometerSettings::CorrelationType) index;
applySettings();
}
void InterferometerGUI::applyDecimation()
{
uint32_t maxHash = 1;
@ -289,7 +322,7 @@ void InterferometerGUI::applyPosition()
ui->filterChainText->setText(s);
displayRateAndShift();
applyChannelSettings();
applySettings();
}
void InterferometerGUI::tick()

View File

@ -28,7 +28,7 @@
class PluginAPI;
class DeviceUISet;
class MIMOSampleSink;
class MIMOChannel;
class Interferometer;
class SpectrumVis;
class ScopeVis;
@ -40,7 +40,7 @@ namespace Ui {
class InterferometerGUI : public RollupWidget, public PluginInstanceGUI {
Q_OBJECT
public:
static InterferometerGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *mimoChannel);
static InterferometerGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *mimoChannel);
virtual void destroy();
virtual void setName(const QString& name);
@ -64,6 +64,7 @@ private:
ChannelMarker m_channelMarker;
InterferometerSettings m_settings;
int m_sampleRate;
qint64 m_centerFrequency;
double m_shiftFrequencyFactor; //!< Channel frequency shift factor
bool m_doApplySettings;
MovingAverageUtil<double, double, 40> m_channelPowerAvg;
@ -73,12 +74,11 @@ private:
MessageQueue m_inputMessageQueue;
uint32_t m_tickCount;
explicit InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *rxChannel, QWidget* parent = nullptr);
explicit InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *rxChannel, QWidget* parent = nullptr);
virtual ~InterferometerGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void applyChannelSettings();
void applyDecimation();
void applyPosition();
void displaySettings();
@ -91,6 +91,7 @@ private slots:
void handleSourceMessages();
void on_decimationFactor_currentIndexChanged(int index);
void on_position_valueChanged(int value);
void on_correlationType_currentIndexChanged(int index);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();

View File

@ -150,6 +150,42 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Corr</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="correlationType">
<property name="toolTip">
<string>Correlation type</string>
</property>
<item>
<property name="text">
<string>Add</string>
</property>
</item>
<item>
<property name="text">
<string>Mul</string>
</property>
</item>
<item>
<property name="text">
<string>FFT</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
@ -182,28 +218,6 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelPower">
<property name="minimumSize">
<size>
<width>52</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>-100.0 dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -257,61 +271,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="BWLayout">
<item>
<widget class="QLabel" name="BWLabel">
<property name="minimumSize">
<size>
<width>15</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>BP</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="BW">
<property name="toolTip">
<string>Lowpass filter cutoff frequency</string>
</property>
<property name="minimum">
<number>-60</number>
</property>
<property name="maximum">
<number>60</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="BWText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>3.0k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="spectrumContainer" native="true">
@ -330,7 +289,7 @@
</size>
</property>
<property name="windowTitle">
<string>Channel Spectrum</string>
<string>Frequency domain</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutSpectrum">
<property name="spacing">
@ -385,7 +344,7 @@
</size>
</property>
<property name="windowTitle">
<string>Channel Scope</string>
<string>Time domain</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutScope">
<property name="spacing">

View File

@ -58,18 +58,18 @@ void InterferometerPlugin::initPlugin(PluginAPI* pluginAPI)
#ifdef SERVER_MODE
PluginInstanceGUI* InterferometerPlugin::createRxChannelGUI(
DeviceUISet *deviceUISet,
MIMOSampleSink *mimoChannel) const
MIMOChannel *mimoChannel) const
{
return 0;
}
#else
PluginInstanceGUI* InterferometerPlugin::createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOSampleSink *mimoChannel) const
PluginInstanceGUI* InterferometerPlugin::createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOChannel *mimoChannel) const
{
return InterferometerGUI::create(m_pluginAPI, deviceUISet, mimoChannel);
}
#endif
MIMOSampleSink* InterferometerPlugin::createMIMOChannelBS(DeviceAPI *deviceAPI) const
MIMOChannel* InterferometerPlugin::createMIMOChannelBS(DeviceAPI *deviceAPI) const
{
return new Interferometer(deviceAPI);
}

View File

@ -23,7 +23,7 @@
#include "plugin/plugininterface.h"
class DeviceUISet;
class MIMOSampleSink;
class MIMOChannel;
class InterferometerPlugin : public QObject, PluginInterface {
Q_OBJECT
@ -36,8 +36,8 @@ public:
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual PluginInstanceGUI* createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOSampleSink *mimoChannel) const;
virtual MIMOSampleSink* createMIMOChannelBS(DeviceAPI *deviceAPI) const;
virtual PluginInstanceGUI* createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOChannel *mimoChannel) const;
virtual MIMOChannel* createMIMOChannelBS(DeviceAPI *deviceAPI) const;
virtual ChannelAPI* createMIMOChannelCS(DeviceAPI *deviceAPI) const;
virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const;

View File

@ -29,7 +29,7 @@ struct InterferometerSettings
{
CorrelationAdd,
CorrelationMultiply,
CorrelationCorrelation
CorrelationFFT
};
CorrelationType m_correlationType;

View File

@ -18,25 +18,37 @@
#include <QDebug>
#include "dsp/downchannelizer.h"
#include "dsp/dspcommands.h"
#include "interferometersink.h"
MESSAGE_CLASS_DEFINITION(InterferometerSink::MsgConfigureChannelizer, Message)
MESSAGE_CLASS_DEFINITION(InterferometerSink::MsgSignalNotification, Message)
MESSAGE_CLASS_DEFINITION(InterferometerSink::MsgConfigureCorrelation, Message)
InterferometerSink::InterferometerSink() :
m_correlator(4096),
InterferometerSink::InterferometerSink(int fftSize) :
m_correlator(fftSize),
m_spectrumSink(nullptr),
m_scopeSink(nullptr)
{
for (int i = 0; i < 2; i++)
{
m_sinkFifos[i].setSize(96000 * 4);
m_sinks[i].setStreamIndex(i);
m_channelizers[i] = new DownChannelizer(&m_sinks[i]);
// QObject::connect(
// &m_sinkBuffers[i],
// &SampleSinkVector::dataReady,
// this,
// [=](){ this->handleSinkBuffer(i); },
// Qt::QueuedConnection
// );
QObject::connect(
&m_sinkBuffers[i],
&SampleSinkVector::dataReady,
&m_sinkFifos[i],
&SampleSinkFifo::dataReady,
this,
[=](){ this->handleSinkBuffer(i); },
[=](){ this->handleSinkFifo(i); },
Qt::QueuedConnection
);
}
@ -58,14 +70,55 @@ void InterferometerSink::feed(const SampleVector::const_iterator& begin, const S
return;
}
m_sinkBuffers[streamIndex].write(begin, end);
m_sinkFifos[streamIndex].write(begin, end);
//m_sinkBuffers[streamIndex].write(begin, end);
}
void InterferometerSink::handleSinkBuffer(unsigned int sinkIndex)
// void InterferometerSink::handleSinkBuffer(unsigned int sinkIndex)
// {
// SampleVector::iterator vbegin;
// SampleVector::iterator vend;
// m_sinkBuffers[sinkIndex].read(vbegin, vend);
// m_channelizers[sinkIndex]->feed(vbegin, vend, false);
// //qDebug("InterferometerSink::handleSinkBuffer: stream: %u samples: %ld", sinkIndex, vend - vbegin);
// if (sinkIndex == 1) {
// run();
// }
// }
void InterferometerSink::handleSinkFifo(unsigned int sinkIndex)
{
int samplesDone = 0;
while ((m_sinkFifos[sinkIndex].fill() > 0) && (m_inputMessageQueue.size() == 0) && (samplesDone < m_channelizers[sinkIndex]->getInputSampleRate()))
{
SampleVector::iterator part1begin;
SampleVector::iterator part1end;
SampleVector::iterator part2begin;
SampleVector::iterator part2end;
unsigned int count = m_sinkFifos[sinkIndex].readBegin(m_sinkFifos[sinkIndex].fill(), &part1begin, &part1end, &part2begin, &part2end);
if (part1begin != part1end) { // first part of FIFO data
//qDebug("InterferometerSink::handleSinkFifo: part1-stream: %u count: %u", sinkIndex, count);
processFifo(part1begin, part1end, sinkIndex);
}
if (part2begin != part2end) { // second part of FIFO data (used when block wraps around)
//qDebug("InterferometerSink::handleSinkFifo: part2-stream: %u count: %u", sinkIndex, count);
processFifo(part2begin, part2end, sinkIndex);
}
m_sinkFifos[sinkIndex].readCommit((unsigned int) count); // adjust FIFO pointers
samplesDone += count;
}
//qDebug("InterferometerSink::handleSinkFifo: done");
}
void InterferometerSink::processFifo(const SampleVector::iterator& vbegin, const SampleVector::iterator& vend, unsigned int sinkIndex)
{
SampleVector::iterator vbegin;
SampleVector::iterator vend;
m_sinkBuffers[sinkIndex].read(vbegin, vend);
m_channelizers[sinkIndex]->feed(vbegin, vend, false);
if (sinkIndex == 1) {
@ -75,35 +128,32 @@ void InterferometerSink::handleSinkBuffer(unsigned int sinkIndex)
void InterferometerSink::run()
{
m_correlator.performCorr(m_sinks[0].getData(), m_sinks[1].getData());
if (m_scopeSink) {
m_scopeSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false);
}
if (m_spectrumSink)
if (m_correlator.performCorr(m_sinks[0].getData(), m_sinks[0].getSize(), m_sinks[1].getData(), m_sinks[1].getSize()))
{
if (m_correlator.getCorrType() == InterferometerSettings::CorrelationCorrelation) {
m_spectrumSink->feed(m_correlator.m_scorr.begin(), m_correlator.m_scorr.begin() + m_correlator.m_processed, false);
} else {
m_spectrumSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false);
if (m_scopeSink) {
m_scopeSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false);
}
}
if (m_correlator.m_remaining != 0)
{
for (int i = 0; i < 2; i++)
if (m_spectrumSink)
{
std::copy(
m_sinks[i].getData().begin() + m_correlator.m_processed,
m_sinks[i].getData().begin() + m_correlator.m_processed + m_correlator.m_remaining,
m_sinks[i].getData().begin()
);
if (m_correlator.getCorrType() == InterferometerSettings::CorrelationFFT) {
m_spectrumSink->feed(m_correlator.m_scorr.begin(), m_correlator.m_scorr.begin() + m_correlator.m_processed, false);
} else {
m_spectrumSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false);
}
}
}
m_sinks[0].setDataStart(m_correlator.m_remaining);
m_sinks[1].setDataStart(m_correlator.m_remaining);
for (int i = 0; i < 2; i++)
{
std::copy(
m_sinks[i].getData().begin() + m_correlator.m_processed,
m_sinks[i].getData().begin() + m_correlator.m_processed + m_correlator.m_remaining[i],
m_sinks[i].getData().begin()
);
m_sinks[i].setDataStart(m_correlator.m_remaining[i]);
}
}
void InterferometerSink::handleInputMessages()
@ -140,6 +190,38 @@ bool InterferometerSink::handleMessage(const Message& cmd)
return true;
}
else if (MsgSignalNotification::match(cmd))
{
MsgSignalNotification& cfg = (MsgSignalNotification&) cmd;
int inputSampleRate = cfg.getInputSampleRate();
qint64 centerFrequency = cfg.getCenterFrequency();
int streamIndex = cfg.getStreamIndex();
qDebug() << "InterferometerSink::handleMessage: MsgSignalNotification:"
<< " inputSampleRate: " << inputSampleRate
<< " centerFrequency: " << centerFrequency
<< " streamIndex: " << streamIndex;
if (streamIndex < 2)
{
DSPSignalNotification *notif = new DSPSignalNotification(inputSampleRate, centerFrequency);
m_channelizers[streamIndex]->getInputMessageQueue()->push(notif);
}
return true;
}
else if (MsgConfigureCorrelation::match(cmd))
{
MsgConfigureCorrelation& cfg = (MsgConfigureCorrelation&) cmd;
InterferometerSettings::CorrelationType correlationType = cfg.getCorrelationType();
qDebug() << "InterferometerSink::handleMessage: MsgConfigureCorrelation:"
<< " correlationType: " << correlationType;
m_correlator.setCorrType(correlationType);
return true;
}
else
{
return false;

View File

@ -20,8 +20,8 @@
#include <QObject>
#include "dsp/mimosamplesink.h"
#include "dsp/samplesinkvector.h"
//#include "dsp/samplesinkvector.h"
#include "dsp/samplesinkfifo.h"
#include "interferometerstreamsink.h"
#include "interferometercorr.h"
@ -54,7 +54,50 @@ public:
{ }
};
InterferometerSink();
class MsgConfigureCorrelation : public Message {
MESSAGE_CLASS_DECLARATION
public:
InterferometerSettings::CorrelationType getCorrelationType() const { return m_correlationType; }
static MsgConfigureCorrelation *create(InterferometerSettings::CorrelationType correlationType) {
return new MsgConfigureCorrelation(correlationType);
}
private:
InterferometerSettings::CorrelationType m_correlationType;
MsgConfigureCorrelation(InterferometerSettings::CorrelationType correlationType) :
Message(),
m_correlationType(correlationType)
{}
};
class MsgSignalNotification : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getInputSampleRate() const { return m_inputSampleRate; }
qint64 getCenterFrequency() const { return m_centerFrequency; }
int getStreamIndex() const { return m_streamIndex; }
static MsgSignalNotification* create(int inputSampleRate, qint64 centerFrequency, int streamIndex) {
return new MsgSignalNotification(inputSampleRate, centerFrequency, streamIndex);
}
private:
int m_inputSampleRate;
qint64 m_centerFrequency;
int m_streamIndex;
MsgSignalNotification(int inputSampleRate, qint64 centerFrequency, int streamIndex) :
Message(),
m_inputSampleRate(inputSampleRate),
m_centerFrequency(centerFrequency),
m_streamIndex(streamIndex)
{ }
};
InterferometerSink(int fftSize);
~InterferometerSink();
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
@ -64,11 +107,13 @@ public:
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, unsigned int streamIndex);
private:
void processFifo(const SampleVector::iterator& vbegin, const SampleVector::iterator& vend, unsigned int sinkIndex);
void run();
bool handleMessage(const Message& cmd);
InterferometerCorrelator m_correlator;
SampleSinkVector m_sinkBuffers[2];
//SampleSinkVector m_sinkBuffers[2];
SampleSinkFifo m_sinkFifos[2];
InterferometerStreamSink m_sinks[2];
DownChannelizer *m_channelizers[2];
BasebandSampleSink *m_spectrumSink;
@ -76,7 +121,8 @@ private:
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
private slots:
void handleSinkBuffer(unsigned int sinkIndex); //!< Handle data when samples have to be processed
//void handleSinkBuffer(unsigned int sinkIndex); //!< Handle data when samples have to be processed
void handleSinkFifo(unsigned int sinkIndex); //!< Handle data when samples have to be processed
void handleInputMessages();
};

View File

@ -24,6 +24,7 @@ InterferometerStreamSink::InterferometerStreamSink() :
m_streamIndex(0),
m_dataSize(0),
m_bufferSize(0),
m_dataStart(0),
m_sampleRate(48000),
m_settingsMutex(QMutex::Recursive)
{}
@ -42,8 +43,10 @@ void InterferometerStreamSink::feed(const SampleVector::const_iterator& begin, c
m_settingsMutex.lock();
m_dataSize = (end - begin) + m_dataStart;
if (m_dataSize > m_bufferSize) {
if (m_dataSize > m_bufferSize)
{
m_data.resize(m_dataSize);
m_bufferSize = m_dataSize;
}
std::copy(begin, end, m_data.begin() + m_dataStart);
@ -57,6 +60,7 @@ bool InterferometerStreamSink::handleMessage(const Message& cmd)
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
qDebug() << "InterferometerStreamSink::handleMessage: MsgChannelizerNotification:"
<< " streamIndex: " << m_streamIndex
<< " inputSampleRate: " << notif.getSampleRate()
<< " inputFrequencyOffset: " << notif.getFrequencyOffset();
m_sampleRate = notif.getSampleRate();

View File

@ -39,6 +39,7 @@ public:
unsigned int getStreamIndex() const { return m_streamIndex; }
void setStreamIndex(unsigned int streamIndex) { m_streamIndex = streamIndex; }
SampleVector& getData() { return m_data; }
int getSize() const { return m_dataSize; }
void setDataStart(int dataStart) { m_dataStart = dataStart; }
private:

View File

@ -454,6 +454,12 @@ void MainWindow::addMIMODevice()
m_deviceUIs.back()->m_deviceAPI = deviceAPI;
m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
QComboBox *channelSelector = m_deviceUIs.back()->m_samplingDeviceControl->getChannelSelector();
// add MIMO channels
QList<QString> mimoChannelNames;
m_pluginManager->listMIMOChannels(mimoChannelNames);
QStringList mimoChannelNamesList(mimoChannelNames);
channelSelector->addItems(mimoChannelNamesList);
m_deviceUIs.back()->setNumberOfAvailableMIMOChannels(mimoChannelNamesList.size());
// Add Rx channels
QList<QString> rxChannelNames;
m_pluginManager->listRxChannels(rxChannelNames);
@ -1952,18 +1958,22 @@ void MainWindow::channelAddClicked(bool checked)
}
else if (deviceUI->m_deviceMIMOEngine) // MIMO device => all possible channels. Depends on index range
{
int nbMIMOChannels = deviceUI->getNumberOfAvailableMIMOChannels();
int nbRxChannels = deviceUI->getNumberOfAvailableRxChannels();
int nbTxChannels = deviceUI->getNumberOfAvailableTxChannels();
int selectedIndex = deviceUI->m_samplingDeviceControl->getChannelSelector()->currentIndex();
qDebug("MainWindow::channelAddClicked: MIMO: tab: %d nbRx: %d nbTx: %d selected: %d",
currentSourceTabIndex, nbRxChannels, nbTxChannels, selectedIndex);
qDebug("MainWindow::channelAddClicked: MIMO: tab: %d nbMIMO: %d nbRx: %d nbTx: %d selected: %d",
currentSourceTabIndex, nbMIMOChannels, nbRxChannels, nbTxChannels, selectedIndex);
if (selectedIndex < nbRxChannels) {
m_pluginManager->createRxChannelInstance(
if (selectedIndex < nbMIMOChannels) {
m_pluginManager->createMIMOChannelInstance(
selectedIndex, deviceUI, deviceUI->m_deviceAPI);
} else if (selectedIndex < nbRxChannels + nbTxChannels) {
} else if (selectedIndex < nbMIMOChannels + nbRxChannels) {
m_pluginManager->createRxChannelInstance(
selectedIndex - nbMIMOChannels, deviceUI, deviceUI->m_deviceAPI);
} else if (selectedIndex < nbMIMOChannels + nbRxChannels + nbTxChannels) {
m_pluginManager->createTxChannelInstance(
selectedIndex - nbRxChannels, deviceUI, deviceUI->m_deviceAPI);
selectedIndex - nbMIMOChannels - nbRxChannels, deviceUI, deviceUI->m_deviceAPI);
}
}
}