mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-26 01:39:05 -05:00
SoapySDR support: output: auto correction GUIs
This commit is contained in:
parent
fd3ea0711d
commit
1168c18e3a
@ -250,6 +250,24 @@ void SoapySDROutput::initGainSettings(SoapySDROutputSettings& settings)
|
||||
updateGains(m_deviceShared.m_device, m_deviceShared.m_channel, settings);
|
||||
}
|
||||
|
||||
bool SoapySDROutput::hasDCAutoCorrection()
|
||||
{
|
||||
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getTxChannelSettings(m_deviceShared.m_channel);
|
||||
return channelSettings->m_hasDCAutoCorrection;
|
||||
}
|
||||
|
||||
bool SoapySDROutput::hasDCCorrectionValue()
|
||||
{
|
||||
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getTxChannelSettings(m_deviceShared.m_channel);
|
||||
return channelSettings->m_hasDCOffsetValue;
|
||||
}
|
||||
|
||||
bool SoapySDROutput::hasIQCorrectionValue()
|
||||
{
|
||||
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getTxChannelSettings(m_deviceShared.m_channel);
|
||||
return channelSettings->m_hasIQBalanceValue;
|
||||
}
|
||||
|
||||
void SoapySDROutput::init()
|
||||
{
|
||||
applySettings(m_settings, true);
|
||||
@ -909,6 +927,54 @@ bool SoapySDROutput::applySettings(const SoapySDROutputSettings& settings, bool
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_autoDCCorrection != settings.m_autoDCCorrection) || force)
|
||||
{
|
||||
if ((dev != 0) && hasDCAutoCorrection())
|
||||
{
|
||||
try
|
||||
{
|
||||
dev->setDCOffsetMode(SOAPY_SDR_TX, requestedChannel, settings.m_autoDCCorrection);
|
||||
qDebug("SoapySDROutput::applySettings: %s DC auto correction", settings.m_autoDCCorrection ? "set" : "unset");
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
qCritical("SoapySDROutput::applySettings: cannot %s DC auto correction", settings.m_autoDCCorrection ? "set" : "unset");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_dcCorrection != settings.m_dcCorrection) || force)
|
||||
{
|
||||
if ((dev != 0) && hasDCCorrectionValue())
|
||||
{
|
||||
try
|
||||
{
|
||||
dev->setDCOffset(SOAPY_SDR_TX, requestedChannel, settings.m_dcCorrection);
|
||||
qDebug("SoapySDROutput::applySettings: DC offset correction set to (%lf, %lf)", settings.m_dcCorrection.real(), settings.m_dcCorrection.imag());
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
qCritical("SoapySDROutput::applySettings: cannot set DC offset correction to (%lf, %lf)", settings.m_dcCorrection.real(), settings.m_dcCorrection.imag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force)
|
||||
{
|
||||
if ((dev != 0) && hasIQCorrectionValue())
|
||||
{
|
||||
try
|
||||
{
|
||||
dev->setIQBalance(SOAPY_SDR_TX, requestedChannel, settings.m_iqCorrection);
|
||||
qDebug("SoapySDROutput::applySettings: IQ balance correction set to (%lf, %lf)", settings.m_iqCorrection.real(), settings.m_iqCorrection.imag());
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
qCritical("SoapySDROutput::applySettings: cannot set IQ balance correction to (%lf, %lf)", settings.m_iqCorrection.real(), settings.m_iqCorrection.imag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forwardChangeOwnDSP)
|
||||
{
|
||||
int sampleRate = settings.m_devSampleRate/(1<<settings.m_log2Interp);
|
||||
|
@ -134,6 +134,10 @@ public:
|
||||
const std::vector<DeviceSoapySDRParams::FrequencySetting>& getTunableElements();
|
||||
const std::vector<DeviceSoapySDRParams::GainSetting>& getIndividualGainsRanges();
|
||||
void initGainSettings(SoapySDROutputSettings& settings);
|
||||
bool hasDCAutoCorrection();
|
||||
bool hasDCCorrectionValue();
|
||||
bool hasIQAutoCorrection() { return false; } // not in SoapySDR interface
|
||||
bool hasIQCorrectionValue();
|
||||
|
||||
private:
|
||||
DeviceSinkAPI *m_deviceAPI;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "soapygui/stringrangegui.h"
|
||||
#include "soapygui/dynamicitemsettinggui.h"
|
||||
#include "soapygui/intervalslidergui.h"
|
||||
#include "soapygui/complexfactorgui.h"
|
||||
|
||||
#include "soapysdroutputgui.h"
|
||||
|
||||
@ -45,7 +46,11 @@ SoapySDROutputGui::SoapySDROutputGui(DeviceUISet *deviceUISet, QWidget* parent)
|
||||
m_sampleRateGUI(0),
|
||||
m_bandwidthGUI(0),
|
||||
m_gainSliderGUI(0),
|
||||
m_autoGain(0)
|
||||
m_autoGain(0),
|
||||
m_dcCorrectionGUI(0),
|
||||
m_iqCorrectionGUI(0),
|
||||
m_autoDCCorrection(0),
|
||||
m_autoIQCorrection(0)
|
||||
{
|
||||
m_sampleSink = (SoapySDROutput*) m_deviceUISet->m_deviceSinkAPI->getSampleSink();
|
||||
ui->setupUi(this);
|
||||
@ -55,6 +60,7 @@ SoapySDROutputGui::SoapySDROutputGui(DeviceUISet *deviceUISet, QWidget* parent)
|
||||
m_sampleSink->getFrequencyRange(f_min, f_max);
|
||||
ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000);
|
||||
|
||||
createCorrectionsControl();
|
||||
createAntennasControl(m_sampleSink->getAntennas());
|
||||
createRangesControl(&m_sampleRateGUI, m_sampleSink->getRateRanges(), "SR", "S/s");
|
||||
createRangesControl(&m_bandwidthGUI, m_sampleSink->getBandwidthRanges(), "BW", "Hz");
|
||||
@ -240,6 +246,57 @@ void SoapySDROutputGui::createIndividualGainsControl(const std::vector<DeviceSoa
|
||||
}
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::createCorrectionsControl()
|
||||
{
|
||||
QVBoxLayout *layout = (QVBoxLayout *) ui->scrollAreaWidgetContents->layout();
|
||||
|
||||
if (m_sampleSink->hasDCCorrectionValue()) // complex GUI
|
||||
{
|
||||
m_dcCorrectionGUI = new ComplexFactorGUI(this);
|
||||
m_dcCorrectionGUI->setLabel(QString("DC"));
|
||||
m_dcCorrectionGUI->setAutomaticEnable(m_sampleSink->hasDCAutoCorrection());
|
||||
layout->addWidget(m_dcCorrectionGUI);
|
||||
|
||||
connect(m_dcCorrectionGUI, SIGNAL(moduleChanged(double)), this, SLOT(dcCorrectionModuleChanged(double)));
|
||||
connect(m_dcCorrectionGUI, SIGNAL(argumentChanged(double)), this, SLOT(dcCorrectionArgumentChanged(double)));
|
||||
|
||||
if (m_sampleSink->hasDCAutoCorrection()) {
|
||||
connect(m_dcCorrectionGUI, SIGNAL(automaticChanged(bool)), this, SLOT(autoDCCorrectionChanged(bool)));
|
||||
}
|
||||
}
|
||||
else if (m_sampleSink->hasDCAutoCorrection()) // simple checkbox
|
||||
{
|
||||
m_autoDCCorrection = new QCheckBox(this);
|
||||
m_autoDCCorrection->setText(QString("DC corr"));
|
||||
layout->addWidget(m_autoDCCorrection);
|
||||
|
||||
connect(m_autoDCCorrection, SIGNAL(toggled(bool)), this, SLOT(autoDCCorrectionChanged(bool)));
|
||||
}
|
||||
|
||||
if (m_sampleSink->hasIQCorrectionValue()) // complex GUI
|
||||
{
|
||||
m_iqCorrectionGUI = new ComplexFactorGUI(this);
|
||||
m_iqCorrectionGUI->setLabel(QString("IQ"));
|
||||
m_iqCorrectionGUI->setAutomaticEnable(m_sampleSink->hasIQAutoCorrection());
|
||||
layout->addWidget(m_iqCorrectionGUI);
|
||||
|
||||
connect(m_iqCorrectionGUI, SIGNAL(moduleChanged(double)), this, SLOT(iqCorrectionModuleChanged(double)));
|
||||
connect(m_iqCorrectionGUI, SIGNAL(argumentChanged(double)), this, SLOT(iqCorrectionArgumentChanged(double)));
|
||||
|
||||
if (m_sampleSink->hasIQAutoCorrection()) {
|
||||
connect(m_iqCorrectionGUI, SIGNAL(automaticChanged(bool)), this, SLOT(autoIQCorrectionChanged(bool)));
|
||||
}
|
||||
}
|
||||
else if (m_sampleSink->hasIQAutoCorrection()) // simple checkbox
|
||||
{
|
||||
m_autoIQCorrection = new QCheckBox(this);
|
||||
m_autoIQCorrection->setText(QString("IQ corr"));
|
||||
layout->addWidget(m_autoIQCorrection);
|
||||
|
||||
connect(m_autoIQCorrection, SIGNAL(toggled(bool)), this, SLOT(autoIQCorrectionChanged(bool)));
|
||||
}
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::setName(const QString& name)
|
||||
{
|
||||
setObjectName(name);
|
||||
@ -404,6 +461,48 @@ void SoapySDROutputGui::individualGainChanged(QString name, double value)
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::autoDCCorrectionChanged(bool set)
|
||||
{
|
||||
m_settings.m_autoDCCorrection = set;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::autoIQCorrectionChanged(bool set)
|
||||
{
|
||||
m_settings.m_autoIQCorrection = set;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::dcCorrectionModuleChanged(double value)
|
||||
{
|
||||
std::complex<double> dcCorrection = std::polar<double>(value, arg(m_settings.m_dcCorrection));
|
||||
m_settings.m_dcCorrection = dcCorrection;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::dcCorrectionArgumentChanged(double value)
|
||||
{
|
||||
double angleInRadians = (value / 180.0) * M_PI;
|
||||
std::complex<double> dcCorrection = std::polar<double>(abs(m_settings.m_dcCorrection), angleInRadians);
|
||||
m_settings.m_dcCorrection = dcCorrection;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::iqCorrectionModuleChanged(double value)
|
||||
{
|
||||
std::complex<double> iqCorrection = std::polar<double>(value, arg(m_settings.m_iqCorrection));
|
||||
m_settings.m_iqCorrection = iqCorrection;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::iqCorrectionArgumentChanged(double value)
|
||||
{
|
||||
double angleInRadians = (value / 180.0) * M_PI;
|
||||
std::complex<double> iqCorrection = std::polar<double>(abs(m_settings.m_iqCorrection), angleInRadians);
|
||||
m_settings.m_iqCorrection = iqCorrection;
|
||||
sendSettings();
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::on_centerFrequency_changed(quint64 value)
|
||||
{
|
||||
m_settings.m_centerFrequency = value * 1000;
|
||||
@ -473,6 +572,7 @@ void SoapySDROutputGui::displaySettings()
|
||||
|
||||
displayTunableElementsControlSettings();
|
||||
displayIndividualGainsControlSettings();
|
||||
displayCorrectionsSettings();
|
||||
|
||||
blockApplySettings(false);
|
||||
}
|
||||
@ -501,6 +601,31 @@ void SoapySDROutputGui::displayIndividualGainsControlSettings()
|
||||
}
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::displayCorrectionsSettings()
|
||||
{
|
||||
if (m_dcCorrectionGUI)
|
||||
{
|
||||
m_dcCorrectionGUI->setAutomatic(m_settings.m_autoDCCorrection);
|
||||
m_dcCorrectionGUI->setModule(abs(m_settings.m_dcCorrection));
|
||||
m_dcCorrectionGUI->setArgument(arg(m_settings.m_dcCorrection)*(180.0/M_PI));
|
||||
}
|
||||
|
||||
if (m_iqCorrectionGUI)
|
||||
{
|
||||
m_iqCorrectionGUI->setAutomatic(m_settings.m_autoIQCorrection);
|
||||
m_iqCorrectionGUI->setModule(abs(m_settings.m_iqCorrection));
|
||||
m_iqCorrectionGUI->setArgument(arg(m_settings.m_iqCorrection)*(180.0/M_PI));
|
||||
}
|
||||
|
||||
if (m_autoDCCorrection) {
|
||||
m_autoDCCorrection->setChecked(m_settings.m_autoDCCorrection);
|
||||
}
|
||||
|
||||
if (m_autoIQCorrection) {
|
||||
m_autoIQCorrection->setChecked(m_settings.m_autoIQCorrection);
|
||||
}
|
||||
}
|
||||
|
||||
void SoapySDROutputGui::sendSettings()
|
||||
{
|
||||
if (!m_updateTimer.isActive()) {
|
||||
|
@ -33,6 +33,7 @@ class StringRangeGUI;
|
||||
class DynamicItemSettingGUI;
|
||||
class IntervalSliderGUI;
|
||||
class QCheckBox;
|
||||
class ComplexFactorGUI;
|
||||
|
||||
namespace Ui {
|
||||
class SoapySDROutputGui;
|
||||
@ -67,6 +68,7 @@ private:
|
||||
void createTunableElementsControl(const std::vector<DeviceSoapySDRParams::FrequencySetting>& tunableElementsList);
|
||||
void createGlobalGainControl();
|
||||
void createIndividualGainsControl(const std::vector<DeviceSoapySDRParams::GainSetting>& individualGainsList);
|
||||
void createCorrectionsControl();
|
||||
|
||||
Ui::SoapySDROutputGui* ui;
|
||||
|
||||
@ -89,11 +91,16 @@ private:
|
||||
IntervalSliderGUI *m_gainSliderGUI;
|
||||
std::vector<DynamicItemSettingGUI*> m_individualGainsGUIs;
|
||||
QCheckBox *m_autoGain;
|
||||
ComplexFactorGUI *m_dcCorrectionGUI;
|
||||
ComplexFactorGUI *m_iqCorrectionGUI;
|
||||
QCheckBox *m_autoDCCorrection;
|
||||
QCheckBox *m_autoIQCorrection;
|
||||
|
||||
void blockApplySettings(bool block) { m_doApplySettings = !block; }
|
||||
void displaySettings();
|
||||
void displayTunableElementsControlSettings();
|
||||
void displayIndividualGainsControlSettings();
|
||||
void displayCorrectionsSettings();
|
||||
void sendSettings();
|
||||
void updateSampleRateAndFrequency();
|
||||
void updateFrequencyLimits();
|
||||
@ -101,6 +108,7 @@ private:
|
||||
|
||||
private slots:
|
||||
void handleInputMessages();
|
||||
|
||||
void antennasChanged();
|
||||
void sampleRateChanged(double sampleRate);
|
||||
void bandwidthChanged(double bandwidth);
|
||||
@ -108,6 +116,13 @@ private slots:
|
||||
void globalGainChanged(double gain);
|
||||
void autoGainChanged(bool set);
|
||||
void individualGainChanged(QString name, double value);
|
||||
void autoDCCorrectionChanged(bool set);
|
||||
void autoIQCorrectionChanged(bool set);
|
||||
void dcCorrectionModuleChanged(double value);
|
||||
void dcCorrectionArgumentChanged(double value);
|
||||
void iqCorrectionModuleChanged(double value);
|
||||
void iqCorrectionArgumentChanged(double value);
|
||||
|
||||
void on_centerFrequency_changed(quint64 value);
|
||||
void on_LOppm_valueChanged(int value);
|
||||
void on_interp_currentIndexChanged(int index);
|
||||
|
@ -38,6 +38,10 @@ void SoapySDROutputSettings::resetToDefaults()
|
||||
m_bandwidth = 1000000;
|
||||
m_globalGain = 0;
|
||||
m_autoGain = false;
|
||||
m_autoDCCorrection = false;
|
||||
m_autoIQCorrection = false;
|
||||
m_dcCorrection = std::complex<double>{0,0};
|
||||
m_iqCorrection = std::complex<double>{0,0};
|
||||
}
|
||||
|
||||
QByteArray SoapySDROutputSettings::serialize() const
|
||||
@ -55,6 +59,12 @@ QByteArray SoapySDROutputSettings::serialize() const
|
||||
s.writeS32(12, m_globalGain);
|
||||
s.writeBlob(13, serializeNamedElementMap(m_individualGains));
|
||||
s.writeBool(14, m_autoGain);
|
||||
s.writeBool(15, m_autoDCCorrection);
|
||||
s.writeBool(16, m_autoIQCorrection);
|
||||
s.writeDouble(17, m_dcCorrection.real());
|
||||
s.writeDouble(18, m_dcCorrection.imag());
|
||||
s.writeDouble(19, m_iqCorrection.real());
|
||||
s.writeDouble(20, m_iqCorrection.imag());
|
||||
|
||||
return s.final();
|
||||
}
|
||||
@ -72,10 +82,11 @@ bool SoapySDROutputSettings::deserialize(const QByteArray& data)
|
||||
if (d.getVersion() == 1)
|
||||
{
|
||||
QByteArray blob;
|
||||
double realval, imagval;
|
||||
|
||||
d.readS32(1, &m_devSampleRate);
|
||||
d.readS32(2, &m_LOppmTenths);
|
||||
d.readU32(3, &m_log2Interp);
|
||||
d.readS32(1, &m_devSampleRate, 1024000);
|
||||
d.readS32(2, &m_LOppmTenths, 0);
|
||||
d.readU32(3, &m_log2Interp, 0);
|
||||
d.readBool(4, &m_transverterMode, false);
|
||||
d.readS64(5, &m_transverterDeltaFrequency, 0);
|
||||
d.readString(6, &m_antenna, "NONE");
|
||||
@ -86,6 +97,14 @@ bool SoapySDROutputSettings::deserialize(const QByteArray& data)
|
||||
d.readBlob(13, &blob);
|
||||
deserializeNamedElementMap(blob, m_individualGains);
|
||||
d.readBool(14, &m_autoGain, false);
|
||||
d.readBool(15, &m_autoDCCorrection, false);
|
||||
d.readBool(16, &m_autoIQCorrection, false);
|
||||
d.readDouble(17, &realval, 0);
|
||||
d.readDouble(18, &imagval, 0);
|
||||
m_dcCorrection = std::complex<double>{realval, imagval};
|
||||
d.readDouble(19, &realval, 0);
|
||||
d.readDouble(20, &imagval, 0);
|
||||
m_iqCorrection = std::complex<double>{realval, imagval};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -33,6 +33,10 @@ struct SoapySDROutputSettings {
|
||||
qint32 m_globalGain;
|
||||
QMap<QString, double> m_individualGains;
|
||||
bool m_autoGain;
|
||||
bool m_autoDCCorrection;
|
||||
bool m_autoIQCorrection;
|
||||
std::complex<double> m_dcCorrection;
|
||||
std::complex<double> m_iqCorrection;
|
||||
|
||||
SoapySDROutputSettings();
|
||||
void resetToDefaults();
|
||||
|
@ -980,11 +980,11 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
|
||||
try
|
||||
{
|
||||
dev->setDCOffsetMode(SOAPY_SDR_RX, requestedChannel, settings.m_autoDCCorrection);
|
||||
qDebug("SoapySDRInput::applySettings: %s DC auto correction", settings.m_autoGain ? "set" : "unset");
|
||||
qDebug("SoapySDRInput::applySettings: %s DC auto correction", settings.m_autoDCCorrection ? "set" : "unset");
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
qCritical("SoapySDRInput::applySettings: cannot %s DC auto correction", settings.m_autoGain ? "set" : "unset");
|
||||
qCritical("SoapySDRInput::applySettings: cannot %s DC auto correction", settings.m_autoDCCorrection ? "set" : "unset");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
|
||||
m_sampleSource->getFrequencyRange(f_min, f_max);
|
||||
ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000);
|
||||
|
||||
createCorrectionsControl();
|
||||
createAntennasControl(m_sampleSource->getAntennas());
|
||||
createRangesControl(&m_sampleRateGUI, m_sampleSource->getRateRanges(), "SR", "S/s");
|
||||
createRangesControl(&m_bandwidthGUI, m_sampleSource->getBandwidthRanges(), "BW", "Hz");
|
||||
|
Loading…
Reference in New Issue
Block a user