From 3038dc0f7566b9099d9387a5c8b38e8ece05b019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20K=C3=A4berich?= Date: Tue, 13 Jul 2021 19:57:01 +0200 Subject: [PATCH] Handle traces created from CSV files in trace edit dialog --- .../CustomWidgets/csvimport.cpp | 145 +++++++++++++ .../PC_Application/CustomWidgets/csvimport.h | 45 ++++ .../PC_Application/CustomWidgets/csvimport.ui | 192 ++++++++++++++++++ .../CustomWidgets/touchstoneimport.cpp | 3 +- Software/PC_Application/LibreVNA-GUI.pro | 3 + .../PC_Application/Traces/traceeditdialog.cpp | 69 +++++-- .../PC_Application/Traces/traceeditdialog.ui | 42 ++-- 7 files changed, 462 insertions(+), 37 deletions(-) create mode 100644 Software/PC_Application/CustomWidgets/csvimport.cpp create mode 100644 Software/PC_Application/CustomWidgets/csvimport.h create mode 100644 Software/PC_Application/CustomWidgets/csvimport.ui diff --git a/Software/PC_Application/CustomWidgets/csvimport.cpp b/Software/PC_Application/CustomWidgets/csvimport.cpp new file mode 100644 index 0000000..2a9f9af --- /dev/null +++ b/Software/PC_Application/CustomWidgets/csvimport.cpp @@ -0,0 +1,145 @@ +#include "csvimport.h" +#include "ui_csvimport.h" +#include +#include "Traces/trace.h" +#include + +CSVImport::CSVImport(QWidget *parent) : + QWidget(parent), + ui(new Ui::csvimport), + status(false) +{ + ui->setupUi(this); + ui->from->setPrecision(5); + ui->to->setPrecision(5); + ui->traces->setPrecision(0); + ui->points->setPrecision(0); + connect(ui->file, &QLineEdit::textChanged, this, &CSVImport::setFile); +} + +CSVImport::~CSVImport() +{ + delete ui; +} + +bool CSVImport::getStatus() +{ + return status; +} + +CSV CSVImport::getCSV() +{ + return csv; +} + +QString CSVImport::getFilename() +{ + return ui->file->text(); +} + +bool CSVImport::fillTrace(Trace &t) +{ + try { + t.fillFromCSV(csv, ui->traceSelector->currentIndex()); + return true; + } catch (const std::exception &e) { + qWarning() << QString("CSV import failed to fill trace: ") + e.what(); + return false; + } +} + +void CSVImport::setFile(QString filename) +{ + ui->file->setText(filename); + evaluateFile(); + emit filenameChanged(filename); +} + +void CSVImport::selectTrace(unsigned int index) +{ + ui->traceSelector->setCurrentIndex(index); +} + +void CSVImport::on_browse_clicked() +{ + auto filename = QFileDialog::getOpenFileName(nullptr, "Open measurement file", "", "CSV files (*.csv)", nullptr, QFileDialog::DontUseNativeDialog); + if (filename.length() > 0) { + ui->file->setText(filename); + evaluateFile(); + } +} + +void CSVImport::evaluateFile() +{ + // store currently selected trace + auto selectedTrace = ui->traceSelector->currentText(); + + bool new_status = false; + ui->traces->setText(""); + ui->points->setText(""); + ui->from->setText(""); + ui->to->setText(""); + ui->status->clear(); + ui->traceSelector->clear(); + try { + csv = CSV::fromFile(ui->file->text()); + auto domain = Trace::dataTypeFromString(csv.getHeader(0)); + if (domain == Trace::DataType::Invalid) { + // just assume frequency domain + domain = Trace::DataType::Frequency; + } + ui->domain->setCurrentText(Trace::dataTypeToString(domain)); + switch(domain) { + case Trace::DataType::Frequency: + ui->from->setUnit("Hz"); + ui->to->setUnit("Hz"); + break; + case Trace::DataType::Time: + ui->from->setUnit("s"); + ui->to->setUnit("s"); + break; + case Trace::DataType::Power: + ui->from->setUnit("dBm"); + ui->to->setUnit("dBm"); + break; + default: + break; + } + + auto xvalues = csv.getColumn(0); + ui->from->setValue(xvalues.front()); + ui->to->setValue(xvalues.back()); + ui->points->setValue(xvalues.size()); + + bool okay = true; + int numTraces = 0; + while(okay) { + try { + Trace t; + auto name = t.fillFromCSV(csv, numTraces); + ui->traceSelector->addItem(name); + numTraces++; + } catch (const std::exception &e) { + // no more traces + okay = false; + } + } + ui->traces->setValue(numTraces); + + // check if previously selected trace is still available + if(ui->traceSelector->findText(selectedTrace) >= 0) { + ui->traceSelector->setCurrentText(selectedTrace); + } else { + ui->traceSelector->setCurrentIndex(0); + } + + new_status = true; + } catch (const std::exception &e) { + ui->status->setText(e.what()); + } + if (new_status != status) { + status = new_status; + emit statusChanged(status); + } + emit filenameChanged(ui->file->text()); +} diff --git a/Software/PC_Application/CustomWidgets/csvimport.h b/Software/PC_Application/CustomWidgets/csvimport.h new file mode 100644 index 0000000..dd8494b --- /dev/null +++ b/Software/PC_Application/CustomWidgets/csvimport.h @@ -0,0 +1,45 @@ +#ifndef CSVIMPORT_H +#define CSVIMPORT_H + +#include +#include "csv.h" +#include "Traces/trace.h" + +namespace Ui { +class csvimport; +} + +class CSVImport : public QWidget +{ + Q_OBJECT + +public: + explicit CSVImport(QWidget *parent = nullptr); + ~CSVImport(); + + bool getStatus(); + CSV getCSV(); + QString getFilename(); + + bool fillTrace(Trace &t); + +signals: + void statusChanged(bool status); + void filenameChanged(QString name); + +public slots: + void setFile(QString filename); + void selectTrace(unsigned int index); + +private slots: + void on_browse_clicked(); + +private: + void evaluateFile(); + Ui::csvimport *ui; + int required_ports; + CSV csv; + bool status; +}; + +#endif // CSVIMPORT_H diff --git a/Software/PC_Application/CustomWidgets/csvimport.ui b/Software/PC_Application/CustomWidgets/csvimport.ui new file mode 100644 index 0000000..83e61f8 --- /dev/null +++ b/Software/PC_Application/CustomWidgets/csvimport.ui @@ -0,0 +1,192 @@ + + + csvimport + + + + 0 + 0 + 232 + 256 + + + + Form + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 20 + 16777215 + + + + ... + + + + + + + + + + + + + + 239 + 41 + 41 + + + + + + + + + 239 + 41 + 41 + + + + + + + + + 190 + 190 + 190 + + + + + + + + + + + + + + + + + Domain: + + + + + + + false + + + true + + + + + + + Traces: + + + + + + + false + + + + + + + Points: + + + + + + + false + + + + + + + From: + + + + + + + false + + + + + + + To: + + + + + + + false + + + + + + + Trace: + + + + + + + + + + + + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
+
+ + +
diff --git a/Software/PC_Application/CustomWidgets/touchstoneimport.cpp b/Software/PC_Application/CustomWidgets/touchstoneimport.cpp index e4fb66a..21d8158 100644 --- a/Software/PC_Application/CustomWidgets/touchstoneimport.cpp +++ b/Software/PC_Application/CustomWidgets/touchstoneimport.cpp @@ -33,6 +33,7 @@ TouchstoneImport::TouchstoneImport(QWidget *parent, int ports) : connect(ui->port2Group, qOverload(&QButtonGroup::buttonClicked), [=](int id) { preventCollisionWithGroup(ui->port1Group, id); }); + connect(ui->file, &QLineEdit::textChanged, this, &TouchstoneImport::setFile); setPorts(ports); } @@ -103,6 +104,7 @@ void TouchstoneImport::setFile(QString filename) { ui->file->setText(filename); evaluateFile(); + emit filenameChanged(filename); } void TouchstoneImport::on_browse_clicked() @@ -110,7 +112,6 @@ void TouchstoneImport::on_browse_clicked() auto filename = QFileDialog::getOpenFileName(nullptr, "Open measurement file", "", "Touchstone files (*.s1p *.s2p *.s3p *.s4p)", nullptr, QFileDialog::DontUseNativeDialog); if (filename.length() > 0) { ui->file->setText(filename); - evaluateFile(); } } diff --git a/Software/PC_Application/LibreVNA-GUI.pro b/Software/PC_Application/LibreVNA-GUI.pro index 1d5c4eb..bc2c73b 100644 --- a/Software/PC_Application/LibreVNA-GUI.pro +++ b/Software/PC_Application/LibreVNA-GUI.pro @@ -11,6 +11,7 @@ HEADERS += \ Calibration/receivercaldialog.h \ Calibration/sourcecaldialog.h \ CustomWidgets/colorpickerbutton.h \ + CustomWidgets/csvimport.h \ CustomWidgets/informationbox.h \ CustomWidgets/jsonpickerdialog.h \ CustomWidgets/siunitedit.h \ @@ -138,6 +139,7 @@ SOURCES += \ Calibration/receivercaldialog.cpp \ Calibration/sourcecaldialog.cpp \ CustomWidgets/colorpickerbutton.cpp \ + CustomWidgets/csvimport.cpp \ CustomWidgets/informationbox.cpp \ CustomWidgets/jsonpickerdialog.cpp \ CustomWidgets/siunitedit.cpp \ @@ -253,6 +255,7 @@ FORMS += \ Calibration/calkitdialog.ui \ Calibration/frequencycaldialog.ui \ Calibration/manualcalibrationdialog.ui \ + CustomWidgets/csvimport.ui \ CustomWidgets/jsonpickerdialog.ui \ CustomWidgets/tilewidget.ui \ CustomWidgets/touchstoneimport.ui \ diff --git a/Software/PC_Application/Traces/traceeditdialog.cpp b/Software/PC_Application/Traces/traceeditdialog.cpp index 4792c6a..e1e3bc1 100644 --- a/Software/PC_Application/Traces/traceeditdialog.cpp +++ b/Software/PC_Application/Traces/traceeditdialog.cpp @@ -19,6 +19,27 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : ui->name->setText(t.name()); ui->color->setColor(trace.color()); ui->vFactor->setValue(t.velocityFactor()); + + connect(ui->bLive, &QPushButton::clicked, [=](bool live) { + if(live) { + ui->stack->setCurrentIndex(0); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + } + }); + connect(ui->bFile, &QPushButton::clicked, [&](bool file) { + if(file) { + if(t.getFilename().endsWith(".csv")) { + ui->stack->setCurrentIndex(2); + ui->csvImport->setFile(t.getFilename()); + ui->csvImport->selectTrace(t.getFileParameter()); + } else { + // attempt to parse as touchstone + ui->stack->setCurrentIndex(1); + ui->touchstoneImport->setFile(t.getFilename()); + } + } + }); + connect(ui->color, &ColorPickerButton::colorChanged, [=](const QColor& color){ trace.setColor(color); }); @@ -26,7 +47,7 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : ui->GSource->setId(ui->bLive, 0); ui->GSource->setId(ui->bFile, 1); - if(t.isCalibration() || (t.isFromFile() && t.getFilename().endsWith(".csv"))) { + if(t.isCalibration()) { // prevent editing imported calibration traces (and csv files for now) ui->bLive->setEnabled(false); ui->bFile->setEnabled(false); @@ -34,12 +55,7 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : ui->CLiveParam->setEnabled(false); } - if(t.isFromFile() && !t.getFilename().endsWith(".csv")) { - ui->bFile->click(); - ui->touchstoneImport->setFile(t.getFilename()); - } - - auto updateFileStatus = [this]() { + auto updateTouchstoneFileStatus = [this]() { // remove all options from paramater combo box while(ui->CParameter->count() > 0) { ui->CParameter->removeItem(0); @@ -61,6 +77,25 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : ui->CParameter->setCurrentIndex(0); } } + if(ui->touchstoneImport->getFilename().endsWith(".csv")) { + // switch to csv import dialog + ui->stack->setCurrentIndex(2); + ui->csvImport->setFile(ui->touchstoneImport->getFilename()); + } + }; + + auto updateCSVFileStatus = [this]() { + if (ui->bFile->isChecked() && !ui->csvImport->getStatus()) { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + } else { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + auto touchstone = ui->touchstoneImport->getTouchstone(); + } + if(!(ui->touchstoneImport->getFilename().endsWith(".csv"))) { + // switch to touchstone import dialog + ui->stack->setCurrentIndex(1); + ui->touchstoneImport->setFile(ui->csvImport->getFilename()); + } }; switch(t.liveType()) { @@ -91,11 +126,13 @@ TraceEditDialog::TraceEditDialog(Trace &t, QWidget *parent) : default: break; } - connect(ui->GSource, qOverload(&QButtonGroup::buttonClicked), updateFileStatus); - connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateFileStatus); - connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateFileStatus); + connect(ui->touchstoneImport, &TouchstoneImport::statusChanged, updateTouchstoneFileStatus); + connect(ui->touchstoneImport, &TouchstoneImport::filenameChanged, updateTouchstoneFileStatus); + connect(ui->csvImport, &CSVImport::filenameChanged, updateCSVFileStatus); - updateFileStatus(); + if(t.isFromFile()) { + ui->bFile->click(); + } // setup math part of the GUI auto model = new MathModel(t); @@ -208,8 +245,14 @@ void TraceEditDialog::on_buttonBox_accepted() if(!trace.isCalibration()) { // only apply changes if it is not a calibration trace if (ui->bFile->isChecked()) { - auto t = ui->touchstoneImport->getTouchstone(); - trace.fillFromTouchstone(t, ui->CParameter->currentIndex()); + if(ui->stack->currentIndex() == 1) { + // touchstone page active + auto t = ui->touchstoneImport->getTouchstone(); + trace.fillFromTouchstone(t, ui->CParameter->currentIndex()); + } else { + // CSV page active + ui->csvImport->fillTrace(trace); + } } else { Trace::LivedataType type = Trace::LivedataType::Overwrite; Trace::LiveParameter param = Trace::LiveParameter::S11; diff --git a/Software/PC_Application/Traces/traceeditdialog.ui b/Software/PC_Application/Traces/traceeditdialog.ui index 436ba09..bf8c507 100644 --- a/Software/PC_Application/Traces/traceeditdialog.ui +++ b/Software/PC_Application/Traces/traceeditdialog.ui @@ -117,7 +117,7 @@ 0 - + @@ -157,7 +157,7 @@ - + @@ -178,6 +178,13 @@ + + + + + + + @@ -335,6 +342,11 @@ + + SIUnitEdit + QLineEdit +
CustomWidgets/siunitedit.h
+
TouchstoneImport QWidget @@ -347,32 +359,16 @@
CustomWidgets/colorpickerbutton.h
- SIUnitEdit - QLineEdit -
CustomWidgets/siunitedit.h
+ CSVImport + QWidget +
CustomWidgets/csvimport.h
+ 1
- - - GSource - buttonClicked(int) - stack - setCurrentIndex(int) - - - -1 - -1 - - - 146 - 216 - - - - +