LibreVNA/Software/PC_Application/LibreVNA-GUI/VNA/Deembedding/matchingnetwork.cpp

837 lines
28 KiB
C++

#include "matchingnetwork.h"
#include "ui_matchingnetworkdialog.h"
#include "unit.h"
#include "CustomWidgets/informationbox.h"
#include "appwindow.h"
#include "Util/util.h"
#include <QDialog>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSpacerItem>
#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
#include <algorithm>
#include <QDebug>
#include <QFileDialog>
using namespace std;
MatchingNetwork::MatchingNetwork()
: DeembeddingOption("MATCHing")
{
dropPending = false;
dragComponent = nullptr;
dropComponent = nullptr;
addNetwork = true;
port = 1;
graph = nullptr;
insertIndicator = nullptr;
addUnsignedIntParameter("PORT", port);
addBoolParameter("ADD", addNetwork);
add(new SCPICommand("CLEAR", [=](QStringList params) -> QString {
Q_UNUSED(params);
clearNetwork();
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
add(new SCPICommand("NUMber", nullptr, [=](QStringList params) -> QString {
Q_UNUSED(params);
return QString::number(network.size());
}));
add(new SCPICommand("NEW", [=](QStringList params) -> QString {
if(params.size() < 1) {
return SCPI::getResultName(SCPI::Result::Error);
}
auto c = MatchingComponent::createFromName(params[0].replace("_", " "));
if(!c) {
return SCPI::getResultName(SCPI::Result::Error);
}
unsigned long long index = network.size();
// parse index (unchanged if not provided)
SCPI::paramToULongLong(params, 1, index);
addComponent(index, c);
return SCPI::getResultName(SCPI::Result::Empty);
}, nullptr));
add(new SCPICommand("TYPE", nullptr, [=](QStringList params) -> QString {
unsigned long long index = 0;
if(!SCPI::paramToULongLong(params, 0, index)) {
return SCPI::getResultName(SCPI::Result::Error);
}
if(index < 1 || index > network.size()) {
return SCPI::getResultName(SCPI::Result::Error);
}
return network[index-1]->getName().replace(" ", "_");
}));
}
MatchingNetwork::~MatchingNetwork()
{
clearNetwork();
}
std::set<unsigned int> MatchingNetwork::getAffectedPorts()
{
return {port};
}
void MatchingNetwork::transformDatapoint(DeviceDriver::VNAMeasurement &p)
{
if(matching.count(p.frequency) == 0) {
// this point is not calculated yet
MatchingPoint m;
// start with identiy matrix
m.forward = ABCDparam(1.0,0.0,0.0,1.0);
m.reverse = ABCDparam(1.0,0.0,0.0,1.0);
for(unsigned int i=0;i<network.size();i++) {
m.forward = m.forward * network[i]->parameters(p.frequency);
m.reverse = m.reverse * network[network.size()-i-1]->parameters(p.frequency);
}
if(!addNetwork) {
// need to remove the effect of the network, invert matrix
m.forward = m.forward.inverse();
m.reverse = m.reverse.inverse();
}
matching[p.frequency] = m;
}
// at this point the map contains the matching network effect
auto m = matching[p.frequency];
DeviceDriver::VNAMeasurement uncorrected = p;
auto portReflectionName = "S"+QString::number(port)+QString::number(port);
if(!uncorrected.measurements.count(portReflectionName)) {
// the reflection measurement for the port to de-embed is not included, nothing can be done
return;
}
// calculate internal reflection at the matching port
auto portReflectionS = uncorrected.measurements[portReflectionName];
auto matchingReflectionS = Sparam(m.forward, p.Z0).m22;
auto internalPortReflectionS = matchingReflectionS / (1.0 - matchingReflectionS * portReflectionS);
// handle the measurements
for(auto &meas : p.measurements) {
QString name = meas.first;
unsigned int i = name.mid(1,1).toUInt();
unsigned int j = name.mid(2,1).toUInt();
if(i == j) {
// reflection measurement
if(i == port) {
// the port of the matching network itself
auto S = Sparam(uncorrected.measurements[name], 1.0, 1.0, 0.0);
auto corrected = Sparam(m.forward * ABCDparam(S, p.Z0), p.Z0);
p.measurements[name] = corrected.m11;
} else {
// another reflection measurement
try {
auto S = uncorrected.toSparam(i, port);
auto corrected = Sparam(ABCDparam(S, p.Z0) * m.reverse, p.Z0);
p.fromSparam(corrected, i, port);
} catch (...) {
// missing measurements, nothing can be done
}
}
} else {
// through measurement
if(i != port && j != port) {
try {
// find through measurements from these two ports to and from the embedding port
auto toPort = uncorrected.measurements["S"+QString::number(port)+QString::number(j)];
auto fromPort = uncorrected.measurements["S"+QString::number(i)+QString::number(port)];
p.measurements[name] = p.measurements[name] + toPort * internalPortReflectionS * fromPort;
} catch (...) {
// missing measurements, nothing can be done
}
} else {
// Already handled by reflection measurement (toSparam uses S12/S21 as well)
// and if the corresponding reflection measurement is not available, we can't
// do anything anyway
}
}
}
}
void MatchingNetwork::edit()
{
auto dialog = new QDialog();
auto ui = new Ui::MatchingNetworkDialog();
ui->setupUi(dialog);
connect(dialog, &QDialog::finished, [=](){
delete ui;
});
dialog->setModal(true);
graph = new QWidget();
ui->scrollArea->setWidget(graph);
auto layout = new QHBoxLayout();
graph->setLayout(layout);
graph->setAcceptDrops(true);
graph->setObjectName("Graph");
graph->installEventFilter(this);
ui->lSeriesC->installEventFilter(this);
ui->lSeriesL->installEventFilter(this);
ui->lSeriesR->installEventFilter(this);
ui->lParallelC->installEventFilter(this);
ui->lParallelL->installEventFilter(this);
ui->lParallelR->installEventFilter(this);
ui->lDefinedThrough->installEventFilter(this);
ui->lDefinedShunt->installEventFilter(this);
ui->port->setValue(port);
ui->port->setMaximum(DeviceDriver::maximumSupportedPorts);
layout->setContentsMargins(0,0,0,0);
layout->setSpacing(0);
layout->addStretch(1);
auto p1 = new QWidget();
p1->setMinimumSize(portWidth, 151);
p1->setMaximumSize(portWidth, 151);
p1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
p1->setStyleSheet("image: url(:/icons/port.png);");
auto DUT = new QWidget();
DUT->setMinimumSize(DUTWidth, 151);
DUT->setMaximumSize(DUTWidth, 151);
DUT->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
DUT->setStyleSheet("image: url(:/icons/DUT_onePort.png);");
layout->addWidget(p1);
for(auto w : network) {
layout->addWidget(w);
connect(w, &MatchingComponent::MatchingComponent::valueChanged, [=](){
matching.clear();
});
}
layout->addWidget(DUT);
layout->addStretch(1);
if(AppWindow::showGUI()) {
dialog->show();
}
if(addNetwork) {
ui->bAddNetwork->setChecked(true);
} else {
ui->bRemoveNetwork->setChecked(true);
}
connect(ui->bAddNetwork, &QRadioButton::toggled, [=](bool add) {
addNetwork = add;
// network changed, need to recalculate matching
matching.clear();
});
connect(ui->port, qOverload<int>(&QSpinBox::valueChanged), [=](){
port = ui->port->value();
});
connect(ui->buttonBox, &QDialogButtonBox::accepted, [=](){
graph = nullptr;
dialog->accept();
});
}
nlohmann::json MatchingNetwork::toJSON()
{
nlohmann::json j;
nlohmann::json jn;
for(auto c : network) {
nlohmann::json jc;
jc["component"] = c->getName().toStdString();
jc["params"] = c->toJSON();
jn.push_back(jc);
}
j["port"] = port;
j["network"] = jn;
j["addNetwork"] = addNetwork;
return j;
}
void MatchingNetwork::fromJSON(nlohmann::json j)
{
clearNetwork();
port = j.value("port", 1);
if(j.contains("network")) {
for(auto jc : j["network"]) {
if(!jc.contains("component")) {
continue;
}
auto c = MatchingComponent::createFromName(QString::fromStdString(jc["component"]));
if(!c) {
continue;
}
c->fromJSON(jc["params"]);
network.push_back(c);
}
}
addNetwork = j.value("addNetwork", true);
matching.clear();
}
void MatchingNetwork::clearNetwork()
{
while(network.size() > 0) {
auto c = network[0];
removeComponent(c);
delete c;
}
}
MatchingComponent *MatchingNetwork::componentAtPosition(int pos)
{
pos -= graph->layout()->itemAt(0)->geometry().width();
pos -= portWidth;
if(pos > 0 && pos <= (int) network.size() * componentWidth) {
// position is in port 1 network
return network[pos / componentWidth];
}
return nullptr;
}
unsigned int MatchingNetwork::findInsertPosition(int xcoord)
{
xcoord -= graph->layout()->itemAt(0)->geometry().width();
xcoord -= portWidth;
// 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)
{
auto index = findInsertPosition(pos);
QHBoxLayout *l = static_cast<QHBoxLayout*>(graph->layout());
l->insertWidget(index, c);
c->show();
// add component to correct matching network
index -= 2; // first two widgets are fixed
addComponent(index, c);
// network changed, need to recalculate matching
matching.clear();
connect(c, &MatchingComponent::valueChanged, [=](){
matching.clear();
});
}
void MatchingNetwork::addComponent(int index, MatchingComponent *c)
{
network.insert(network.begin() + index, c);
updateSCPINames();
if(graph) {
graph->update();
}
matching.clear();
// remove from list when the component deletes itself
connect(c, &MatchingComponent::deleted, [=](){
removeComponent(c);
});
}
void MatchingNetwork::removeComponent(int index)
{
network.erase(network.begin() + index);
matching.clear();
updateSCPINames();
if(graph) {
graph->update();
}
}
void MatchingNetwork::removeComponent(MatchingComponent *c)
{
network.erase(std::remove(network.begin(), network.end(), c), network.end());
matching.clear();
updateSCPINames();
if(graph) {
graph->update();
}
}
void MatchingNetwork::createDragComponent(MatchingComponent *c)
{
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
QByteArray encodedPointer;
QDataStream stream(&encodedPointer, QIODevice::WriteOnly);
stream << quintptr(c);
mimeData->setData("matchingComponent/pointer", encodedPointer);
drag->setMimeData(mimeData);
drag->exec(Qt::MoveAction);
}
void MatchingNetwork::updateInsertIndicator(int xcoord)
{
auto index = findInsertPosition(xcoord);
QHBoxLayout *l = static_cast<QHBoxLayout*>(graph->layout());
l->removeWidget(insertIndicator);
l->insertWidget(index, insertIndicator);
}
bool MatchingNetwork::eventFilter(QObject *object, QEvent *event)
{
if(object->objectName() == "Graph") {
if(event->type() == QEvent::MouseButtonPress) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
dragComponent = componentAtPosition(mouseEvent->pos().x());
if(dragComponent) {
dragStartPosition = mouseEvent->pos();
return true;
}
}
return false;
} else if(event->type() == QEvent::MouseMove) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (!(mouseEvent->buttons() & Qt::LeftButton)) {
return false;
}
if (!dragComponent) {
return false;
}
if ((mouseEvent->pos() - dragStartPosition).manhattanLength()
< QApplication::startDragDistance()) {
return false;
}
// remove and hide component while it is being dragged
graph->layout()->removeWidget(dragComponent);
dragComponent->hide();
removeComponent(dragComponent);
graph->update();
// network changed, need to recalculate matching
matching.clear();
createDragComponent(dragComponent);
return true;
} else if(event->type() == QEvent::DragEnter) {
auto dragEvent = static_cast<QDragEnterEvent*>(event);
if(dragEvent->mimeData()->hasFormat("matchingComponent/pointer")) {
dropPending = true;
auto data = dragEvent->mimeData()->data("matchingComponent/pointer");
QDataStream stream(&data, QIODevice::ReadOnly);
quintptr dropPtr;
stream >> dropPtr;
dropComponent = (MatchingComponent*) dropPtr;
dragEvent->acceptProposedAction();
insertIndicator = new QWidget();
insertIndicator->setMinimumSize(2, imageHeight);
insertIndicator->setMaximumSize(2, imageHeight);
insertIndicator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
insertIndicator->setStyleSheet("background-color:red;");
updateInsertIndicator(dragEvent->position().toPoint().x());
return true;
}
} else if(event->type() == QEvent::DragMove) {
auto dragEvent = static_cast<QDragMoveEvent*>(event);
updateInsertIndicator(dragEvent->position().toPoint().x());
return true;
} else if(event->type() == QEvent::Drop) {
auto dragEvent = static_cast<QDropEvent*>(event);
delete insertIndicator;
addComponentAtPosition(dragEvent->position().toPoint().x(), dropComponent);
return true;
} else if(event->type() == QEvent::DragLeave) {
dropPending = false;
dropComponent = nullptr;
delete insertIndicator;
}
} else {
// clicked/dragged one of the components outside of the graph
if(event->type() == QEvent::MouseButtonPress) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton) {
dragStartPosition = mouseEvent->pos();
if(object->objectName() == "lSeriesC") {
dragComponent = new MatchingComponent(MatchingComponent::Type::SeriesC);
} else if(object->objectName() == "lSeriesL") {
dragComponent = new MatchingComponent(MatchingComponent::Type::SeriesL);
} else if(object->objectName() == "lSeriesR") {
dragComponent = new MatchingComponent(MatchingComponent::Type::SeriesR);
} else if(object->objectName() == "lParallelC") {
dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelC);
} else if(object->objectName() == "lParallelL") {
dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelL);
} else if(object->objectName() == "lParallelR") {
dragComponent = new MatchingComponent(MatchingComponent::Type::ParallelR);
} else if(object->objectName() == "lDefinedThrough") {
dragComponent = new MatchingComponent(MatchingComponent::Type::DefinedThrough);
} else if(object->objectName() == "lDefinedShunt") {
dragComponent = new MatchingComponent(MatchingComponent::Type::DefinedShunt);
} else {
dragComponent = nullptr;
}
return true;
}
return false;
} else if(event->type() == QEvent::MouseMove) {
auto mouseEvent = static_cast<QMouseEvent*>(event);
if (!(mouseEvent->buttons() & Qt::LeftButton)) {
return false;
}
if (!dragComponent) {
return false;
}
if ((mouseEvent->pos() - dragStartPosition).manhattanLength()
< QApplication::startDragDistance()) {
return false;
}
createDragComponent(dragComponent);
return true;
}
}
return false;
}
void MatchingNetwork::updateSCPINames()
{
// Need to remove all components from the subnode list first, otherwise
// name changes wouldn't work due to temporarily name collisions
for(auto &c : network) {
remove(c);
}
unsigned int i=1;
for(auto &c : network) {
c->changeName(QString::number(i));
add(c);
i++;
}
}
MatchingComponent::MatchingComponent(Type type)
: SCPINode("COMPONENT")
{
this->type = type;
eValue = nullptr;
touchstone = nullptr;
touchstoneLabel = nullptr;
setMinimumSize(151, 151);
setMaximumSize(151, 151);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFocusPolicy(Qt::FocusPolicy::ClickFocus);
switch(type) {
case Type::SeriesR:
case Type::SeriesL:
case Type::SeriesC: {
eValue = new SIUnitEdit();
eValue->setPrecision(4);
eValue->setPrefixes("fpnum k");
connect(eValue, &SIUnitEdit::valueChanged, [=](double newval) {
value = newval;
emit valueChanged();
});
auto layout = new QVBoxLayout();
layout->addWidget(eValue);
setLayout(layout);
}
break;
case Type::ParallelR:
case Type::ParallelL:
case Type::ParallelC: {
eValue = new SIUnitEdit();
eValue->setPrecision(4);
eValue->setPrefixes("fpnum k");
connect(eValue, &SIUnitEdit::valueChanged, [=](double newval) {
value = newval;
emit valueChanged();
});
auto layout = new QVBoxLayout();
layout->addWidget(eValue);
layout->addStretch(1);
layout->setContentsMargins(9, 5, 9, 9);
setLayout(layout);
}
default:
break;
}
switch(type) {
case Type::SeriesR:
eValue->setUnit("Ω");
eValue->setValue(50);
setStyleSheet("image: url(:/icons/seriesR.png);");
break;
case Type::SeriesL:
eValue->setUnit("H");
eValue->setValue(1e-9);
setStyleSheet("image: url(:/icons/seriesL.png);");
break;
case Type::SeriesC:
eValue->setUnit("F");
eValue->setValue(1e-12);
setStyleSheet("image: url(:/icons/seriesC.png);");
break;
case Type::ParallelR:
eValue->setUnit("Ω");
eValue->setValue(50);
setStyleSheet("image: url(:/icons/parallelR.png);");
break;
case Type::ParallelL:
eValue->setUnit("H");
eValue->setValue(1e-9);
setStyleSheet("image: url(:/icons/parallelL.png);");
break;
case Type::ParallelC:
eValue->setUnit("F");
eValue->setValue(1e-12);
setStyleSheet("image: url(:/icons/parallelC.png);");
break;
case Type::DefinedThrough: {
touchstone = new Touchstone(2);
touchstoneLabel = new QLabel();
touchstoneLabel->setWordWrap(true);
touchstoneLabel->setAlignment(Qt::AlignCenter);
auto layout = new QVBoxLayout();
layout->addWidget(touchstoneLabel);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
setStyleSheet("image: url(:/icons/definedThrough.png);");
updateTouchstoneLabel();
}
break;
case Type::DefinedShunt: {
touchstone = new Touchstone(2);
touchstoneLabel = new QLabel();
touchstoneLabel->setWordWrap(true);
touchstoneLabel->setAlignment(Qt::AlignCenter);
auto layout = new QVBoxLayout();
layout->addWidget(touchstoneLabel);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
setStyleSheet("image: url(:/icons/definedShunt.png);");
updateTouchstoneLabel();
}
break;
default:
break;
}
switch(type) {
case Type::SeriesR:
case Type::SeriesL:
case Type::SeriesC:
case Type::ParallelR:
case Type::ParallelL:
case Type::ParallelC:
addDoubleParameter("VALue", value, true, true, [=](){
eValue->setValue(value);
});
break;
case Type::DefinedThrough:
case Type::DefinedShunt:
add(new SCPICommand("FILE", [=](QStringList params) -> QString {
if(params.size() < 1) {
return SCPI::getResultName(SCPI::Result::Error);
}
try {
*touchstone = Touchstone::fromFile(params[0].toStdString());
updateTouchstoneLabel();
emit valueChanged();
return SCPI::getResultName(SCPI::Result::Empty);
} catch(const std::exception& e) {
// failed to load file
return SCPI::getResultName(SCPI::Result::Error);
}
}, nullptr));
break;
default:
break;
}
}
MatchingComponent::~MatchingComponent()
{
delete eValue;
delete touchstone;
delete touchstoneLabel;
}
ABCDparam MatchingComponent::parameters(double freq)
{
switch(type) {
case Type::SeriesR:
return ABCDparam(1.0, eValue->value(), 0.0, 1.0);
case Type::SeriesL:
return ABCDparam(1.0, complex<double>(0, freq * 2 * M_PI * eValue->value()), 0.0, 1.0);
case Type::SeriesC:
return ABCDparam(1.0, complex<double>(0, -1.0 / (freq * 2 * M_PI * eValue->value())), 0.0, 1.0);
case Type::ParallelR:
return ABCDparam(1.0, 0.0, 1.0/eValue->value(), 1.0);
case Type::ParallelL:
return ABCDparam(1.0, 0.0, 1.0/complex<double>(0, freq * 2 * M_PI * eValue->value()), 1.0);
case Type::ParallelC:
return ABCDparam(1.0, 0.0, 1.0/complex<double>(0, -1.0 / (freq * 2 * M_PI * eValue->value())), 1.0);
case Type::DefinedThrough:
if(touchstone->points() == 0 || freq < touchstone->minFreq() || freq > touchstone->maxFreq()) {
// outside of provided frequency range, pass through unchanged
return ABCDparam(1.0, 0.0, 0.0, 1.0);
} else {
auto d = touchstone->interpolate(freq);
auto S = Sparam(d.S[0], d.S[1], d.S[2], d.S[3]);
return ABCDparam(S, touchstone->getReferenceImpedance());
}
case Type::DefinedShunt:
if(touchstone->points() == 0 || freq < touchstone->minFreq() || freq > touchstone->maxFreq()) {
// outside of provided frequency range, pass through unchanged
return ABCDparam(1.0, 0.0, 0.0, 1.0);
} else {
auto d = touchstone->interpolate(freq);
auto Y = Yparam(Sparam(d.S[0], d.S[1], d.S[2], d.S[3]), touchstone->getReferenceImpedance());
return ABCDparam(1.0, 0.0, Y.m11, 1.0);
}
default:
return ABCDparam(1.0, 0.0, 0.0, 1.0);
}
}
void MatchingComponent::MatchingComponent::setValue(double v)
{
value = v;
if(eValue) {
eValue->setValue(v);
}
}
MatchingComponent *MatchingComponent::createFromName(QString name)
{
for(unsigned int i=0;i<(int) Type::Last;i++) {
if(typeToName((Type) i).compare(name, Qt::CaseInsensitive) == 0) {
return new MatchingComponent((Type) i);
}
}
// invalid name
return nullptr;
}
QString MatchingComponent::getName()
{
return typeToName(type);
}
nlohmann::json MatchingComponent::toJSON()
{
nlohmann::json j;
switch(type) {
case Type::SeriesC:
case Type::SeriesR:
case Type::SeriesL:
case Type::ParallelC:
case Type::ParallelR:
case Type::ParallelL:
j["value"] = eValue->value();
break;
case Type::DefinedThrough:
case Type::DefinedShunt:
j["touchstone"] = touchstone->toJSON();
break;
case Type::Last:
break;
}
return j;
}
void MatchingComponent::fromJSON(nlohmann::json j)
{
switch(type) {
case Type::SeriesC:
case Type::SeriesR:
case Type::SeriesL:
case Type::ParallelC:
case Type::ParallelR:
case Type::ParallelL:
eValue->setValue(j.value("value", 1e-12));
break;
case Type::DefinedThrough:
case Type::DefinedShunt:
touchstone->fromJSON(j["touchstone"]);
updateTouchstoneLabel();
break;
case Type::Last:
break;
}
}
void MatchingComponent::mouseDoubleClickEvent(QMouseEvent *e)
{
Q_UNUSED(e);
if(type == Type::DefinedThrough || type == Type::DefinedShunt) {
// select new touchstone file
auto filename = QFileDialog::getOpenFileName(nullptr, "Open measurement file", "", "Touchstone files (*.s2p)", nullptr, QFileDialog::DontUseNativeDialog);
if (!filename.isEmpty()) {
try {
*touchstone = Touchstone::fromFile(filename.toStdString());
} catch(const std::exception& e) {
InformationBox::ShowError("Failed to load file", QString("Attempt to load file ended with error: \"") + e.what()+"\"");
}
updateTouchstoneLabel();
emit valueChanged();
}
}
}
void MatchingComponent::updateTouchstoneLabel()
{
if(!touchstone || !touchstoneLabel) {
return;
}
QFont font = touchstoneLabel->font();
font.setPointSize(10);
touchstoneLabel->setFont(font);
if(touchstone->points() == 0) {
touchstoneLabel->setText("No data. Double-click to select touchstone file");
} else {
QString text = QString::number(touchstone->points()) + " points from "+Unit::ToString(touchstone->minFreq(), "Hz", " kMG", 4)
+ " to "+Unit::ToString(touchstone->maxFreq(), "Hz", " kMG", 4);
touchstoneLabel->setText(text);
}
if(type == Type::DefinedThrough) {
touchstoneLabel->setAlignment(Qt::AlignCenter);
} else if(type == Type::DefinedShunt) {
touchstoneLabel->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
}
}
QString MatchingComponent::typeToName(MatchingComponent::Type type)
{
switch(type) {
case Type::SeriesR: return "SeriesR";
case Type::SeriesL: return "SeriesL";
case Type::SeriesC: return "SeriesC";
case Type::ParallelR: return "ParallelR";
case Type::ParallelL: return "ParallelL";
case Type::ParallelC: return "ParallelC";
case Type::DefinedThrough: return "Touchstone Through";
case Type::DefinedShunt: return "Touchstone Shunt";
default: return "";
}
}
void MatchingComponent::MatchingComponent::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Delete) {
emit deleted(this);
delete this;
}
}
void MatchingComponent::MatchingComponent::focusInEvent(QFocusEvent *event)
{
Q_UNUSED(event);
oldStylesheet = styleSheet();
setStyleSheet(styleSheet().append("\nborder: 1px solid red;"));
}
void MatchingComponent::MatchingComponent::focusOutEvent(QFocusEvent *event)
{
Q_UNUSED(event);
setStyleSheet(oldStylesheet);
}