diff --git a/Software/PC_Application/Traces/Marker/marker.cpp b/Software/PC_Application/Traces/Marker/marker.cpp index a25a1b8..0830a17 100644 --- a/Software/PC_Application/Traces/Marker/marker.cpp +++ b/Software/PC_Application/Traces/Marker/marker.cpp @@ -684,18 +684,51 @@ void Marker::traceDataChanged() void Marker::updateSymbol() { if(isDisplayedMarker()) { - constexpr int width = 15, height = 15; - symbol = QPixmap(width, height); - symbol.fill(Qt::transparent); - QPainter p(&symbol); - p.setRenderHint(QPainter::Antialiasing); - QPointF points[] = {QPointF(0,0),QPointF(width,0),QPointF(width/2,height)}; - auto traceColor = parentTrace->color(); - p.setPen(traceColor); - p.setBrush(traceColor); - p.drawConvexPolygon(points, 3); - p.setPen(Util::getFontColorFromBackground(traceColor)); - p.drawText(QRectF(0,0,width, height*2.0/3.0), Qt::AlignCenter, QString::number(number) + suffix); + auto style = Preferences::getInstance().Marker.symbolStyle; + switch(style) { + case MarkerSymbolStyle::FilledNumberInside: { + constexpr int width = 15, height = 15; + symbol = QPixmap(width, height); + symbol.fill(Qt::transparent); + QPainter p(&symbol); + p.setRenderHint(QPainter::Antialiasing); + QPointF points[] = {QPointF(0,0),QPointF(width,0),QPointF(width/2,height)}; + auto traceColor = parentTrace->color(); + p.setPen(traceColor); + p.setBrush(traceColor); + p.drawConvexPolygon(points, 3); + p.setPen(Util::getFontColorFromBackground(traceColor)); + p.drawText(QRectF(0,0,width, height * 2.0 / 3.0), Qt::AlignCenter, QString::number(number) + suffix); + } + break; + case MarkerSymbolStyle::FilledNumberAbove: { + constexpr int width = 15, height = 30; + symbol = QPixmap(width, height); + symbol.fill(Qt::transparent); + QPainter p(&symbol); + p.setRenderHint(QPainter::Antialiasing); + QPointF points[] = {QPointF(0,height/2),QPointF(width,height/2),QPointF(width/2,height)}; + auto traceColor = parentTrace->color(); + p.setPen(traceColor); + p.setBrush(traceColor); + p.drawConvexPolygon(points, 3); + p.drawText(QRectF(0,0,width, height * 0.45), Qt::AlignCenter, QString::number(number) + suffix); + } + break; + case MarkerSymbolStyle::EmptyNumberAbove: { + constexpr int width = 15, height = 30; + symbol = QPixmap(width, height); + symbol.fill(Qt::transparent); + QPainter p(&symbol); + p.setRenderHint(QPainter::Antialiasing); + QPointF points[] = {QPointF(0,height/2),QPointF(width,height/2),QPointF(width/2,height)}; + auto traceColor = parentTrace->color(); + p.setPen(traceColor); + p.drawConvexPolygon(points, 3); + p.drawText(QRectF(0,0,width, height * 0.45), Qt::AlignCenter, QString::number(number) + suffix); + } + break; + } } else { symbol = QPixmap(1,1); } diff --git a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp index 4bcea37..201d40b 100644 --- a/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp +++ b/Software/PC_Application/VNA/Deembedding/impedancerenormalization.cpp @@ -17,8 +17,34 @@ ImpedanceRenormalization::ImpedanceRenormalization() void ImpedanceRenormalization::transformDatapoint(VirtualDevice::VNAMeasurement &p) { - //p.S = Sparam(ABCDparam(p.S, p.Z0), impedance); - // TODO + std::map> transformed; + int ports = 0; + QString name = "S11"; + while(p.measurements.count(name) > 0) { + ports++; + name = "S"+QString::number(ports+1)+QString::number(ports+1); + } + for(auto i=1;i<=ports;i++) { + auto S11name = "S"+QString::number(i)+QString::number(i); + auto S11 = p.measurements[S11name]; + transformed[S11name] = Sparam(ABCDparam(Sparam(S11, 0.0, 0.0, 1.0), p.Z0), impedance).m11; + for(auto j=i+1;j<=ports;j++) { + auto S12name = "S"+QString::number(i)+QString::number(j); + auto S21name = "S"+QString::number(j)+QString::number(i); + auto S22name = "S"+QString::number(j)+QString::number(j); + if(!p.measurements.count(S12name) || !p.measurements.count(S21name) || !p.measurements.count(S22name)) { + // not all measurements available, skip this + continue; + } + auto S12 = p.measurements[S12name]; + auto S21 = p.measurements[S21name]; + auto S22 = p.measurements[S22name]; + auto S_t = Sparam(ABCDparam(Sparam(S11, S12, S21, S22), p.Z0), impedance); + transformed[S12name] = S_t.m12; + transformed[S21name] = S_t.m21; + } + } + p.measurements = transformed; p.Z0 = impedance; } diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp index 9521f10..5e425f2 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.cpp @@ -24,6 +24,7 @@ MatchingNetwork::MatchingNetwork() dragComponent = nullptr; dropComponent = nullptr; addNetwork = true; + port = 1; } void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p) @@ -34,26 +35,40 @@ void MatchingNetwork::transformDatapoint(VirtualDevice::VNAMeasurement &p) // this point is not calculated yet MatchingPoint m; // start with identiy matrix - m.p1 = ABCDparam(1.0,0.0,0.0,1.0); - for(auto c : p1Network) { - m.p1 = m.p1 * c->parameters(p.frequency); - } - // same for network at port 2 - m.p2 = ABCDparam(1.0,0.0,0.0,1.0); - for(auto c : p2Network) { - m.p2 = m.p2 * c->parameters(p.frequency); + m.p = ABCDparam(1.0,0.0,0.0,1.0); + for(auto c : network) { + m.p = m.p * c->parameters(p.frequency); } if(!addNetwork) { - // need to remove the effect of the networks, invert matrices - m.p1 = m.p1.inverse(); - m.p2 = m.p2.inverse(); + // need to remove the effect of the network, invert matrix + m.p = m.p.inverse(); } matching[p.frequency] = m; } // at this point the map contains the matching network effect auto m = matching[p.frequency]; - auto corrected = m.p1 * measurement * m.p2; - p.fromSparam(Sparam(corrected, p.Z0), 1, 2); + VirtualDevice::VNAMeasurement uncorrected = p; + // correct reflection measurement (in case no two-port measurement is complete + QString name = "S"+QString::number(port)+QString::number(port); + if(uncorrected.measurements.count(name) > 0) { + auto S = Sparam(uncorrected.measurements[name], 0.0, 0.0, 1.0); + auto corrected = Sparam(m.p * ABCDparam(S, p.Z0), p.Z0); + p.measurements[name] = corrected.m11; + } + // handle the rest of the measurements + for(int i=0;ilParallelL->installEventFilter(this); ui->lParallelR->installEventFilter(this); ui->lDefinedThrough->installEventFilter(this); + + ui->port->setValue(port); + ui->port->setMaximum(VirtualDevice::getInfo(VirtualDevice::getConnected()).ports); + layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); layout->addStretch(1); @@ -93,26 +112,15 @@ void MatchingNetwork::edit() DUT->setMaximumSize(DUTWidth, 151); DUT->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); DUT->setStyleSheet("image: url(:/icons/DUT.png);"); - auto p2 = new QWidget(); - p2->setMinimumSize(portWidth, 151); - p2->setMaximumSize(portWidth, 151); - p2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - p2->setStyleSheet("image: url(:/icons/port2.png);"); + layout->addWidget(p1); - for(auto w : p1Network) { + for(auto w : network) { layout->addWidget(w); connect(w, &MatchingComponent::MatchingComponent::valueChanged, [=](){ matching.clear(); }); } layout->addWidget(DUT); - for(auto w : p2Network) { - layout->addWidget(w); - connect(w, &MatchingComponent::MatchingComponent::valueChanged, [=](){ - matching.clear(); - }); - } - layout->addWidget(p2); layout->addStretch(1); @@ -129,37 +137,34 @@ void MatchingNetwork::edit() // network changed, need to recalculate matching matching.clear(); }); + connect(ui->port, qOverload(&QSpinBox::valueChanged), [=](){ + port = ui->port->value(); + }); connect(ui->buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); } nlohmann::json MatchingNetwork::toJSON() { nlohmann::json j; - nlohmann::json jn1, jn2; - for(auto c : p1Network) { + nlohmann::json jn; + for(auto c : network) { nlohmann::json jc; jc["component"] = c->getName().toStdString(); jc["params"] = c->toJSON(); - jn1.push_back(jc); + jn.push_back(jc); } - for(auto c : p2Network) { - nlohmann::json jc; - jc["component"] = c->getName().toStdString(); - jc["params"] = c->toJSON(); - jn2.push_back(jc); - } - j["port1"] = jn1; - j["port2"] = jn2; + j["port"] = port; + j["network"] = jn; j["addNetwork"] = addNetwork; return j; } void MatchingNetwork::fromJSON(nlohmann::json j) { - p1Network.clear(); - p2Network.clear(); - if(j.contains("port1")) { - for(auto jc : j["port1"]) { + network.clear(); + port = j.value("port", 1); + if(j.contains("network")) { + for(auto jc : j["network"]) { if(!jc.contains("component")) { continue; } @@ -168,20 +173,7 @@ void MatchingNetwork::fromJSON(nlohmann::json j) continue; } c->fromJSON(jc["params"]); - p1Network.push_back(c); - } - } - if(j.contains("port2")) { - for(auto jc : j["port2"]) { - if(!jc.contains("component")) { - continue; - } - auto c = MatchingComponent::createFromName(QString::fromStdString(jc["component"])); - if(!c) { - continue; - } - c->fromJSON(jc["params"]); - p2Network.push_back(c); + network.push_back(c); } } addNetwork = j.value("addNetwork", true); @@ -192,15 +184,9 @@ MatchingComponent *MatchingNetwork::componentAtPosition(int pos) { pos -= graph->layout()->itemAt(0)->geometry().width(); pos -= portWidth; - if(pos > 0 && pos <= (int) p1Network.size() * componentWidth) { + if(pos > 0 && pos <= (int) network.size() * componentWidth) { // position is in port 1 network - return p1Network[pos / componentWidth]; - } else if(pos > (int) p1Network.size() * componentWidth + DUTWidth) { - pos -= (int) p1Network.size() * componentWidth + DUTWidth; - if(pos <= (int) p2Network.size() * componentWidth) { - // position is in port 2 network - return p2Network[pos / componentWidth]; - } + return network[pos / componentWidth]; } return nullptr; } @@ -209,28 +195,15 @@ unsigned int MatchingNetwork::findInsertPosition(int xcoord) { xcoord -= graph->layout()->itemAt(0)->geometry().width(); xcoord -= portWidth; - if(xcoord <= (int) p1Network.size() * componentWidth + DUTWidth/2) { - // added in port 1 network - int index = (xcoord + componentWidth / 2) / componentWidth; - if(index < 0) { - index = 0; - } else if(index > (int) p1Network.size()) { - index = p1Network.size(); - } - // add 2 (first two widgets are always the stretch and port 1 widget) - return index + 2; - } else { - // added in port 2 network - xcoord -= (int) p1Network.size() * componentWidth + DUTWidth; - int index = (xcoord + componentWidth / 2) / componentWidth; - if(index < 0) { - index = 0; - } else if(index > (int) p2Network.size()) { - index = p2Network.size(); - } - // add 3 (same two widgets as in port 1 + DUT) and the size of the port 1 network - return index + 3 + p1Network.size(); + // added in port 1 network + int index = (xcoord + componentWidth / 2) / componentWidth; + if(index < 0) { + index = 0; + } else if(index > (int) network.size()) { + index = network.size(); } + // add 2 (first two widgets are always the stretch and port 1 widget) + return index + 2; } void MatchingNetwork::addComponentAtPosition(int pos, MatchingComponent *c) @@ -242,12 +215,7 @@ void MatchingNetwork::addComponentAtPosition(int pos, MatchingComponent *c) // add component to correct matching network index -= 2; // first two widgets are fixed - if(index <= p1Network.size()) { - addComponent(true, index, c); - } else { - index -= 1 + p1Network.size(); - addComponent(false, index, c); - } + addComponent(index, c); // network changed, need to recalculate matching matching.clear(); @@ -256,22 +224,13 @@ void MatchingNetwork::addComponentAtPosition(int pos, MatchingComponent *c) }); } -void MatchingNetwork::addComponent(bool port1, int index, MatchingComponent *c) +void MatchingNetwork::addComponent(int index, MatchingComponent *c) { - if(port1) { - p1Network.insert(p1Network.begin() + index, c); - // remove from list when the component deletes itself - connect(c, &MatchingComponent::deleted, [=](){ - p1Network.erase(remove(p1Network.begin(), p1Network.end(), c), p1Network.end()); - }); - } else { - // same procedure for port 2 network - p2Network.insert(p2Network.begin() + index, c); - // remove from list when the component deletes itself - connect(c, &MatchingComponent::deleted, [=](){ - p2Network.erase(remove(p2Network.begin(), p2Network.end(), c), p2Network.end()); - }); - } + network.insert(network.begin() + index, c); + // remove from list when the component deletes itself + connect(c, &MatchingComponent::deleted, [=](){ + network.erase(remove(network.begin(), network.end(), c), network.end()); + }); } void MatchingNetwork::createDragComponent(MatchingComponent *c) @@ -326,8 +285,7 @@ bool MatchingNetwork::eventFilter(QObject *object, QEvent *event) // remove and hide component while it is being dragged graph->layout()->removeWidget(dragComponent); dragComponent->hide(); - p1Network.erase(remove(p1Network.begin(), p1Network.end(), dragComponent), p1Network.end()); - p2Network.erase(remove(p2Network.begin(), p2Network.end(), dragComponent), p2Network.end()); + network.erase(remove(network.begin(), network.end(), dragComponent), network.end()); graph->update(); // network changed, need to recalculate matching diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h index e881a76..314a4f9 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetwork.h +++ b/Software/PC_Application/VNA/Deembedding/matchingnetwork.h @@ -77,11 +77,13 @@ private: MatchingComponent *componentAtPosition(int pos); unsigned int findInsertPosition(int xcoord); void addComponentAtPosition(int pos, MatchingComponent *c); - void addComponent(bool port1, int index, MatchingComponent *c); + void addComponent(int index, MatchingComponent *c); void createDragComponent(MatchingComponent *c); void updateInsertIndicator(int xcoord); bool eventFilter(QObject *object, QEvent *event) override; - std::vector p1Network, p2Network; + + std::vector network; + int port; QWidget *graph, *insertIndicator; QPoint dragStartPosition; @@ -91,7 +93,7 @@ private: class MatchingPoint { public: - ABCDparam p1, p2; + ABCDparam p; }; std::map matching; diff --git a/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui b/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui index a1c67f3..5b9a10a 100644 --- a/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui +++ b/Software/PC_Application/VNA/Deembedding/matchingnetworkdialog.ui @@ -6,8 +6,8 @@ 0 0 - 772 - 443 + 913 + 633 @@ -21,6 +21,37 @@ + + + + + + Port: + + + + + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -48,7 +79,7 @@ 0 0 - 750 + 891 168 diff --git a/Software/PC_Application/VNA/Deembedding/portextension.cpp b/Software/PC_Application/VNA/Deembedding/portextension.cpp index edcf601..0b0e2a8 100644 --- a/Software/PC_Application/VNA/Deembedding/portextension.cpp +++ b/Software/PC_Application/VNA/Deembedding/portextension.cpp @@ -13,50 +13,35 @@ using namespace std; PortExtension::PortExtension() : DeembeddingOption() { - port1.enabled = false; - port1.frequency = 0; - port1.loss = 0; - port1.DCloss = 0; - port1.delay = 0; - port1.velocityFactor = 0.66; - port2.enabled = false; - port2.frequency = 0; - port2.loss = 0; - port2.DCloss = 0; - port2.delay = 0; - port2.velocityFactor = 0.66; + ext.frequency = 0; + ext.loss = 0; + ext.DCloss = 0; + ext.delay = 0; + ext.velocityFactor = 0.66; + + port = 1; kit = nullptr; } void PortExtension::transformDatapoint(VirtualDevice::VNAMeasurement &d) { - if(port1.enabled || port2.enabled) { - if(port1.enabled) { - auto phase = -2 * M_PI * port1.delay * d.frequency; - auto db_attennuation = port1.DCloss; - if(port1.frequency != 0) { - db_attennuation += port1.loss * sqrt(d.frequency / port1.frequency); - } - // convert from db to factor - auto att = pow(10.0, -db_attennuation / 20.0); - auto correction = polar(att, phase); - d.measurements["S11"] /= correction * correction; - d.measurements["S21"] /= correction; - d.measurements["S12"] /= correction; + auto phase = -2 * M_PI * ext.delay * d.frequency; + auto db_attennuation = ext.DCloss; + if(ext.frequency != 0) { + db_attennuation += ext.loss * sqrt(d.frequency / ext.frequency); + } + // convert from db to factor + auto att = pow(10.0, -db_attennuation / 20.0); + auto correction = polar(att, phase); + for(auto &m : d.measurements) { + if(m.first.mid(1, 1).toInt() == port) { + // selected port is the destination of this S parameter + m.second /= correction; } - if(port2.enabled) { - auto phase = -2 * M_PI * port2.delay * d.frequency; - auto db_attennuation = port2.DCloss; - if(port2.frequency != 0) { - db_attennuation += port2.loss * sqrt(d.frequency / port2.frequency); - } - // convert from db to factor - auto att = pow(10.0, -db_attennuation / 20.0); - auto correction = polar(att, phase); - d.measurements["S22"] /= correction * correction; - d.measurements["S21"] /= correction; - d.measurements["S12"] /= correction; + if(m.first.mid(2, 1).toInt() == port) { + // selected port is the source of this S parameter + m.second /= correction; } } } @@ -73,117 +58,56 @@ void PortExtension::edit() }); // set initial values - ui->P1Enabled->setChecked(port1.enabled); - ui->P1Time->setUnit("s"); - ui->P1Time->setPrefixes("pnum "); - ui->P1Distance->setUnit("m"); - ui->P1Distance->setPrefixes("m "); - ui->P1DCloss->setUnit("db"); - ui->P1Loss->setUnit("db"); - ui->P1Frequency->setUnit("Hz"); - ui->P1Frequency->setPrefixes(" kMG"); - ui->P1Time->setValue(port1.delay); - ui->P1Velocity->setValue(port1.velocityFactor); - ui->P1Distance->setValue(port1.delay * port1.velocityFactor * c); - ui->P1DCloss->setValue(port1.DCloss); - ui->P1Loss->setValue(port1.loss); - ui->P1Frequency->setValue(port1.frequency); + ui->Time->setUnit("s"); + ui->Time->setPrefixes("pnum "); + ui->Distance->setUnit("m"); + ui->Distance->setPrefixes("m "); + ui->DCloss->setUnit("db"); + ui->Loss->setUnit("db"); + ui->Frequency->setUnit("Hz"); + ui->Frequency->setPrefixes(" kMG"); + ui->Time->setValue(ext.delay); + ui->Velocity->setValue(ext.velocityFactor); + ui->Distance->setValue(ext.delay * ext.velocityFactor * c); + ui->DCloss->setValue(ext.DCloss); + ui->Loss->setValue(ext.loss); + ui->Frequency->setValue(ext.frequency); if(!kit) { - ui->P1calkit->setEnabled(false); - } - - ui->P2Enabled->setChecked(port2.enabled); - ui->P2Time->setUnit("s"); - ui->P2Time->setPrefixes("pnum "); - ui->P2Distance->setUnit("m"); - ui->P2Distance->setPrefixes("m "); - ui->P2DCloss->setUnit("db"); - ui->P2Loss->setUnit("db"); - ui->P2Frequency->setUnit("Hz"); - ui->P2Frequency->setPrefixes(" kMG"); - ui->P2Time->setValue(port2.delay); - ui->P2Velocity->setValue(port2.velocityFactor); - ui->P2Distance->setValue(port2.delay * port2.velocityFactor * c); - ui->P2DCloss->setValue(port2.DCloss); - ui->P2Loss->setValue(port2.loss); - ui->P2Frequency->setValue(port2.frequency); - if(!kit) { - ui->P2calkit->setEnabled(false); + ui->calkit->setEnabled(false); } auto updateValuesFromUI = [=](){ - port1.delay = ui->P1Time->value(); - port1.velocityFactor = ui->P1Velocity->value(); - port1.DCloss = ui->P1DCloss->value(); - port1.loss = ui->P1Loss->value(); - port1.frequency = ui->P1Frequency->value(); - port2.delay = ui->P2Time->value(); - port2.velocityFactor = ui->P2Velocity->value(); - port2.DCloss = ui->P2DCloss->value(); - port2.loss = ui->P2Loss->value(); - port2.frequency = ui->P2Frequency->value(); + ext.delay = ui->Time->value(); + ext.velocityFactor = ui->Velocity->value(); + ext.DCloss = ui->DCloss->value(); + ext.loss = ui->Loss->value(); + ext.frequency = ui->Frequency->value(); }; - connect(ui->P1Enabled, &QCheckBox::toggled, [=](bool enabled) { - port1.enabled = enabled; - }); // connections to link delay and distance - connect(ui->P1Time, &SIUnitEdit::valueChanged, [=](double newval) { - ui->P1Distance->setValueQuiet(newval * ui->P1Velocity->value() * c); + connect(ui->Time, &SIUnitEdit::valueChanged, [=](double newval) { + ui->Distance->setValueQuiet(newval * ui->Velocity->value() * c); updateValuesFromUI(); }); - connect(ui->P1Distance, &SIUnitEdit::valueChanged, [=](double newval) { - ui->P1Time->setValueQuiet(newval / (ui->P1Velocity->value() * c)); + connect(ui->Distance, &SIUnitEdit::valueChanged, [=](double newval) { + ui->Time->setValueQuiet(newval / (ui->Velocity->value() * c)); updateValuesFromUI(); }); - connect(ui->P1Velocity, &SIUnitEdit::valueChanged, [=](double newval) { - ui->P1Time->setValueQuiet(ui->P1Distance->value() / (newval * c)); + connect(ui->Velocity, &SIUnitEdit::valueChanged, [=](double newval) { + ui->Time->setValueQuiet(ui->Distance->value() / (newval * c)); updateValuesFromUI(); }); - connect(ui->P1DCloss, &SIUnitEdit::valueChanged, updateValuesFromUI); - connect(ui->P1Loss, &SIUnitEdit::valueChanged, updateValuesFromUI); - connect(ui->P1Frequency, &SIUnitEdit::valueChanged, updateValuesFromUI); - connect(ui->P1short, &QPushButton::pressed, [=](){ + connect(ui->DCloss, &SIUnitEdit::valueChanged, updateValuesFromUI); + connect(ui->Loss, &SIUnitEdit::valueChanged, updateValuesFromUI); + connect(ui->Frequency, &SIUnitEdit::valueChanged, updateValuesFromUI); + connect(ui->_short, &QPushButton::pressed, [=](){ isOpen = false; - isPort1 = true; - isIdeal = ui->P1ideal->isChecked(); + isIdeal = ui->ideal->isChecked(); startMeasurement(); }); - connect(ui->P1open, &QPushButton::pressed, [=](){ + connect(ui->open, &QPushButton::pressed, [=](){ isOpen = true; - isPort1 = true; - isIdeal = ui->P1ideal->isChecked(); - startMeasurement(); - }); - - connect(ui->P2Enabled, &QCheckBox::toggled, [=](bool enabled) { - port2.enabled = enabled; - }); - connect(ui->P2Time, &SIUnitEdit::valueChanged, [=](double newval) { - ui->P2Distance->setValueQuiet(newval * ui->P2Velocity->value() * c); - updateValuesFromUI(); - }); - connect(ui->P2Distance, &SIUnitEdit::valueChanged, [=](double newval) { - ui->P2Time->setValueQuiet(newval / (ui->P2Velocity->value() * c)); - updateValuesFromUI(); - }); - connect(ui->P2Velocity, &SIUnitEdit::valueChanged, [=](double newval) { - ui->P2Time->setValueQuiet(ui->P2Distance->value() / (newval * c)); - updateValuesFromUI(); - }); - connect(ui->P2DCloss, &SIUnitEdit::valueChanged, updateValuesFromUI); - connect(ui->P2Loss, &SIUnitEdit::valueChanged, updateValuesFromUI); - connect(ui->P2Frequency, &SIUnitEdit::valueChanged, updateValuesFromUI); - connect(ui->P2short, &QPushButton::pressed, [=](){ - isOpen = false; - isPort1 = false; - isIdeal = ui->P2ideal->isChecked(); - startMeasurement(); - }); - connect(ui->P2open, &QPushButton::pressed, [=](){ - isOpen = true; - isPort1 = false; - isIdeal = ui->P2ideal->isChecked(); + isIdeal = ui->ideal->isChecked(); startMeasurement(); }); @@ -203,22 +127,17 @@ void PortExtension::measurementCompleted(std::vector reflection; - if(isPort1) { - reflection = p.measurements["S11"]; - } else { - reflection = p.measurements["S22"]; - } + QString name = "S"+QString::number(port)+QString::number(port); + auto reflection = p.measurements[name]; // remove calkit if specified if(!isIdeal) { complex calStandard = 1.0; - // TODO -// auto standards = kit->toSOLT(p.frequency); -// if(isOpen) { -// calStandard = standards.Open; -// } else { -// calStandard = standards.Short; -// } + auto comp = isOpen ? CalStandard::Virtual::Type::Open : CalStandard::Virtual::Type::Short; + for(auto s : kit->getStandards()) { + if(s->getType() == comp) { + calStandard = static_cast(s)->toS11(p.frequency); + } + } // remove effect of calibration standard reflection /= calStandard; } @@ -266,23 +185,16 @@ void PortExtension::measurementCompleted(std::vectorP1Time->setValue(delay); - ui->P1DCloss->setValue(DCloss); - ui->P1Loss->setValue(loss); - ui->P1Frequency->setValue(freq); - } else { - ui->P2Time->setValue(delay); - ui->P2DCloss->setValue(DCloss); - ui->P2Loss->setValue(loss); - ui->P2Frequency->setValue(freq); - } + ui->Time->setValue(delay); + ui->DCloss->setValue(DCloss); + ui->Loss->setValue(loss); + ui->Frequency->setValue(freq); } } void PortExtension::startMeasurement() { - emit triggerMeasurement(isPort1, false, false, !isPort1); + emit triggerMeasurement(); } void PortExtension::setCalkit(Calkit *kit) @@ -293,35 +205,28 @@ void PortExtension::setCalkit(Calkit *kit) nlohmann::json PortExtension::toJSON() { nlohmann::json j; - for(int i=0;i<2;i++) { - auto ext = i == 0 ? port1 : port2; - nlohmann::json je; - je["enabled"] = ext.enabled; - je["delay"] = ext.delay; - je["velocityFactor"] = ext.velocityFactor; - je["DCloss"] = ext.DCloss; - je["loss"] = ext.loss; - je["frequency"] = ext.frequency; - j.push_back(je); - } + j["port"] = port; + j["delay"] = ext.delay; + j["velocityFactor"] = ext.velocityFactor; + j["DCloss"] = ext.DCloss; + j["loss"] = ext.loss; + j["frequency"] = ext.frequency; return j; } void PortExtension::fromJSON(nlohmann::json j) { - for(int i=0;i<2;i++) { - Extension ext; - nlohmann::json je = j[i]; - ext.enabled = je.value("enabled", false); - ext.delay = je.value("delay", 0.0); - ext.velocityFactor = je.value("velocityFactor", 0.66); - ext.DCloss = je.value("DCloss", 0.0); - ext.loss = je.value("loss", 0.0); - ext.frequency = je.value("frequency", 6000000000); - if(i==0) { - port1 = ext; - } else { - port2 = ext; - } + nlohmann::json jfrom; + if(j.contains("port")) { + // new format + jfrom = j; + } else { + jfrom = j[0]; + port = 1; } + ext.delay = jfrom.value("delay", 0.0); + ext.velocityFactor = jfrom.value("velocityFactor", 0.66); + ext.DCloss = jfrom.value("DCloss", 0.0); + ext.loss = jfrom.value("loss", 0.0); + ext.frequency = jfrom.value("frequency", 6000000000); } diff --git a/Software/PC_Application/VNA/Deembedding/portextension.h b/Software/PC_Application/VNA/Deembedding/portextension.h index fa649df..5013e0b 100644 --- a/Software/PC_Application/VNA/Deembedding/portextension.h +++ b/Software/PC_Application/VNA/Deembedding/portextension.h @@ -31,18 +31,17 @@ private: void startMeasurement(); class Extension { public: - bool enabled; double delay; double velocityFactor; double DCloss; double loss; double frequency; }; - Extension port1, port2; + Extension ext; // status variables for automatic measurements Calkit *kit; - bool isPort1; + int port; bool isOpen; bool isIdeal; diff --git a/Software/PC_Application/VNA/Deembedding/portextensioneditdialog.ui b/Software/PC_Application/VNA/Deembedding/portextensioneditdialog.ui index a245e38..3100071 100644 --- a/Software/PC_Application/VNA/Deembedding/portextensioneditdialog.ui +++ b/Software/PC_Application/VNA/Deembedding/portextensioneditdialog.ui @@ -9,8 +9,8 @@ 0 0 - 318 - 505 + 312 + 459 @@ -21,310 +21,157 @@ - - - 0 + + + + + Port: + + + + + + + 1 + + + + + + + + + Delay - - - Port 1 - - - - - - Enabled - - - - - - - Delay - - - - - - Distance: - - - - - - - - - - Time: - - - - - - - - - - Velocity Factor: - - - - - - - - - - - - - Loss - - - - - - - - At DC: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - at - - - - - - - - - - - - - - - Determine automatically - - - - - - Assume ideal open/short - - - true - - - - - - - Use definition from calibration kit - - - - - - - - - Measure short - - - - - - - Measure open - - - - - - - - - - - - - Port 2 - - - - - - Enabled - - - - - - - Delay - - - - - - Distance: - - - - - - - - - - Time: - - - - - - - - - - Velocity Factor: - - - - - - - - - - - - - Loss - - - - - - - - At DC: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - at - - - - - - - - - - - - - - - Determine automatically - - - - - - Assume ideal open/short - - - true - - - - - - - Use definition from calibration kit - - - - - - - - - Measure short - - - - - - - Measure open - - - - - - - - - - + + + + + Distance: + + + + + + + + + + Time: + + + + + + + + + + Velocity Factor: + + + + + + + + + + + + + Loss + + + + + + + + At DC: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + at + + + + + + + + + + + + + + + Determine automatically + + + + + + Assume ideal open/short + + + true + + + + + + + Use definition from calibration kit + + + + + + + + + Measure short + + + + + + + Measure open + + + + + + diff --git a/Software/PC_Application/VNA/Deembedding/twothru.cpp b/Software/PC_Application/VNA/Deembedding/twothru.cpp index 6af2cc0..062298c 100644 --- a/Software/PC_Application/VNA/Deembedding/twothru.cpp +++ b/Software/PC_Application/VNA/Deembedding/twothru.cpp @@ -13,13 +13,15 @@ using namespace std; TwoThru::TwoThru() { Z0 = 50.0; + port1 = 1; + port2 = 2; } void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p) { // correct measurement if(points.size() > 0) { - Tparam meas(p.toSparam(1,2)); + Tparam meas(p.toSparam(port1,port2)); Tparam inv1, inv2; if(p.frequency < points.front().freq) { @@ -49,7 +51,7 @@ void TwoThru::transformDatapoint(VirtualDevice::VNAMeasurement &p) // perform correction Tparam corrected = inv1*meas*inv2; // transform back into S parameters - p.fromSparam(Sparam(corrected), 1, 2); + p.fromSparam(Sparam(corrected), port1, port2); } } @@ -125,6 +127,27 @@ void TwoThru::edit() ui->Z0->setVisible(false); ui->lZ0->setVisible(false); + ui->port1->setValue(port1); + ui->port1->setMaximum(VirtualDevice::getInfo(VirtualDevice::getConnected()).ports); + ui->port2->setValue(port2); + ui->port2->setMaximum(VirtualDevice::getInfo(VirtualDevice::getConnected()).ports); + + auto portChanged = [=](){ + port1 = ui->port1->value(); + port2 = ui->port2->value(); + // clear all points + points.clear(); + measurements2xthru.clear(); + measurementsDUT.clear(); + // enable taking of new measurements only if ports are different + ui->bMeasure->setEnabled(port1 != port2); + ui->bMeasureDUT->setEnabled(port1 != port2); + updateGUI(); + }; + + connect(ui->port1, qOverload(&QSpinBox::valueChanged), portChanged); + connect(ui->port2, qOverload(&QSpinBox::valueChanged), portChanged); + connect(ui->bMeasure, &QPushButton::clicked, [=](){ measuringDUT = false; measuring2xthru = true; @@ -168,6 +191,8 @@ void TwoThru::edit() nlohmann::json TwoThru::toJSON() { nlohmann::json j; + j["port1"] = port1; + j["port2"] = port2; for(auto p : points) { nlohmann::json jp; jp["frequency"] = p.freq; @@ -194,6 +219,8 @@ nlohmann::json TwoThru::toJSON() void TwoThru::fromJSON(nlohmann::json j) { + port1 = j.value("port1", 1); + port2 = j.value("port2", 2); points.clear(); for(auto jp : j) { Point p; @@ -229,10 +256,11 @@ std::vector TwoThru::calculateErrorBoxes(std::vector interpolateEvenFrequencySteps(std::vector input); - static std::vector calculateErrorBoxes(std::vector data_2xthru); - static std::vector calculateErrorBoxes(std::vector data_2xthru, std::vector data_fix_dut_fix, double z0); + std::vector calculateErrorBoxes(std::vector data_2xthru); + std::vector calculateErrorBoxes(std::vector data_2xthru, std::vector data_fix_dut_fix, double z0); std::vector measurements2xthru; std::vector measurementsDUT; double Z0; + int port1, port2; std::vector points; bool measuring2xthru; bool measuringDUT; diff --git a/Software/PC_Application/VNA/Deembedding/twothrudialog.ui b/Software/PC_Application/VNA/Deembedding/twothrudialog.ui index 29ac935..8de43dc 100644 --- a/Software/PC_Application/VNA/Deembedding/twothrudialog.ui +++ b/Software/PC_Application/VNA/Deembedding/twothrudialog.ui @@ -9,8 +9,8 @@ 0 0 - 701 - 465 + 732 + 520 @@ -19,7 +19,7 @@ true - + @@ -51,6 +51,56 @@ + + + + Configuration + + + + + + 2xthru is between ports + + + + + + + 1 + + + + + + + and + + + + + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + diff --git a/Software/PC_Application/main.cpp b/Software/PC_Application/main.cpp index ced0fea..cabdd98 100644 --- a/Software/PC_Application/main.cpp +++ b/Software/PC_Application/main.cpp @@ -1,11 +1,14 @@ #include "appwindow.h" #include #include "Device/device.h" -#include "Device/virtualdevice.h" #ifdef Q_OS_UNIX #include #endif +#include "Tools/parameters.h" +#include +using namespace std; + static QApplication *app; static AppWindow *window; @@ -21,9 +24,6 @@ int main(int argc, char *argv[]) { qSetMessagePattern("%{time process}: [%{type}] %{message}"); - Device::RegisterTypes(); - VirtualDevice::RegisterTypes(); - app = new QApplication(argc, argv); QCoreApplication::setOrganizationName("LibreVNA"); QCoreApplication::setApplicationName("LibreVNA-GUI"); @@ -31,6 +31,34 @@ int main(int argc, char *argv[]) { QCoreApplication::setApplicationVersion(window->getAppVersion() + "-" + window->getAppGitHash().left(9)); + Device::RegisterTypes(); + + auto S11 = complex(-0.5, 0.25); + auto S22 = complex(0.5, 0.15); + auto S33 = complex(0.8, -0.25); + + auto S12 = complex(0.1, 0); + auto S21 = complex(0.2, 0.3); + + auto S13 = complex(0.3, -0.2); + auto S31 = complex(0.4, 0.4); + + auto S23 = complex(0.5, 0.2); + auto S32 = complex(0.6, -0.2); + + auto p12 = Sparam(S11, S12, S21, S22); + auto p12_only = Sparam(0.0, S12, 1.0, 0.0); + auto p13 = Sparam(S11, S13, S31, S33); + auto p23 = Sparam(S22, S23, S32, S33); + + // convert to 75 ohm + auto p12_75 = Sparam(ABCDparam(p12, 50.0), 75.0); + auto p12_only_75 = Sparam(ABCDparam(p12_only, 50.0), 75.0); + auto p13_75 = Sparam(ABCDparam(p12, 50.0), 75.0); + auto Zp23_75 = Sparam(ABCDparam(p12, 50.0), 75.0); + + auto p1 = Sparam(S11, 0.0, 0.0, 1.0); + auto p1_75 = Sparam(ABCDparam(p12, 50.0), 75.0); #ifdef Q_OS_UNIX signal(SIGINT, tryExitGracefully); diff --git a/Software/PC_Application/preferences.cpp b/Software/PC_Application/preferences.cpp index ea19482..aa95f8e 100644 --- a/Software/PC_Application/preferences.cpp +++ b/Software/PC_Application/preferences.cpp @@ -310,6 +310,7 @@ void PreferencesDialog::setInitialGUIState() ui->MarkerShowAllMarkerData->setChecked(p->Marker.defaultBehavior.showAllData); ui->MarkerInterpolate->setCurrentIndex(p->Marker.interpolatePoints ? 1 : 0); ui->MarkerSortOrder->setCurrentIndex((int) p->Marker.sortOrder); + ui->MarkerSymbolStyle->setCurrentIndex((int) p->Marker.symbolStyle); ui->SCPIServerEnabled->setChecked(p->SCPIServer.enabled); ui->SCPIServerPort->setValue(p->SCPIServer.port); @@ -380,6 +381,7 @@ void PreferencesDialog::updateFromGUI() p->Marker.defaultBehavior.showAllData = ui->MarkerShowAllMarkerData->isChecked(); p->Marker.interpolatePoints = ui->MarkerInterpolate->currentIndex() == 1; p->Marker.sortOrder = (MarkerSortOrder) ui->MarkerSortOrder->currentIndex(); + p->Marker.symbolStyle = (MarkerSymbolStyle) ui->MarkerSymbolStyle->currentIndex(); p->SCPIServer.enabled = ui->SCPIServerEnabled->isChecked(); p->SCPIServer.port = ui->SCPIServerPort->value(); diff --git a/Software/PC_Application/preferences.h b/Software/PC_Application/preferences.h index 1699e9f..fab2a8e 100644 --- a/Software/PC_Application/preferences.h +++ b/Software/PC_Application/preferences.h @@ -34,6 +34,14 @@ enum MarkerSortOrder { Q_DECLARE_METATYPE(MarkerSortOrder) +enum MarkerSymbolStyle { + FilledNumberInside = 0, + FilledNumberAbove = 1, + EmptyNumberAbove = 2, +}; + +Q_DECLARE_METATYPE(MarkerSymbolStyle); + class Preferences : public Savable { public: @@ -126,6 +134,7 @@ public: } defaultBehavior; bool interpolatePoints; MarkerSortOrder sortOrder; + MarkerSymbolStyle symbolStyle; } Marker; struct { bool enabled; @@ -204,6 +213,7 @@ private: {&Marker.defaultBehavior.showAllData, "Marker.defaultBehavior.ShowAllData", false}, {&Marker.interpolatePoints, "Marker.interpolatePoints", false}, {&Marker.sortOrder, "Marker.sortOrder", MarkerSortOrder::PrefMarkerSortXCoord}, + {&Marker.symbolStyle, "Marker.symbolStyle", MarkerSymbolStyle::EmptyNumberAbove}, {&SCPIServer.enabled, "SCPIServer.enabled", true}, {&SCPIServer.port, "SCPIServer.port", 19542}, {&compoundDeviceJSON, "compoundDeviceJSON", "[]"}, diff --git a/Software/PC_Application/preferencesdialog.ui b/Software/PC_Application/preferencesdialog.ui index f7fa1a9..76da164 100644 --- a/Software/PC_Application/preferencesdialog.ui +++ b/Software/PC_Application/preferencesdialog.ui @@ -84,7 +84,7 @@ 0 0 687 - 938 + 884 @@ -103,7 +103,7 @@ - 1 + 0 @@ -1286,6 +1286,32 @@ + + + + Symbol Style: + + + + + + + + Filled triangle - Marker number inside + + + + + Filled triangle - Marker number above + + + + + Empty triangle - Marker number above + + + +