mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-29 20:10:22 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			368 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| // Copyright (C) 2022 F4EXB                                                      //
 | |
| // written by Edouard Griffiths                                                  //
 | |
| //                                                                               //
 | |
| // This program is free software; you can redistribute it and/or modify          //
 | |
| // it under the terms of the GNU General Public License as published by          //
 | |
| // the Free Software Foundation as version 3 of the License, or                  //
 | |
| // (at your option) any later version.                                           //
 | |
| //                                                                               //
 | |
| // This program is distributed in the hope that it will be useful,               //
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 | |
| // GNU General Public License V3 for more details.                               //
 | |
| //                                                                               //
 | |
| // You should have received a copy of the GNU General Public License             //
 | |
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | |
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| #include <QFileDialog>
 | |
| #include <QFile>
 | |
| #include <QStandardPaths>
 | |
| 
 | |
| #include "util/db.h"
 | |
| #include "util/csv.h"
 | |
| #include "dsp/spectrummarkers.h"
 | |
| 
 | |
| #include "spectrumcalibrationpointsdialog.h"
 | |
| 
 | |
| #include "ui_spectrumcalibrationpointsdialog.h"
 | |
| 
 | |
| SpectrumCalibrationPointsDialog::SpectrumCalibrationPointsDialog(
 | |
|     QList<SpectrumCalibrationPoint>& calibrationPoints,
 | |
|     SpectrumSettings::CalibrationInterpolationMode& calibrationInterpMode,
 | |
|     const SpectrumHistogramMarker *markerZero,
 | |
|     QWidget* parent
 | |
| ) :
 | |
|     QDialog(parent),
 | |
|     ui(new Ui::SpectrumCalibrationPointsDialog),
 | |
|     m_calibrationPoints(calibrationPoints),
 | |
|     m_calibrationInterpMode(calibrationInterpMode),
 | |
|     m_markerZero(markerZero),
 | |
|     m_calibrationPointIndex(0),
 | |
|     m_centerFrequency(0),
 | |
|     m_globalCorrection(0.0),
 | |
|     m_setElseCorrectGlobal(false)
 | |
| {
 | |
|     ui->setupUi(this);
 | |
|     ui->calibPointFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
 | |
|     ui->calibPointFrequency->setValueRange(false, 10, -9999999999L, 9999999999L);
 | |
|     ui->calibrationGlobalCorr->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
 | |
|     ui->calibrationGlobalCorr->setValueRange(false, 5, -20000L, 4000L, 2);
 | |
|     ui->relativePower->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
 | |
|     ui->relativePower->setValueRange(false, 5, -20000L, 4000L, 2);
 | |
|     ui->calibratedPower->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
 | |
|     ui->calibratedPower->setValueRange(false, 5, -20000L, 4000L, 2);
 | |
|     ui->calibPoint->setMaximum(m_calibrationPoints.size() - 1);
 | |
|     ui->calibInterpMode->blockSignals(true);
 | |
|     ui->calibInterpMode->setCurrentIndex((int) m_calibrationInterpMode);
 | |
|     ui->calibInterpMode->blockSignals(false);
 | |
|     ui->calibrationGlobalCorr->setValue(m_globalCorrection * 100.0);
 | |
|     ui->corrOrSet->setText("Cor");
 | |
|     displayCalibrationPoint();
 | |
| }
 | |
| 
 | |
| SpectrumCalibrationPointsDialog::~SpectrumCalibrationPointsDialog()
 | |
| {}
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::displayCalibrationPoint()
 | |
