#include "deembedding.h" #include "deembeddingdialog.h" #include #include "ui_measurementdialog.h" using namespace std; void Deembedding::configure() { auto d = new DeembeddingDialog(this); d->show(); } void Deembedding::measurementCompleted() { // pass on the measurement result to the option that triggered the measurement if (measuringOption) { measuringOption->measurementCompleted(measurements); measuringOption = nullptr; } delete measurementDialog; measurementDialog = nullptr; measurementUI = nullptr; } void Deembedding::setInitialTraceSelections() { // all checkboxes initially set to none measurementUI->cS11->blockSignals(true); measurementUI->cS12->blockSignals(true); measurementUI->cS21->blockSignals(true); measurementUI->cS22->blockSignals(true); measurementUI->cS11->clear(); measurementUI->cS12->clear(); measurementUI->cS21->clear(); measurementUI->cS22->clear(); measurementUI->cS11->addItem("None"); measurementUI->cS12->addItem("None"); measurementUI->cS21->addItem("None"); measurementUI->cS22->addItem("None"); // add applicable traces for(auto t : tm.getTraces()) { if(t->isReflection()) { measurementUI->cS11->addItem(t->name(), QVariant::fromValue(t)); measurementUI->cS22->addItem(t->name(), QVariant::fromValue(t)); } else { measurementUI->cS12->addItem(t->name(), QVariant::fromValue(t)); measurementUI->cS21->addItem(t->name(), QVariant::fromValue(t)); } } measurementUI->cS11->blockSignals(false); measurementUI->cS12->blockSignals(false); measurementUI->cS21->blockSignals(false); measurementUI->cS22->blockSignals(false); } void Deembedding::traceSelectionChanged(QComboBox *w) { vector cbs; if (measurementUI->cS11->isVisible()) { cbs.push_back(measurementUI->cS11); } if (measurementUI->cS12->isVisible()) { cbs.push_back(measurementUI->cS12); } if (measurementUI->cS21->isVisible()) { cbs.push_back(measurementUI->cS21); } if (measurementUI->cS22->isVisible()) { cbs.push_back(measurementUI->cS22); } // update available traces in combo boxes if(w->currentIndex() != 0 && points == 0) { // the first trace has been selected, extract frequency info Trace *t = qvariant_cast(w->itemData(w->currentIndex())); points = t->size(); if(points > 0) { minFreq = t->minX(); maxFreq = t->maxX(); } // remove all trace options with incompatible frequencies for(auto c : cbs) { for(int i=1;icount();i++) { Trace *t = qvariant_cast(c->itemData(i)); if(t->size() != points || (points > 0 && (t->minX() != minFreq || t->maxX() != maxFreq))) { // this trace is not available anymore c->removeItem(i); // decrement to check the next index in the next loop iteration i--; } } } } else if(w->currentIndex() == 0 && points > 0) { measurementUI->buttonBox->setEnabled(false); // Check if all trace selections are set for none for(auto c : cbs) { if(c->currentIndex() != 0) { // some trace is still selected, abort return; } } // all traces set for none points = 0; minFreq = 0; maxFreq = 0; setInitialTraceSelections(); } bool allSelectionsValid = true; for(auto c : cbs) { if (c->currentIndex() == 0) { allSelectionsValid = false; break; } } if(allSelectionsValid) { measurementUI->buttonBox->setEnabled(true); } } void Deembedding::startMeasurementDialog(bool S11, bool S12, bool S21, bool S22) { measurements.clear(); points = 0; minFreq = 0.0; maxFreq = 0.0; measurementDialog = new QDialog; auto ui = new Ui_DeembeddingMeasurementDialog; measurementUI = ui; ui->setupUi(measurementDialog); // disable not needed GUI elements if(!S11) { ui->lS11->setVisible(false); ui->cS11->setVisible(false); } if(!S12) { ui->lS12->setVisible(false); ui->cS12->setVisible(false); } if(!S21) { ui->lS21->setVisible(false); ui->cS21->setVisible(false); } if(!S22) { ui->lS22->setVisible(false); ui->cS22->setVisible(false); } connect(ui->bMeasure, &QPushButton::clicked, [=](){ ui->bMeasure->setEnabled(false); ui->cS11->setEnabled(false); ui->cS12->setEnabled(false); ui->cS21->setEnabled(false); ui->cS22->setEnabled(false); ui->buttonBox->setEnabled(false); measuring = true; }); connect(ui->cS11, qOverload(&QComboBox::currentIndexChanged), [=](int){ traceSelectionChanged(ui->cS11); }); connect(ui->cS12, qOverload(&QComboBox::currentIndexChanged), [=](int){ traceSelectionChanged(ui->cS12); }); connect(ui->cS21, qOverload(&QComboBox::currentIndexChanged), [=](int){ traceSelectionChanged(ui->cS21); }); connect(ui->cS22, qOverload(&QComboBox::currentIndexChanged), [=](int){ traceSelectionChanged(ui->cS22); }); connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){ // create datapoints from individual traces measurements.clear(); Trace *S11 = nullptr, *S12 = nullptr, *S21 = nullptr, *S22 = nullptr; if (ui->cS11->currentIndex() != 0) { S11 = qvariant_cast(ui->cS11->itemData(ui->cS11->currentIndex())); } if (ui->cS12->currentIndex() != 0) { S12 = qvariant_cast(ui->cS12->itemData(ui->cS12->currentIndex())); } if (ui->cS21->currentIndex() != 0) { S21 = qvariant_cast(ui->cS21->itemData(ui->cS21->currentIndex())); } if (ui->cS22->currentIndex() != 0) { S22 = qvariant_cast(ui->cS22->itemData(ui->cS22->currentIndex())); } for(unsigned int i=0;isample(i); p.imag_S11 = sample.y.imag(); p.real_S11 = sample.y.real(); p.frequency = sample.x; } if(S12) { auto sample = S12->sample(i); p.imag_S12 = sample.y.imag(); p.real_S12 = sample.y.real(); p.frequency = sample.x; } if(S21) { auto sample = S21->sample(i); p.imag_S21 = sample.y.imag(); p.real_S21 = sample.y.real(); p.frequency = sample.x; } if(S22) { auto sample = S22->sample(i); p.imag_S22 = sample.y.imag(); p.real_S22 = sample.y.real(); p.frequency = sample.x; } measurements.push_back(p); } measurementCompleted(); }); setInitialTraceSelections(); measurementDialog->show(); } Deembedding::Deembedding(TraceModel &tm) : tm(tm), measuring(false), points(0) { } void Deembedding::Deembed(Protocol::Datapoint &d) { // figure out the point in one sweep based on the incomig pointNums static unsigned lastPointNum; if (d.pointNum == 0) { sweepPoints = lastPointNum; } else if(d.pointNum > sweepPoints) { sweepPoints = d.pointNum; } lastPointNum = d.pointNum; for(auto it = options.begin();it != options.end();it++) { if (measuring && measuringOption == *it) { // this option needs a measurement if (d.pointNum == 0) { if(measurements.size() == 0) { // this is the first point of the measurement measurements.push_back(d); } else { // this is the first point of the next sweep, measurement complete measuring = false; measurementCompleted(); } } else if(measurements.size() > 0) { // in the middle of the measurement, add point measurements.push_back(d); } if(measurementUI) { measurementUI->progress->setValue(100 * measurements.size() / sweepPoints); } } (*it)->transformDatapoint(d); } } void Deembedding::removeOption(unsigned int index) { if(index < options.size()) { delete options[index]; options.erase(options.begin() + index); } } void Deembedding::addOption(DeembeddingOption *option) { options.push_back(option); connect(option, &DeembeddingOption::deleted, [=](DeembeddingOption *o){ // find deleted option and remove from list auto pos = find(options.begin(), options.end(), o); if(pos != options.end()) { options.erase(pos); } }); connect(option, &DeembeddingOption::triggerMeasurement, [=](bool S11, bool S12, bool S21, bool S22) { measuringOption = option; startMeasurementDialog(S11, S12, S21, S22); }); } void Deembedding::swapOptions(unsigned int index) { if(index + 1 >= options.size()) { return; } std::swap(options[index], options[index+1]); } nlohmann::json Deembedding::toJSON() { nlohmann::json list; for(auto m : options) { nlohmann::json jm; jm["operation"] = DeembeddingOption::getName(m->getType()).toStdString(); jm["settings"] = m->toJSON(); list.push_back(jm); } return list; } void Deembedding::fromJSON(nlohmann::json j) { // clear all options while(options.size() > 0) { removeOption(0); } for(auto jm : j) { QString operation = QString::fromStdString(jm.value("operation", "")); if(operation.isEmpty()) { qWarning() << "Skipping empty de-embedding operation"; continue; } // attempt to find the type of operation DeembeddingOption::Type type = DeembeddingOption::Type::Last; for(unsigned int i=0;i<(int) DeembeddingOption::Type::Last;i++) { if(DeembeddingOption::getName((DeembeddingOption::Type) i) == operation) { // found the correct operation type = (DeembeddingOption::Type) i; break; } } if(type == DeembeddingOption::Type::Last) { // unable to find this operation qWarning() << "Unable to create de-embedding operation:" << operation; continue; } qDebug() << "Creating math operation of type:" << operation; auto op = DeembeddingOption::create(type); if(jm.contains("settings")) { op->fromJSON(jm["settings"]); } addOption(op); } }