mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04: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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user