| {
 | |
|     ui->calibPointFrequency->blockSignals(true);
 | |
|     ui->calibPoint->blockSignals(true);
 | |
|     ui->relativePower->blockSignals(true);
 | |
|     ui->calibratedPower->blockSignals(true);
 | |
| 
 | |
|     if (m_calibrationPoints.size() == 0)
 | |
|     {
 | |
|         ui->calibPoint->setEnabled(false);
 | |
|         ui->calibPointDel->setEnabled(false);
 | |
|         ui->relativePower->setEnabled(false);
 | |
|         ui->calibratedPower->setEnabled(false);
 | |
|         ui->calibPointFrequency->setEnabled(false);
 | |
|         ui->importMarkerZero->setEnabled(false);
 | |
|         ui->centerFrequency->setEnabled(false);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         ui->calibPoint->setEnabled(true);
 | |
|         ui->calibPointDel->setEnabled(true);
 | |
|         ui->relativePower->setEnabled(true);
 | |
|         ui->calibratedPower->setEnabled(true);
 | |
|         ui->calibPointFrequency->setEnabled(true);
 | |
|         ui->importMarkerZero->setEnabled(true);
 | |
|         ui->centerFrequency->setEnabled(true);
 | |
|         ui->calibPoint->setValue(m_calibrationPointIndex);
 | |
|         ui->calibPointText->setText(tr("%1").arg(m_calibrationPointIndex));
 | |
|         double powerDB = CalcDb::dbPower(m_calibrationPoints[m_calibrationPointIndex].m_powerRelativeReference, 1e-20);
 | |
|         ui->relativePower->setValue(round(powerDB*100.0)); // fixed point 2 decimals
 | |
|         powerDB = CalcDb::dbPower(m_calibrationPoints[m_calibrationPointIndex].m_powerCalibratedReference, 1e-20);
 | |
|         ui->calibratedPower->setValue(round(powerDB*100.0)); // fixed point 2 decimals
 | |
|         ui->calibPointFrequency->setValue(m_calibrationPoints[m_calibrationPointIndex].m_frequency);
 | |
|     }
 | |
| 
 | |
|     ui->calibPointFrequency->blockSignals(false);
 | |
|     ui->calibPoint->blockSignals(false);
 | |
|     ui->relativePower->blockSignals(false);
 | |
|     ui->calibratedPower->blockSignals(false);
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPoint_valueChanged(int value)
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     m_calibrationPointIndex = value;
 | |
|     displayCalibrationPoint();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPointAdd_clicked()
 | |
| {
 | |
|     m_calibrationPoints.append(SpectrumCalibrationPoint());
 | |
|     m_calibrationPoints.back().m_frequency = m_centerFrequency;
 | |
|     m_calibrationPointIndex = m_calibrationPoints.size() - 1;
 | |
|     ui->calibPoint->setMaximum(m_calibrationPoints.size() - 1);
 | |
|     ui->calibPoint->setMinimum(0);
 | |
|     displayCalibrationPoint();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPointDel_clicked()
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     m_calibrationPoints.removeAt(m_calibrationPointIndex);
 | |
|     m_calibrationPointIndex = m_calibrationPointIndex < m_calibrationPoints.size() ?
 | |
|         m_calibrationPointIndex : m_calibrationPointIndex - 1;
 | |
|     ui->calibPoint->setMaximum(m_calibrationPoints.size() - 1);
 | |
|     ui->calibPoint->setMinimum(0);
 | |
|     displayCalibrationPoint();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_relativePower_changed(qint64 value)
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     float powerDB = value / 100.0f;
 | |
|     m_calibrationPoints[m_calibrationPointIndex].m_powerRelativeReference = CalcDb::powerFromdB(powerDB);
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibratedPower_changed(qint64 value)
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     float powerDB = value / 100.0f;
 | |
|     m_calibrationPoints[m_calibrationPointIndex].m_powerCalibratedReference = CalcDb::powerFromdB(powerDB);
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPointFrequency_changed(qint64 value)
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     m_calibrationPoints[m_calibrationPointIndex].m_frequency = value;
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPointDuplicate_clicked()
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     m_calibrationPoints.push_back(SpectrumCalibrationPoint(m_calibrationPoints[m_calibrationPointIndex]));
 | |
|     ui->calibPoint->setMaximum(m_calibrationPoints.size() - 1);
 | |
|     ui->calibPoint->setMinimum(0);
 | |
|     m_calibrationPointIndex = m_calibrationPoints.size() - 1;
 | |
|     displayCalibrationPoint();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPointsSort_clicked()
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     std::sort(m_calibrationPoints.begin(), m_calibrationPoints.end(), calibrationPointsLessThan);
 | |
|     m_calibrationPointIndex = 0;
 | |
|     displayCalibrationPoint();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_importMarkerZero_clicked()
 | |
| {
 | |
|     if ((m_calibrationPoints.size() == 0) || (m_markerZero == nullptr)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     m_calibrationPoints[m_calibrationPointIndex].m_frequency = m_markerZero->m_frequency;
 | |
|     m_calibrationPoints[m_calibrationPointIndex].m_powerRelativeReference = CalcDb::powerFromdB(m_markerZero->m_powerMax);
 | |
|     displayCalibrationPoint();
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_centerFrequency_clicked()
 | |
| {
 | |
|     if (m_calibrationPoints.size() == 0) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     m_calibrationPoints[m_calibrationPointIndex].m_frequency = m_centerFrequency;
 | |
|     displayCalibrationPoint();
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibInterpMode_currentIndexChanged(int index)
 | |
| {
 | |
|     m_calibrationInterpMode = (SpectrumSettings::CalibrationInterpolationMode) index;
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibrationGlobalCorr_changed(qint64 value)
 | |
| {
 | |
|     m_globalCorrection = value / 100.0;
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_corrOrSet_toggled(bool checked)
 | |
| {
 | |
|     if (checked) {
 | |
|         ui->corrOrSet->setText("Set");
 | |
|     } else {
 | |
|         ui->corrOrSet->setText("Cor");
 | |
|     }
 | |
| 
 | |
|     m_setElseCorrectGlobal = checked;
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_globalRelativeCorrection_clicked()
 | |
| {
 | |
|     for (auto& calibrationPoint : m_calibrationPoints)
 | |
|     {
 | |
|         if (m_setElseCorrectGlobal) {
 | |
|             calibrationPoint.m_powerRelativeReference = CalcDb::powerFromdB(m_globalCorrection);
 | |
|         } else {
 | |
|             calibrationPoint.m_powerRelativeReference *= CalcDb::powerFromdB(m_globalCorrection);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     displayCalibrationPoint();
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_globalCalibratedCorrection_clicked()
 | |
| {
 | |
|     for (auto& calibrationPoint : m_calibrationPoints)
 | |
|     {
 | |
|         if (m_setElseCorrectGlobal) {
 | |
|             calibrationPoint.m_powerCalibratedReference = CalcDb::powerFromdB(m_globalCorrection);
 | |
|         } else {
 | |
|             calibrationPoint.m_powerCalibratedReference *= CalcDb::powerFromdB(m_globalCorrection);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     displayCalibrationPoint();
 | |
|     emit updateCalibrationPoints();
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPointsExport_clicked()
 | |
| {
 | |
|     QFileDialog fileDialog(
 | |
|         nullptr,
 | |
|         "Select file to write calibration points to",
 | |
|         QStandardPaths::writableLocation(QStandardPaths::AppDataLocation),
 | |
|         "*.csv"
 | |
|     );
 | |
|     fileDialog.setAcceptMode(QFileDialog::AcceptSave);
 | |
| 
 | |
|     if (fileDialog.exec())
 | |
|     {
 | |
|         QStringList fileNames = fileDialog.selectedFiles();
 | |
| 
 | |
|         if (fileNames.size() > 0)
 | |
|         {
 | |
|             QFile file(fileNames[0]);
 | |
| 
 | |
|             if (file.open(QIODevice::WriteOnly | QIODevice::Text))
 | |
|             {
 | |
|                 QTextStream stream;
 | |
|                 stream.setDevice(&file);
 | |
|                 stream << "Frequency,Relative,Calibrated\n";
 | |
| 
 | |
|                 for (const auto &calibrationPint : m_calibrationPoints)
 | |
|                 {
 | |
| 
 | |
|                     stream << calibrationPint.m_frequency << ","
 | |
|                         << CalcDb::dbPower(calibrationPint.m_powerRelativeReference, 1e-20) << ","
 | |
|                         << CalcDb::dbPower(calibrationPint.m_powerCalibratedReference, 1e-20) << "\n";
 | |
|                 }
 | |
| 
 | |
|                 stream.flush();
 | |
|                 file.close();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void SpectrumCalibrationPointsDialog::on_calibPointsImport_clicked()
 | |
| {
 | |
|     QFileDialog fileDialog(
 | |
|         nullptr,
 | |
|         "Select .csv calibration points file to read",
 | |
|         QStandardPaths::writableLocation(QStandardPaths::AppDataLocation),
 | |
|         "*.csv"
 | |
|     );
 | |
| 
 | |
|     if (fileDialog.exec())
 | |
|     {
 | |
|         QStringList fileNames = fileDialog.selectedFiles();
 | |
| 
 | |
|         if (fileNames.size() > 0)
 | |
|         {
 | |
|             QFile file(fileNames[0]);
 | |
| 
 | |
|             if (file.open(QIODevice::ReadOnly | QIODevice::Text))
 | |
|             {
 | |
| 
 | |
|                 QTextStream in(&file);
 | |
|                 QString error;
 | |
|                 QHash<QString, int> colIndexes = CSV::readHeader(
 | |
|                     in,
 | |
|                     {"Frequency", "Relative", "Calibrated"},
 | |
|                     error
 | |
|                 );
 | |
| 
 | |
|                 if (error.isEmpty())
 | |
|                 {
 | |
|                     QStringList cols;
 | |
|                     int frequencyCol = colIndexes.value("Frequency");
 | |
|                     int referenceCol = colIndexes.value("Relative");
 | |
|                     int absoluteCol = colIndexes.value("Calibrated");
 | |
| 
 | |
|                     m_calibrationPoints.clear();
 | |
| 
 | |
|                     while (CSV::readRow(in, &cols))
 | |
|                     {
 | |
|                         m_calibrationPoints.push_back(SpectrumCalibrationPoint());
 | |
|                         m_calibrationPoints.back().m_frequency = cols[frequencyCol].toLongLong();
 | |
|                         m_calibrationPoints.back().m_powerRelativeReference = CalcDb::powerFromdB(cols[referenceCol].toFloat());
 | |
|                         m_calibrationPoints.back().m_powerCalibratedReference = CalcDb::powerFromdB(cols[absoluteCol].toFloat());
 | |
|                     }
 | |
| 
 | |
|                     m_calibrationPointIndex = 0;
 | |
|                     ui->calibPoint->setMaximum(m_calibrationPoints.size() - 1);
 | |
|                     ui->calibPoint->setMinimum(0);
 | |
|                     displayCalibrationPoint();
 | |
|                     emit updateCalibrationPoints();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |