matchdialog.cpp
-----------------
begin : Fri Jul 22 2005
copyright : (C) 2005 by Michael Margraf
email : michael.margraf@alumni.tu-berlin.de
copyright : (C) 2012, 2013, 2016 by Qucs Team (see AUTHORS file)
-----------------------------------------------------------------------------
Update (2017) : New impedance matching techniques: Single matching,
double stub matching, real to real broadband transformers,
cascaded L-sections and lambda/8 + lambda/4 matching
Andres Martinez-Mera <andresmartinezmera@gmail.com>
Claudio Girardi <claudio.girardi@virgilio.it>
------------------------------------------------------------------------------
***************************************************************************/
* *
* 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; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "../../qucs-filter/material_props.h"
#include "main.h"
#include "matchdialog.h"
#include "misc.h"
#include "qucs.h"
#include <QApplication>
#include <QClipboard>
#include <QComboBox>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QVBoxLayout>
MatchDialog::MatchDialog(QWidget *parent) : QDialog(parent) {
setWindowTitle(tr("Create Matching Circuit"));
DoubleVal = new QDoubleValidator(this);
DoubleVal->setLocale(QLocale::C);
all = new QHBoxLayout(this);
left side, is much the old matching tool whereas the other layout was
included specifically for microstrip synthesis.
*/
QVBoxLayout *matchFrame = new QVBoxLayout();
QVBoxLayout *micro_layout = new QVBoxLayout();
all->addLayout(matchFrame);
all->addLayout(micro_layout);
MethodBox = new QGroupBox(tr("Implementation"));
matchFrame->addWidget(MethodBox);
MethodLayout = new QVBoxLayout();
SubstrateBox = new QGroupBox(tr("Microstrip Substrate"));
QGridLayout *hsubs = new QGridLayout();
SubstrateBox->setVisible(false);
micro_layout->addWidget(SubstrateBox);
SubstrateBox->setLayout(hsubs);
RelPermLabel = new QLabel(tr("Relative Permitivity"));
RelPermCombo = new QComboBox();
RelPermCombo->setEditable(true);
const char **p = List_er;
while (*(++p))
RelPermCombo->addItem(*p);
RelPermCombo->lineEdit()->setText("9.8");
hsubs->addWidget(RelPermLabel, 0, 0);
hsubs->addWidget(RelPermCombo, 0, 1, 1, 2);
subsHLabel = new QLabel(tr("Substrate height"));
SubHeightEdit = new QLineEdit("1.0");
SubsHScale = new QLabel("mm");
hsubs->addWidget(subsHLabel, 1, 0);
hsubs->addWidget(SubHeightEdit, 1, 1);
hsubs->addWidget(SubsHScale, 1, 2);
thicknessLabel = new QLabel(tr("Metal thickness"));
thicknessEdit = new QLineEdit("12.5");
ThicknessScale = new QLabel("um");
hsubs->addWidget(thicknessLabel, 2, 0);
hsubs->addWidget(thicknessEdit, 2, 1);
hsubs->addWidget(ThicknessScale, 2, 2);
minWLabel = new QLabel(tr("Minimum width"));
minWEdit = new QLineEdit("0.4");
minWScale = new QLabel("mm");
hsubs->addWidget(minWLabel, 3, 0);
hsubs->addWidget(minWEdit, 3, 1);
hsubs->addWidget(minWScale, 3, 2);
maxWLabel = new QLabel(tr("Maximum width"));
maxWEdit = new QLineEdit("5.0");
maxWScale = new QLabel("mm");
hsubs->addWidget(maxWLabel, 4, 0);
hsubs->addWidget(maxWEdit, 4, 1);
hsubs->addWidget(maxWScale, 4, 2);
tanDLabel = new QLabel(tr("tanD"));
tanDEdit = new QLineEdit("0.0125");
hsubs->addWidget(tanDLabel, 5, 0);
hsubs->addWidget(tanDEdit, 5, 1);
ResistivityLabel = new QLabel(tr("Resistivity"));
ResistivityEdit = new QLineEdit("2.43902e-08");
hsubs->addWidget(ResistivityLabel, 6, 0);
hsubs->addWidget(ResistivityEdit, 6, 1);
QHBoxLayout *h4 = new QHBoxLayout();
h4->setSpacing(3);
TopoLabel = new QLabel(tr("Method"));
h4->addWidget(TopoLabel);
TopoCombo = new QComboBox();
TopoCombo->setFixedWidth(220);
TopoCombo->addItem(tr("L-section"));
TopoCombo->addItem(tr("Single stub"));
TopoCombo->addItem(tr("Double stub"));
QString str = tr("Multistage ") + QString(QChar(0xBB, 0x03)) + "/4";
TopoCombo->addItem(str);
TopoCombo->addItem("Cascaded L-sections");
str = QString(QChar(0xBB, 0x03)) + "/8 +" + QString(QChar(0xBB, 0x03)) +
"/4 transformer";
TopoCombo->addItem(str);
h4->addWidget(TopoCombo);
connect(TopoCombo, SIGNAL(activated(int)), SLOT(slotChangeMode_TopoCombo()));
h4->addStretch(5);
MethodLayout->addLayout(h4);
QHBoxLayout *h5 = new QHBoxLayout();
OpenRadioButton = new QRadioButton(tr("Open stub"), this);
h5->addWidget(OpenRadioButton);
OpenRadioButton->setChecked(true);
OpenRadioButton->setVisible(false);
ShortRadioButton = new QRadioButton(tr("Short circuit stub"), this);
h5->addWidget(ShortRadioButton);
ShortRadioButton->setChecked(false);
ShortRadioButton->setVisible(false);
MethodLayout->addLayout(h5);
QHBoxLayout *h6 = new QHBoxLayout();
OrderLabel = new QLabel(tr("Number of sections"));
OrderEdit = new QLineEdit("3");
h6->addWidget(OrderLabel);
h6->addWidget(OrderEdit);
OrderLabel->setVisible(false);
OrderEdit->setVisible(false);
OrderEdit->setFixedWidth(50);
OrderEdit->setAlignment(Qt::AlignLeft);
h6->setAlignment(Qt::AlignLeft);
QHBoxLayout *h7 = new QHBoxLayout();
Weighting_groupBox = new QGroupBox(tr("Weighting"));
QHBoxLayout *h7_box = new QHBoxLayout();
QVBoxLayout *v7_box = new QVBoxLayout();
BinRadio = new QRadioButton(tr("Binomial"), this);
ChebyRadio = new QRadioButton(tr("Chebyshev"), this);
BinRadio->setChecked(true);
h7_box->addWidget(BinRadio);
h7_box->addWidget(ChebyRadio);
QHBoxLayout *h8 = new QHBoxLayout();
maxRippleLabel = new QLabel(tr("Maximum ripple"));
h8->addWidget(maxRippleLabel);
MaxRippleEdit = new QLineEdit("0.05");
h8->addWidget(MaxRippleEdit);
MaxRippleEdit->setFixedWidth(50);
MaxRippleEdit->setAlignment(Qt::AlignLeft);
h8->setAlignment(Qt::AlignLeft);
QGridLayout *OptLayout = new QGridLayout();
v7_box->addLayout(h7_box);
v7_box->addLayout(h8);
Weighting_groupBox->setLayout(v7_box);
Weighting_groupBox->setVisible(false);
h7->addWidget(Weighting_groupBox);
MethodLayout->addLayout(h7);
MethodLayout->addLayout(h6);
MethodBox->setLayout(MethodLayout);
BalancedCheck = new QCheckBox(tr("Use balanced stubs"));
BalancedCheck->setEnabled(false);
TwoCheck = new QCheckBox(tr("Calculate two-port matching"));
TwoCheck->setChecked(true);
AddSPBlock =
new QCheckBox(tr("Add S-Parameter simulation"));
AddSPBlock->setChecked(false);
MicrostripCheck = new QCheckBox(tr("Synthesize microstrip lines"));
MicrostripCheck->setEnabled(false);
MicrostripCheck->setChecked(false);
OptLayout->addWidget(BalancedCheck, 0, 0);
OptLayout->addWidget(TwoCheck, 0, 1);
OptLayout->addWidget(AddSPBlock, 1, 0);
OptLayout->addWidget(MicrostripCheck, 1, 1);
matchFrame->addLayout(OptLayout);
connect(TwoCheck, SIGNAL(toggled(bool)), SLOT(slotSetTwoPort(bool)));
connect(MicrostripCheck, SIGNAL(toggled(bool)),
SLOT(slotSetMicrostripCheck()));
connect(ChebyRadio, SIGNAL(toggled(bool)), SLOT(slotChebyCheck()));
QGroupBox *ImpBox = new QGroupBox(tr("Reference Impedance"));
matchFrame->addWidget(ImpBox);
QHBoxLayout *ImpLayout = new QHBoxLayout();
Port1Label = new QLabel(tr("Port 1"));
Ref1Edit = new QLineEdit("50");
Ref1Edit->setMaximumWidth(75);
Ref1Edit->setValidator(DoubleVal);
Ohm1Label = new QLabel(QString(QChar(0xA9, 0x03)));
connect(Ref1Edit, SIGNAL(textChanged(const QString &)),
SLOT(slotImpedanceChanged(const QString &)));
Port2Label = new QLabel(tr("Port 2"));
Ref2Edit = new QLineEdit("50");
Ref2Edit->setMaximumWidth(75);
Ref2Edit->setValidator(DoubleVal);
Ohm2Label = new QLabel(QString(QChar(0xA9, 0x03)));
ImpLayout->addWidget(Port1Label);
ImpLayout->addWidget(Ref1Edit);
ImpLayout->addWidget(Ohm1Label);
ImpLayout->addSpacing(50);
ImpLayout->addWidget(Port2Label);
ImpLayout->addWidget(Ref2Edit);
ImpLayout->addWidget(Ohm2Label);
ImpBox->setLayout(ImpLayout);
QGroupBox *SParBox = new QGroupBox(tr("S Parameter"));
matchFrame->addWidget(SParBox);
QVBoxLayout *SParLayout = new QVBoxLayout();
SParBox->setLayout(SParLayout);
QHBoxLayout *h1 = new QHBoxLayout();
h1->setSpacing(3);
FormatLabel = new QLabel(tr("Input format"));
h1->addWidget(FormatLabel);
FormatCombo = new QComboBox();
h1->addWidget(FormatCombo);
FormatCombo->setFixedWidth(140);
FormatCombo->addItem(tr("Real/Imag"));
FormatCombo->addItem(tr("mag/deg"));
connect(FormatCombo, SIGNAL(activated(int)), SLOT(slotChangeMode(int)));
h1->addStretch(5);
SParLayout->addLayout(h1);
QHBoxLayout *h3 = new QHBoxLayout();
h3->setSpacing(3);
QVBoxLayout *VBox1 = new QVBoxLayout();
h3->addLayout(VBox1);
S11Label = new QLabel(tr("S11"));
S21Label = new QLabel(tr("S21"));
VBox1->addWidget(S11Label);
VBox1->addWidget(S21Label);
QVBoxLayout *VBox2 = new QVBoxLayout();
h3->addLayout(VBox2);
S11magEdit = new QLineEdit("0.5");
S11magEdit->setValidator(DoubleVal);
S11magEdit->setMaximumWidth(75);
S21magEdit = new QLineEdit("0.5");
S21magEdit->setValidator(DoubleVal);
S21magEdit->setMaximumWidth(75);
VBox2->addWidget(S11magEdit);
VBox2->addWidget(S21magEdit);
QVBoxLayout *VBox3 = new QVBoxLayout();
h3->addLayout(VBox3);
S11sLabel = new QLabel("+j");
S21sLabel = new QLabel("+j");
VBox3->addWidget(S11sLabel);
VBox3->addWidget(S21sLabel);
QVBoxLayout *VBox4 = new QVBoxLayout();
h3->addLayout(VBox4);
S11degEdit = new QLineEdit("0");
S11degEdit->setValidator(DoubleVal);
S11degEdit->setMaximumWidth(75);
S21degEdit = new QLineEdit("0");
S21degEdit->setValidator(DoubleVal);
S21degEdit->setMaximumWidth(75);
VBox4->addWidget(S11degEdit);
VBox4->addWidget(S21degEdit);
QVBoxLayout *VBox5 = new QVBoxLayout();
h3->addLayout(VBox5);
S11uLabel = new QLabel(" ");
S21uLabel = new QLabel(" ");
VBox5->addWidget(S11uLabel);
VBox5->addWidget(S21uLabel);
h3->addStretch(5);
QVBoxLayout *VBox6 = new QVBoxLayout();
h3->addLayout(VBox6);
S12Label = new QLabel(tr("S12"));
S22Label = new QLabel(tr("S22"));
VBox6->addWidget(S12Label);
VBox6->addWidget(S22Label);
QVBoxLayout *VBox7 = new QVBoxLayout();
h3->addLayout(VBox7);
S12magEdit = new QLineEdit("0");
S12magEdit->setValidator(DoubleVal);
S12magEdit->setMaximumWidth(75);
S22magEdit = new QLineEdit("0.5");
S22magEdit->setValidator(DoubleVal);
S22magEdit->setMaximumWidth(75);
VBox7->addWidget(S12magEdit);
VBox7->addWidget(S22magEdit);
QVBoxLayout *VBox8 = new QVBoxLayout();
h3->addLayout(VBox8);
S12sLabel = new QLabel("+j");
S22sLabel = new QLabel("+j");
VBox8->addWidget(S12sLabel);
VBox8->addWidget(S22sLabel);
QVBoxLayout *VBox9 = new QVBoxLayout();
h3->addLayout(VBox9);
S12degEdit = new QLineEdit("0");
S12degEdit->setMaximumWidth(75);
S12degEdit->setValidator(DoubleVal);
S22degEdit = new QLineEdit("0");
S22degEdit->setMaximumWidth(75);
S22degEdit->setValidator(DoubleVal);
VBox9->addWidget(S12degEdit);
VBox9->addWidget(S22degEdit);
QVBoxLayout *VBox0 = new QVBoxLayout();
h3->addLayout(VBox0);
S12uLabel = new QLabel(" ");
S22uLabel = new QLabel(" ");
VBox0->addWidget(S12uLabel);
VBox0->addWidget(S22uLabel);
SParLayout->addLayout(h3);
setTabOrder(S11magEdit, S11degEdit);
setTabOrder(S11degEdit, S12magEdit);
setTabOrder(S12magEdit, S12degEdit);
setTabOrder(S12degEdit, S21magEdit);
setTabOrder(S21magEdit, S21degEdit);
setTabOrder(S21degEdit, S22magEdit);
setTabOrder(S22magEdit, S22degEdit);
connect(S21magEdit, SIGNAL(textChanged(const QString &)),
SLOT(slotImpedanceChanged(const QString &)));
connect(S21degEdit, SIGNAL(textChanged(const QString &)),
SLOT(slotImpedanceChanged(const QString &)));
connect(S11magEdit, SIGNAL(textChanged(const QString &)),
SLOT(slotReflexionChanged(const QString &)));
connect(S11degEdit, SIGNAL(textChanged(const QString &)),
SLOT(slotReflexionChanged(const QString &)));
QHBoxLayout *h2 = new QHBoxLayout();
h2->setSpacing(3);
FrequencyLabel = new QLabel(tr("Frequency:"));
FrequencyEdit = new QLineEdit();
FrequencyEdit->setValidator(DoubleVal);
FrequencyEdit->setMaximumWidth(75);
h2->addWidget(FrequencyLabel);
h2->addWidget(FrequencyEdit);
UnitCombo = new QComboBox();
UnitCombo->addItem("Hz");
UnitCombo->addItem("kHz");
UnitCombo->addItem("MHz");
UnitCombo->addItem("GHz");
UnitCombo->setFixedWidth(100);
h2->addWidget(UnitCombo);
h2->addStretch(5);
SParLayout->addLayout(h2);
QHBoxLayout *h0 = new QHBoxLayout();
h0->setSpacing(5);
matchFrame->addLayout(h0);
h0->addStretch(5);
QPushButton *buttCreate = new QPushButton(tr("Create"));
QPushButton *buttCancel = new QPushButton(tr("Cancel"));
h0->addWidget(buttCreate);
h0->addWidget(buttCancel);
connect(buttCreate, SIGNAL(clicked()), SLOT(slotButtCreate()));
connect(buttCancel, SIGNAL(clicked()), SLOT(reject()));
slotReflexionChanged("");
setFrequency(1e9);
}
MatchDialog::~MatchDialog() {
delete all;
delete DoubleVal;
}
void MatchDialog::setFrequency(double Freq_) {
int Expo = int(log10(Freq_) / 3.0);
if (Expo < 0)
Expo = 0;
else if (Expo > 3)
Expo = 3;
UnitCombo->setCurrentIndex(Expo);
Freq_ /= pow(10.0, double(3 * Expo));
FrequencyEdit->setText(QString::number(Freq_));
}
void MatchDialog::slotSetMicrostripCheck() {
if (MicrostripCheck->isChecked()) {
SubstrateBox->setVisible(true);
resize(650, 100);
} else {
SubstrateBox->setVisible(false);
setMaximumSize(500, 100);
}
}
void MatchDialog::slotChebyCheck() {
if (ChebyRadio->isChecked()) {
MaxRippleEdit->setVisible(true);
maxRippleLabel->setVisible(true);
} else {
MaxRippleEdit->setVisible(false);
maxRippleLabel->setVisible(false);
}
}
void MatchDialog::set2PortWidgetsVisible(bool visible) {
S12magEdit->setVisible(visible);
S22magEdit->setVisible(visible);
S12degEdit->setVisible(visible);
S22degEdit->setVisible(visible);
S12Label->setVisible(visible);
S22Label->setVisible(visible);
S12sLabel->setVisible(visible);
S22sLabel->setVisible(visible);
S12degEdit->setVisible(visible);
S22degEdit->setVisible(visible);
S12uLabel->setVisible(visible);
S22uLabel->setVisible(visible);
Port2Label->setVisible(visible);
Ref2Edit->setVisible(visible);
Ohm2Label->setVisible(visible);
}
void MatchDialog::slotSetTwoPort(bool on) {
if (on) {
S11Label->setText(tr("S11"));
S21Label->setText(tr("S21"));
setS21LineEdits(tmpS21mag, tmpS21deg);
set2PortWidgetsVisible(true);
} else {
S11Label->setText(tr("Reflexion Coefficient"));
S21Label->setText(tr("Impedance (Ohms)"));
set2PortWidgetsVisible(false);
tmpS21mag = S21magEdit->text().toDouble();
tmpS21deg = S21degEdit->text().toDouble();
slotReflexionChanged("");
}
}
void MatchDialog::slotChangeMode_TopoCombo() {
if ((TopoCombo->currentIndex() == 1) ||
(TopoCombo->currentIndex() == 2))
{
ShortRadioButton->setVisible(true);
OpenRadioButton->setVisible(true);
OpenRadioButton->setChecked(true);
BalancedCheck->setEnabled(true);
} else {
ShortRadioButton->setVisible(false);
OpenRadioButton->setVisible(false);
BalancedCheck->setEnabled(false);
}
if ((TopoCombo->currentIndex() != 0) &&
(TopoCombo->currentIndex() != 4))
{
MicrostripCheck->setEnabled(true);
} else {
MicrostripCheck->setEnabled(false);
}
if (TopoCombo->currentIndex() == 3)
Weighting_groupBox->setVisible(true);
else
Weighting_groupBox->setVisible(false);
if ((TopoCombo->currentIndex() == 4) ||
(TopoCombo->currentIndex() == 3))
{
OrderLabel->setVisible(true);
OrderEdit->setVisible(true);
} else {
OrderLabel->setVisible(false);
OrderEdit->setVisible(false);
}
}
void MatchDialog::slotChangeMode(int Index) {
if (Index) {
S11sLabel->setText("/");
S12sLabel->setText("/");
S21sLabel->setText("/");
S22sLabel->setText("/");
S11uLabel->setText(QString::fromUtf8("°"));
S12uLabel->setText(QString::fromUtf8("°"));
S21uLabel->setText(QString::fromUtf8("°"));
S22uLabel->setText(QString::fromUtf8("°"));
double Real = S11magEdit->text().toDouble();
double Imag = S11degEdit->text().toDouble();
c2p(Real, Imag);
setS11LineEdits(Real, Imag);
Real = S12magEdit->text().toDouble();
Imag = S12degEdit->text().toDouble();
c2p(Real, Imag);
setS12LineEdits(Real, Imag);
Real = S21magEdit->text().toDouble();
Imag = S21degEdit->text().toDouble();
c2p(Real, Imag);
setS21LineEdits(Real, Imag);
c2p(tmpS21mag, tmpS21deg);
Real = S22magEdit->text().toDouble();
Imag = S22degEdit->text().toDouble();
c2p(Real, Imag);
setS22LineEdits(Real, Imag);
} else {
S11sLabel->setText("+j");
S12sLabel->setText("+j");
S21sLabel->setText("+j");
S22sLabel->setText("+j");
S11uLabel->setText(" ");
S12uLabel->setText(" ");
S21uLabel->setText(" ");
S22uLabel->setText(" ");
double Mag = S11magEdit->text().toDouble();
double Phase = S11degEdit->text().toDouble();
p2c(Mag, Phase);
setS11LineEdits(Mag, Phase);
Mag = S12magEdit->text().toDouble();
Phase = S12degEdit->text().toDouble();
p2c(Mag, Phase);
setS12LineEdits(Mag, Phase);
Mag = S21magEdit->text().toDouble();
Phase = S21degEdit->text().toDouble();
p2c(Mag, Phase);
setS21LineEdits(Mag, Phase);
p2c(tmpS21mag, tmpS21deg);
Mag = S22magEdit->text().toDouble();
Phase = S22degEdit->text().toDouble();
p2c(Mag, Phase);
setS22LineEdits(Mag, Phase);
}
}
void MatchDialog::slotImpedanceChanged(const QString &) {
if (TwoCheck->isChecked())
return;
double Z0 = Ref1Edit->text().toDouble();
double Real = S21magEdit->text().toDouble();
double Imag = S21degEdit->text().toDouble();
if (FormatCombo->currentIndex()) {
p2c(Real, Imag);
z2r(Real, Imag, Z0);
c2p(Real, Imag);
} else {
z2r(Real, Imag, Z0);
}
setS11LineEdits(Real, Imag);
}
void MatchDialog::slotReflexionChanged(const QString &) {
if (TwoCheck->isChecked())
return;
double Z0 = Ref1Edit->text().toDouble();
double Real = S11magEdit->text().toDouble();
double Imag = S11degEdit->text().toDouble();
if (FormatCombo->currentIndex()) {
p2c(Real, Imag);
r2z(Real, Imag, Z0);
c2p(Real, Imag);
} else {
r2z(Real, Imag, Z0);
}
setS21LineEdits(Real, Imag);
}
void MatchDialog::setS11LineEdits(double Real, double Imag) {
S11magEdit->blockSignals(true);
S11magEdit->setText(QString::number(Real));
S11magEdit->blockSignals(false);
S11degEdit->blockSignals(true);
S11degEdit->setText(QString::number(Imag));
S11degEdit->blockSignals(false);
}
void MatchDialog::setS12LineEdits(double Real, double Imag) {
S12magEdit->setText(QString::number(Real));
S12degEdit->setText(QString::number(Imag));
}
void MatchDialog::setS21LineEdits(double Real, double Imag) {
S21magEdit->blockSignals(true);
S21magEdit->setText(QString::number(Real));
S21magEdit->blockSignals(false);
S21degEdit->blockSignals(true);
S21degEdit->setText(QString::number(Imag));
S21degEdit->blockSignals(false);
}
void MatchDialog::setS22LineEdits(double Real, double Imag) {
S22magEdit->setText(QString::number(Real));
S22degEdit->setText(QString::number(Imag));
}
void MatchDialog::slotButtCreate() {
double Z1 = Ref1Edit->text().toDouble();
double Z2 = Ref2Edit->text().toDouble();
double Freq = FrequencyEdit->text().toDouble() *
pow(10.0, 3.0 * UnitCombo->currentIndex());
double S11real = S11magEdit->text().toDouble();
double S11imag = S11degEdit->text().toDouble();
double S12real = S12magEdit->text().toDouble();
double S12imag = S12degEdit->text().toDouble();
double S21real = S21magEdit->text().toDouble();
double S21imag = S21degEdit->text().toDouble();
double S22real = S22magEdit->text().toDouble();
double S22imag = S22degEdit->text().toDouble();
if (FormatCombo->currentIndex()) {
p2c(S11real, S11imag);
p2c(S12real, S12imag);
p2c(S21real, S21imag);
p2c(S22real, S22imag);
}
bool BalancedStubs = BalancedCheck->isChecked();
bool micro_syn = MicrostripCheck->isChecked();
bool SP_block = AddSPBlock->isChecked();
bool open_short =
OpenRadioButton
->isChecked();
int order = OrderEdit->text().toInt() +
1;
bool success = true;
double gamma_MAX =
MaxRippleEdit->text()
.toDouble();
tSubstrate Substrate;
if (micro_syn)
{
Substrate.er = RelPermCombo->currentText().section(" ", 0, 0).toDouble();
Substrate.height = SubHeightEdit->text().toDouble() / 1e3;
Substrate.thickness = thicknessEdit->text().toDouble() / 1e6;
Substrate.tand = tanDEdit->text().toDouble();
Substrate.resistivity = ResistivityEdit->text().toDouble();
Substrate.roughness = 0.0;
Substrate.minWidth = minWEdit->text().toDouble() / 1e3;
Substrate.maxWidth = maxWEdit->text().toDouble() / 1e3;
}
if (TwoCheck->isChecked()) {
double DetReal = S11real * S22real - S11imag * S22imag - S12real * S21real +
S12imag * S21imag;
double DetImag = S11real * S22imag + S11imag * S22real - S12real * S21imag -
S12imag * S21real;
std::complex<double> s11 (S11real, S11imag);
std::complex<double> s12 (S12real, S12imag);
std::complex<double> s21 (S21real, S21imag);
std::complex<double> s22 (S22real, S22imag);
double delta = abs(s11*s22 - s12*s21);
double K = (1 - abs(s11)*abs(s11) - abs(s22)*abs(s22) + delta*delta) / (2*abs(s12*s21));
if ((K > 1) && (delta < 1)){
success =
calc2PortMatch(S11real, S11imag, S22real, S22imag, DetReal, DetImag, Z1,
Z2, Freq, micro_syn, SP_block, open_short, Substrate,
order, gamma_MAX, BalancedStubs);
}else{
success = false;
QMessageBox::critical(
0, tr("Error"),
tr("The device is not unconditionally stable:\n\nK = %1\n|%2| = %3\n\nIt is not possible to synthesize a matching network.\n\nConsider adding resistive losses and/or feedback to reach unconditional stability (K > 1 and |%2| < 1)")
.arg(QString::number(K, 'f', 2)).arg(QChar(0x0394)).arg(QString::number(delta, 'f', 2)));
}
} else {
success = calcMatchingCircuit(S11real, S11imag, Z1, Freq, micro_syn,
SP_block, open_short, Substrate, order,
gamma_MAX, BalancedStubs);
}
if (!success) {
return;
}
QucsMain->slotEditPaste(success);
accept();
}
void MatchDialog::c2p(double &Real, double &Imag) {
double Real_ = Real;
Real = sqrt(Real * Real + Imag * Imag);
Imag = 180.0 / pi * atan2(Imag, Real_);
}
void MatchDialog::p2c(double &Real, double &Imag) {
double Real_ = Real;
Real = Real_ * cos(Imag * pi / 180.0);
Imag = Real_ * sin(Imag * pi / 180.0);
}
void MatchDialog::r2z(double &Real, double &Imag, double Z0) {
double tmp = Z0 / ((1.0 - Real) * (1.0 - Real) + Imag * Imag);
Real = (1.0 - Real * Real - Imag * Imag) * tmp;
Imag *= 2.0 * tmp;
}
void MatchDialog::z2r(double &Real, double &Imag, double Z0) {
double tmp = (Real + Z0) * (Real + Z0) + Imag * Imag;
Real = (Real * Real + Imag * Imag - Z0 * Z0) / tmp;
Imag *= 2.0 * Z0 / tmp;
}
QString MatchDialog::calcMatchingLC(double r_real, double r_imag, double Z0,
double Freq) {
double Zreal = r_real, Zimag = r_imag;
r2z(Zreal, Zimag, Z0);
if (Zreal < 0.0) {
if (Zreal < -1e-13) {
QMessageBox::critical(
0, tr("Error"),
tr("Real part of impedance must be greater zero,\nbut is %1 !")
.arg(Zreal));
return QString();
}
Zreal = 0.0;
}
double X1, X2, Omega = 2.0 * pi * Freq;
QString Str;
if (r_real < 0) {
Str = "sp";
X1 = sqrt(Zreal * (Z0 - Zreal));
if (Zimag < 0.0)
X1 *= -1.0;
X1 -= Zimag;
X2 = (Zimag + X1) / (Zreal * Zreal + (Zimag + X1) * (Zimag + X1));
} else {
Str = "ps";
X1 = Zreal + Zimag * Zimag / Zreal - Z0;
X1 = sqrt(Z0 * X1);
if (Zimag > 0.0)
X1 *= -1.0;
X2 = Zimag / (Zreal * Zreal + Zimag * Zimag) + X1 / (Z0 * Z0 + X1 * X1);
}
QString laddercode = "", series_element, shunt_element;
if (X1 < 0.0)
series_element = QStringLiteral("CS:%1;").arg(-1.0 / Omega / X1);
else
series_element = QStringLiteral("LS:%1;").arg(X1 / Omega);
if (X2 < 0.0)
shunt_element = QStringLiteral("LP:%1;").arg(-1.0 / Omega / X2);
else
shunt_element = QStringLiteral("CP:%1;").arg(X2 / Omega);
(r_real < 0) ? laddercode = shunt_element + series_element
: laddercode = series_element + shunt_element;
return laddercode;
}
bool MatchDialog::calcMatchingCircuit(double S11real, double S11imag, double Z0,
double Freq, bool micro_syn,
bool SP_Block, bool open_short,
tSubstrate Substrate, int order,
double gamma_MAX, bool BalancedStubs) {
QString laddercode;
switch (TopoCombo->currentIndex()) {
case 0:
laddercode = calcMatchingLC(S11real, S11imag, Z0,
Freq);
break;
case 1:
laddercode =
calcSingleStub(S11real, S11imag, Z0, Freq, open_short, BalancedStubs);
break;
case 2:
laddercode =
calcDoubleStub(S11real, S11imag, Z0, Freq, open_short, BalancedStubs);
break;
case 3:
(BinRadio->isChecked())
? laddercode = calcBinomialLines(S11real, S11imag, Z0, order, Freq)
: laddercode =
calcChebyLines(S11real, S11imag, Z0, gamma_MAX, order, Freq);
break;
case 4:
laddercode =
calcMatchingCascadedLCSections(S11real, S11imag, Z0, Freq, order - 1);
break;
case 5:
laddercode = calcMatchingLambda8Lambda4(S11real, S11imag, Z0, Freq);
break;
}
if (laddercode.isEmpty())
return false;
double RL = S11real, XL = S11imag;
QString wirestr = "";
QString componentstr = "";
QString paintingstr = "";
int x_pos = 0;
r2z(RL, XL, Z0);
if (SP_Block) {
laddercode.append("S2P:Freq;");
laddercode.prepend(QStringLiteral("P1:%1;").arg(Z0));
laddercode.append(QStringLiteral("ZL:%1#%2;").arg(RL).arg(XL));
} else
{
laddercode.prepend("LBL:Port 1;");
laddercode.append("LBL:Port 2;");
}
SchematicParser(laddercode, x_pos, Freq, Substrate, micro_syn);
return true;
}
QString MatchDialog::calcBiMatch(double S11real, double S11imag, double S22real,
double S22imag, double DetReal, double DetImag,
double Z0, double Freq, bool open_short,
double gamma_MAX, int order,
bool BalancedStubs) {
double B = 1.0 + S11real * S11real + S11imag * S11imag - S22real * S22real -
S22imag * S22imag - DetReal * DetReal - DetImag * DetImag;
double Creal = S11real - S22real * DetReal - S22imag * DetImag;
double Cimag = S22real * DetImag - S11imag - S22imag * DetReal;
double Cmag = 2.0 * (Creal * Creal + Cimag * Cimag);
Creal /= Cmag;
Cimag /= Cmag;
double Rreal = B * B - 2.0 * Cmag;
double Rimag;
if (Rreal < 0.0) {
Rimag = Cimag * B - Creal * sqrt(-Rreal);
Rreal = Creal * B + Cimag * sqrt(-Rreal);
} else {
Rreal = B - sqrt(Rreal);
Rimag = Cimag * Rreal;
Rreal *= Creal;
}
QString laddercode;
switch (TopoCombo->currentIndex())
{
case 0:
laddercode = calcMatchingLC(Rreal, -Rimag, Z0, Freq);
break;
case 1:
laddercode =
calcSingleStub(Rreal, -Rimag, Z0, Freq, open_short, BalancedStubs);
break;
case 2:
laddercode =
calcDoubleStub(Rreal, -Rimag, Z0, Freq, open_short, BalancedStubs);
break;
case 3:
(BinRadio->isChecked())
? laddercode = calcBinomialLines(Rreal, -Rimag, Z0, order, Freq)
: laddercode =
calcChebyLines(Rreal, -Rimag, Z0, gamma_MAX, order, Freq);
break;
case 4:
laddercode = calcMatchingCascadedLCSections(Rreal, -Rimag, Z0, Freq, order);
break;
case 5:
laddercode = calcMatchingLambda8Lambda4(Rreal, -Rimag, Z0, Freq);
break;
}
return laddercode;
}
bool MatchDialog::calc2PortMatch(double S11real, double S11imag, double S22real,
double S22imag, double DetReal, double DetImag,
double Z1, double Z2, double Freq,
bool microsyn, bool SP_Block, bool open_short,
tSubstrate Substrate, int order,
double gamma_MAX, bool BalancedStubs) {
QString InputLadderCode =
calcBiMatch(S11real, S11imag, S22real, S22imag, DetReal, DetImag, Z1,
Freq, open_short, gamma_MAX, order, BalancedStubs);
if (InputLadderCode.isEmpty())
return false;
QString OutputLadderCode =
calcBiMatch(S22real, S22imag, S11real, S11imag, DetReal, DetImag, Z2,
Freq, open_short, gamma_MAX, order, BalancedStubs);
if (OutputLadderCode.isEmpty())
return false;
else
OutputLadderCode = flipLadderCode(OutputLadderCode);
if (SP_Block) {
InputLadderCode.prepend(QStringLiteral("S2P:%1;").arg(
Freq));
InputLadderCode.prepend(QStringLiteral("P1:%1;").arg(Z1));
OutputLadderCode.append(QStringLiteral("P2:%1;").arg(Z2));
} else {
InputLadderCode.prepend(QStringLiteral("LBL:Port 1;"));
OutputLadderCode.append(QStringLiteral("LBL:Port 2;"));
}
QString laddercode = InputLadderCode + QStringLiteral("DEV:0") + OutputLadderCode;
int x_pos = 0;
SchematicParser(laddercode, x_pos, Freq, Substrate, microsyn);
return true;
}
QString MatchDialog::flipLadderCode(QString laddercode) {
QStringList strlist = laddercode.split(";"), auxlist;
std::reverse(strlist.begin(), strlist.end());
QString flipped_laddercode = "";
for (int i = 0; i < strlist.length(); i++) {
flipped_laddercode += strlist.at(i) + ";";
}
return flipped_laddercode;
}
#define MAX_ERROR 1e-7
void calcMicrostrip(tSubstrate *substrate, double width, double freq,
double &er_eff, double &zl) {
double a, b;
double h = substrate->height;
double t = substrate->thickness;
double er = substrate->er;
double Wh = width / h;
t /= h;
double w1 = Wh;
if (t > 1e-100) {
a = coth(sqrt(6.517 * Wh));
b = t / pi * log(1.0 + 10.873127 / t / a / a);
w1 += b;
Wh += 0.5 * b * (1.0 + sech(sqrt(er - 1.0)));
}
a = Wh * Wh;
b = a * a;
er_eff = -0.564 * pow((er - 0.9) / (er + 3.0), 0.053);
er_eff *= 1.0 + log((b + a / 2704.0) / (b + 0.432)) / 49.0 +
log(1.0 + a * Wh / 5929.741) / 18.7;
er_eff = (er + 1.0) / 2.0 + (er - 1.0) / 2.0 * pow(1.0 + 10.0 / Wh, er_eff);
zl = 6.0 + 0.2831853 * exp(-pow(30.666 / Wh, 0.7528));
zl = Z_FIELD / 2.0 / pi * log(zl / Wh + sqrt(1.0 + 4.0 / Wh / Wh));
a = 6.0 + 0.2831853 * exp(-pow(30.666 / w1, 0.7528));
a = Z_FIELD / 2.0 / pi * log(a / w1 + sqrt(1.0 + 4.0 / w1 / w1));
a /= zl;
zl /= sqrt(er_eff);
er_eff *= a * a;
freq *= h / 1e6;
a = 0.0363 * exp(-4.6 * Wh) * (1.0 - exp(-pow(freq / 38.7, 4.97)));
a *= 1.0 + 2.751 * (1.0 - exp(-pow(er / 15.916, 8.0)));
a = pow((0.1844 + a) * freq, 1.5763);
a *= 0.27488 + Wh * (0.6315 + 0.525 / pow(1.0 + 0.0157 * freq, 20.0)) -
0.065683 * exp(-8.7513 * Wh);
a *= 0.33622 * (1.0 - exp(-0.03442 * er));
double er_freq = er - (er - er_eff) / (1.0 + a);
a = -0.03891 * pow(er, 1.4);
b = -0.267 * pow(Wh, 7.0);
double R7 = 1.206 - 0.3144 * exp(a) * (1.0 - exp(b));
a = 0.016 + pow(0.0514 * er, 4.524);
b = pow(freq / 28.843, 12.0);
a = 5.086 * a * b / (0.3838 + 0.386 * a) / (1.0 + 1.2992 * b);
b = -22.2 * pow(Wh, 1.92);
a *= exp(b);
b = pow(er - 1.0, 6.0);
double R9 = a * b / (1.0 + 10.0 * b);
a = 4.766 * exp(-3.228 * pow(Wh, 0.641));
a = 1.0 + 1.275 * (1.0 - exp(-0.004625 * a * pow(er, 1.674) *
pow(freq / 18.365, 2.745)));
b = 0.9408 * pow(er_freq, a) - 0.9603;
b /= (0.9408 - R9) * pow(er_eff, a) - 0.9603;
R9 = b;
a = 0.00044 * pow(er, 2.136) + 0.0184;
a *= 0.707 * pow(freq / 12.3, 1.097);
a = exp(-0.026 * pow(freq, 1.15656) - a);
b = pow(freq / 19.47, 6.0);
b /= 1.0 + 0.0962 * b;
b = 1.0 + 0.0503 * er * er * b * (1.0 - exp(-pow(Wh / 15, 6.0)));
R7 *= (1.0 - 1.1241 * a / b / (1.0 + 0.00245 * Wh * Wh));
zl *= pow(R9, R7);
er_eff = er_freq;
}
void MatchDialog::getMicrostrip(double Z0, double freq, tSubstrate *substrate,
double &width, double &er_eff) {
int iteration = 0;
double Z0_current, Z0_result, increment;
width = 1e-3;
do {
calcMicrostrip(substrate, width, freq, er_eff, Z0_current);
if (fabs(Z0 - Z0_current) < MAX_ERROR)
break;
increment = width / 100.0;
width += increment;
calcMicrostrip(substrate, width, freq, er_eff, Z0_result);
width -= (Z0_current - Z0) / (Z0_result - Z0_current) * increment;
if (width <= 0.0)
width = increment;
iteration++;
} while (iteration < 150);
}
QString MatchDialog::calcSingleStub(double r_real, double r_imag, double Z0,
double Freq, bool open_short,
bool BalancedStubs) {
double t = 0, t1 = 0, t2 = 0;
double dl, dl1, dl2, B;
double B1, B2, d, lstub, ll;
double lambda = SPEED_OF_LIGHT / (Freq);
double RL = r_real, XL = r_imag;
r2z(RL, XL, Z0);
if (RL == Z0) {
t = -XL / (2 * Z0);
(t < 0) ? dl = (pi + atan(t)) / (2 * pi) : dl = (atan(t)) / (2 * pi);
B = (RL * RL * t - (Z0 - XL * t) * (Z0 * t + XL)) /
(Z0 * (RL * RL + (Z0 * t + XL) * (Z0 * t + XL)));
} else {
t1 = (XL + sqrt(((RL / Z0) * fabs((Z0 - RL) * (Z0 - RL) + XL * XL)))) /
(RL - Z0);
(t1 < 0) ? dl1 = (pi + atan(t1)) / (2 * pi) : dl1 = (atan(t1)) / (2 * pi);
B1 = (RL * RL * t1 - (Z0 - XL * t1) * (Z0 * t1 + XL)) /
(Z0 * (RL * RL + (Z0 * t1 + XL) * (Z0 * t1 + XL)));
t2 = (XL - sqrt((RL * fabs((Z0 - RL) * (Z0 - RL) + XL * XL)) / (Z0))) /
(RL - Z0);
(t2 < 0) ? dl2 = (pi + atan(t2)) / (2 * pi) : dl2 = (atan(t2)) / (2 * pi);
B2 = (RL * RL * t2 - (Z0 - XL * t2) * (Z0 * t2 + XL)) /
(Z0 * (RL * RL + (Z0 * t2 + XL) * (Z0 * t2 + XL)));
}
if (t != 0) {
d = dl * lambda;
(open_short) ? ll = -(atan(B * Z0)) / (2 * pi)
: ll = (atan(1. / (B * Z0))) / (2 * pi);
if ((open_short) && (ll < 0))
ll += 0.5;
if ((!open_short) && (ll > 0.5))
ll -= 0.5;
lstub = ll * lambda;
}
if (t1 != 0) {
d = dl1 * lambda;
(open_short) ? ll = -(atan(B1 * Z0)) / (2 * pi)
: ll = (atan(1. / (1. * B1 * Z0))) / (2 * pi);
if ((open_short) && (ll < 0))
ll += 0.5;
if ((!open_short) && (ll > 0.5))
ll -= 0.5;
lstub = ll * lambda;
} else {
if (t2 != 0) {
d = dl2 * lambda;
(open_short) ? ll = -(atan(B2 * Z0)) / (2 * pi)
: ll = (atan(1. / (1. * B2 * Z0))) / (2 * pi);
if ((open_short) && (ll < 0))
ll += 0.5;
if ((!open_short) && (ll > 0.5))
ll -= 0.5;
lstub = ll * lambda;
}
}
if (BalancedStubs) {
double K;
(open_short) ? K = 0.5 : K = 2;
lstub = (lambda / (2 * pi)) * atan(K * tan((2 * pi * lstub) / lambda));
if (lstub < 0)
lstub += 0.5 * lambda;
}
QString laddercode;
if ((open_short) && (!BalancedStubs))
laddercode = QStringLiteral("OL:%1#%2;TL:%1#%3;")
.arg(Z0)
.arg(lstub)
.arg(d);
if ((open_short) && (BalancedStubs))
laddercode = QStringLiteral("OU:%1#%2;OL:%1#%2;TL:%1#%3;")
.arg(Z0)
.arg(lstub)
.arg(d);
if ((!open_short) && (!BalancedStubs))
laddercode = QStringLiteral("SL:%1#%2;TL:%1#%3;")
.arg(Z0)
.arg(lstub)
.arg(d);
if ((!open_short) && (BalancedStubs))
laddercode = QStringLiteral("SU:%1#%2;SL:%1#%2;TL:%1#%3;")
.arg(Z0)
.arg(lstub)
.arg(d);
return laddercode;
}
QString MatchDialog::calcDoubleStub(double r_real, double r_imag, double Z0,
double Freq, bool open_short,
bool BalancedStubs) {
double RL = r_real, XL = r_imag;
r2z(RL, XL, Z0);
double Y0 = 1. / Z0;
double GL = (1 / ((RL * RL) + (XL * XL))) * RL;
double BL = -(1 / ((RL * RL) + (XL * XL))) * XL;
double lambda = SPEED_OF_LIGHT / Freq;
double beta = (2 * pi) / lambda;
double d = lambda / 8;
double t = tan(beta * d);
double ll1, ll2;
if (GL > Y0 * ((1 + t * t) / (2 * t * t)))
{
QMessageBox::warning(0, tr("Error"),
tr("It is not possible to match this load using the double stub method"));
return QString();
}
double B11 = -BL + (Y0 + sqrt((1 + t * t) * GL * Y0 - GL * GL * t * t)) /
(t);
double B21 =
((Y0 * sqrt((1 + t * t) * GL * Y0 - GL * GL * t * t)) + GL * Y0) /
(GL * t);
(open_short) ? ll1 = (atan(B11 * Z0)) / (2 * pi)
: ll1 = -(atan(1. / (1. * B11 * Z0))) / (2 * pi);
(open_short) ? ll2 = (atan(B21 * Z0)) / (2 * pi)
: ll2 = -(atan(1. / (1. * B21 * Z0))) / (2 * pi);
if (ll1 < 0)
ll1 += 0.5;
if (ll2 < 0)
ll2 += 0.5;
if ((!open_short) && (ll1 > 0.5))
ll1 -= 0.5;
if ((!open_short) && (ll2 > 0.5))
ll2 -= 0.5;
double lstub1 = ll1 * lambda, lstub2 = ll2 * lambda;
if (BalancedStubs) {
double K;
(open_short) ? K = 0.5 : K = 2;
lstub1 = (lambda / (2 * pi)) * atan(K * tan((2 * pi * lstub1) / lambda));
lstub2 = (lambda / (2 * pi)) * atan(K * tan((2 * pi * lstub2) / lambda));
if (lstub1 < 0)
lstub1 += 0.5 * lambda;
if (lstub2 < 0)
lstub2 += 0.5 * lambda;
}
QString laddercode;
if ((open_short) && (BalancedStubs))
laddercode = QStringLiteral("OU:%1#%2;OL:%1#%2;TL:%1#%3;OU:%1#%4;OL:%1#%4;")
.arg(Z0)
.arg(lstub2)
.arg(d)
.arg(lstub1);
if ((open_short) && (!BalancedStubs))
laddercode = QStringLiteral("OL:%1#%2;TL:%1#%3;OL:%1#%4;")
.arg(Z0)
.arg(lstub2)
.arg(d)
.arg(lstub1);
if ((!open_short) && (BalancedStubs))
laddercode = QStringLiteral("SU:%1#%2;SL:%1#%2;TL:%1#%3;SU:%1#%4;SL:%1#%4;")
.arg(Z0)
.arg(lstub2)
.arg(d)
.arg(lstub1);
if ((!open_short) && (!BalancedStubs))
laddercode = QStringLiteral("SL:%1#%2;TL:%1#%3;SL:%1#%4;")
.arg(Z0)
.arg(lstub2)
.arg(d)
.arg(lstub1);
return laddercode;
}
int BinomialCoeffs(int n, int k) {
double coeff = 1;
for (int i = 1; i <= k; i++) {
coeff *= (n + (1 - i)) / (1.0 * i);
}
return (int)coeff;
}
QString MatchDialog::calcBinomialLines(double r_real, double r_imag, double Z0,
int order, double Freq) {
double RL = r_real, XL = r_imag;
r2z(RL, XL, Z0);
if (RL == 0) {
QMessageBox::warning(
0, QObject::tr("Error"),
QObject::tr("The load has not resistive part. It cannot be matched "
"using the quarter wavelength method"));
return NULL;
}
if (XL != 0) {
QMessageBox::warning(0, QObject::tr("Warning"),
QObject::tr("Reactive loads cannot be matched. Only "
"the real part will be matched"));
}
double l4 = SPEED_OF_LIGHT / (4. * Freq);
double Ci, Zi, Zaux = Z0;
QString laddercode;
for (int i = 1; i < order; i++) {
Ci = BinomialCoeffs(order - 1, i - 1);
Zi = exp(log(Zaux) + (Ci / pow(2, order - 1)) * log(RL / Z0));
Zaux = Zi;
laddercode += QStringLiteral("TL:%1#%2;").arg(Zi).arg(l4);
}
return laddercode;
}
QString MatchDialog::calcChebyLines(double r_real, double r_imag, double Z0,
double gamma, int order, double Freq) {
const int N = order - 1;
if (N > 7)
{
QMessageBox::warning(
0, QObject::tr("Error"),
QObject::tr("Chebyshev weighting for N>7 is not available"));
return QString();
}
QString laddercode;
double RL = r_real, XL = r_imag;
r2z(RL, XL, Z0);
double sec_theta_m = 0.0;
double log_ratio = log(RL / Z0) / (2 * gamma);
if (fabs(log_ratio) < 1) {
sec_theta_m = 0.0;
} else {
sec_theta_m = cosh((1.0 / N) * acosh(fabs(log_ratio)));
}
std::vector<double> w(N,0.0);
switch (N)
{
case 1:
w[0] = sec_theta_m;
break;
case 2:
w[0] = sec_theta_m * sec_theta_m;
w[1] = 2 * (sec_theta_m * sec_theta_m - 1);
break;
case 3:
w[0] = pow(sec_theta_m, 3);
w[1] = 3 * (pow(sec_theta_m, 3) - sec_theta_m);
w[2] = w[1];
break;
case 4:
w[0] = pow(sec_theta_m, 4);
w[1] = 4 * sec_theta_m * sec_theta_m * (sec_theta_m * sec_theta_m - 1);
w[2] = 2 * (1 - 4 * sec_theta_m * sec_theta_m + 3 * pow(sec_theta_m, 4));
w[3] = w[1];
break;
case 5:
w[0] = pow(sec_theta_m, 5);
w[1] = 5 * (pow(sec_theta_m, 5) - pow(sec_theta_m, 3));
w[2] =
10 * pow(sec_theta_m, 5) - 15 * pow(sec_theta_m, 3) + 5 * sec_theta_m;
w[3] = w[2];
w[4] = w[1];
break;
case 6:
w[0] = pow(sec_theta_m, 6);
w[1] = 6 * pow(sec_theta_m, 4) * (sec_theta_m * sec_theta_m - 1);
w[2] = 15 * pow(sec_theta_m, 6) - 24 * pow(sec_theta_m, 4) +
9 * sec_theta_m * sec_theta_m;
w[3] = 2 * (10 * pow(sec_theta_m, 6) - 18 * pow(sec_theta_m, 4) +
9 * sec_theta_m * sec_theta_m - 1);
w[4] = w[2];
w[5] = w[1];
break;
case 7:
w[0] = pow(sec_theta_m, 7);
w[1] = 7 * pow(sec_theta_m, 5) * (sec_theta_m * sec_theta_m - 1);
w[2] = 21 * pow(sec_theta_m, 7) - 35 * pow(sec_theta_m, 5) +
14 * pow(sec_theta_m, 3);
w[3] = 35 * pow(sec_theta_m, 7) - 70 * pow(sec_theta_m, 5) +
42 * pow(sec_theta_m, 3) - 7 * sec_theta_m;
w[4] = w[3];
w[5] = w[2];
w[6] = w[1];
break;
}
double l4 = SPEED_OF_LIGHT / (4. * Freq);
double Zaux = Z0, Zi;
for (int i = 0; i < N; i++) {
(RL < Z0) ? Zi = exp(log(Zaux) - gamma * w[i])
: Zi = exp(log(Zaux) + gamma * w[i]);
Zaux = Zi;
laddercode += QStringLiteral("TL:%1#%2;").arg(Zi).arg(l4);
}
return laddercode;
}
QString MatchDialog::calcMatchingCascadedLCSections(double r_real,
double r_imag, double Z0,
double Freq, int N) {
double RL = r_real, XL = r_imag, RS = Z0;
double w = 2 * pi * Freq, Q, C, L;
r2z(RL, XL, Z0);
double Raux, R, R1, R2;
QString s = "";
if (RL == 0) {
QMessageBox::warning(
0, QObject::tr("Error"),
QObject::tr("The load is reactive. It cannot be matched "
"using the quarter wavelength method"));
return NULL;
}
if (XL != 0) {
QMessageBox::warning(0, QObject::tr("Warning"),
QObject::tr("Reactive loads cannot be matched. Only "
"the real part will be matched"));
}
if (RL > RS)
R1 = RL, R2 = RS;
else
R1 = RS, R2 = RL;
Raux = R1;
for (int i = 0; i < N - 1; i++) {
R = pow(R1, 1. * (N - (i + 1)) / N) * pow(R2, 1. * (i + 1) / N);
Q = sqrt(Raux / R - 1);
C = Q / (w * Raux);
L = Q * R / w;
s += QStringLiteral("CP:%1;LS:%2;").arg(C).arg(L);
Raux = R;
}
Q = sqrt(R / R2 - 1);
C = Q / (w * R);
L = Q * R2 / w;
s += QStringLiteral("CP:%1;LS:%2;").arg(C).arg(L);
if (RL > RS)
{
QString temp = "";
QStringList strlist = s.split(";");
for (int i = strlist.count() - 1; i >= 0; i--)
temp += strlist.at(i) + ";";
s = temp;
}
return s;
}
QString MatchDialog::calcMatchingLambda8Lambda4(double r_real, double r_imag,
double Z0, double Freq) {
double RL = r_real, XL = r_imag;
double l4 = SPEED_OF_LIGHT / (4. * Freq);
double l8 = .5 * l4;
r2z(RL, XL, Z0);
double Zmm = sqrt(RL * RL + XL * XL);
double Zm = sqrt((Z0 * RL * Zmm) / (Zmm - XL));
return QStringLiteral("TL:%1#%2;TL:%3#%4;").arg(Zm).arg(l4).arg(Zmm).arg(l8);
}
void MatchDialog::SchematicParser(QString laddercode, int &x_pos, double Freq,
tSubstrate Substrate, bool microsyn) {
QStringList strlist = laddercode.split(";");
QString component, tag, label;
qDebug() << laddercode;
double value, value2, er, width;
int x_series = 120, x_shunt = 20;
QString componentstr = "", wirestr = "", paintingstr = "";
for (int i = 0; i < strlist.count(); i++) {
component = strlist.at(i);
int index_colon = component.indexOf(":");
tag = component.mid(0, index_colon);
component.remove(0, index_colon + 1);
int index = component.indexOf("#");
if (index != -1)
{
value = component.mid(0, index).toDouble();
value2 = component.mid(index + 1).toDouble();
} else {
if (!tag.compare("LBL"))
{
label = component;
} else
{
value = component.toDouble();
}
}
if (!tag.compare("P1"))
{
componentstr += QStringLiteral("<Pac P1 1 %2 -30 18 -26 0 1 \"1\" 1 \"%1\" 1 "
"\"0 dBm\" 0 \"1 GHz\" 0>\n")
.arg(misc::num2str(value, 3, "Ohm"))
.arg(x_pos);
componentstr += QStringLiteral("<GND * 1 %1 0 0 0 0 0>\n").arg(x_pos);
wirestr += QStringLiteral("<%1 -60 %1 -120>\n").arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120>\n").arg(x_pos).arg(x_pos + 120);
x_pos += 120;
} else if (!tag.compare("LBL"))
{
paintingstr += QStringLiteral("<Text %1 -150 12 #000000 0 \"%2\">\n")
.arg(x_pos)
.arg(component);
x_pos += 50;
} else if (!tag.compare("P2"))
{
x_pos += 100;
componentstr += QStringLiteral("<Pac P2 1 %2 -30 18 -26 0 1 \"1\" 1 \"%1\" 1 "
"\"0 dBm\" 0 \"1 GHz\" 0>\n")
.arg(misc::num2str(value, 3, "Ohm"))
.arg(x_pos);
componentstr += QStringLiteral("<GND * 1 %1 0 0 0 0 0>\n").arg(x_pos);
wirestr += QStringLiteral("<%1 -60 %1 -120>\n").arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120>\n")
.arg(x_pos - 100)
.arg(x_pos);
} else if (!tag.compare("DEV"))
{
paintingstr += QStringLiteral("<Text %1 -150 12 #000000 0 \"Device\">\n")
.arg(x_pos + 70);
paintingstr +=
QStringLiteral("<Rectangle %1 -160 90 50 #000000 0 1 #c0c0c0 1 0>\n")
.arg(x_pos + 50);
x_pos += 200;
} else if (!tag.compare("LS"))
{
QString val = misc::num2str(value, 3, "H");
componentstr += QStringLiteral("<L L1 1 %1 -120 -26 10 0 0 \"%2\" 1 "
" 0>\n")
.arg(x_pos + 60)
.arg(val);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos)
.arg(x_pos + 30);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos + 90)
.arg(x_pos + x_series);
x_pos += x_series;
} else if (!tag.compare("CS"))
{
QString val = misc::num2str(value, 3, "F");
componentstr += QStringLiteral("<C C1 1 %1 -120 -26 17 0 0 \"%2\" 1 "
" 0>\n")
.arg(x_pos + 60)
.arg(val);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos)
.arg(x_pos + 30);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos + 90)
.arg(x_pos + x_series);
x_pos += x_series;
} else if (!tag.compare("LP"))
{
QString val = misc::num2str(value, 3, "H");
componentstr += QStringLiteral("<GND * 1 %1 0 0 0 0 0>\n").arg(x_pos);
componentstr += QStringLiteral("<L L1 1 %1 -30 5 -20 0 1 \"%2\" 1 "
" 0>\n")
.arg(x_pos)
.arg(val);
wirestr += QStringLiteral("<%1 -60 %1 -120 "
" 0 0 0 "
">\n")
.arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos - 20)
.arg(x_pos + x_shunt);
x_pos += x_shunt;
} else if (!tag.compare("CP"))
{
QString val = misc::num2str(value, 3, "F");
componentstr += QStringLiteral("<GND * 1 %1 0 0 0 0 0>\n").arg(x_pos);
componentstr += QStringLiteral("<C C1 1 %1 -30 15 -20 0 1 \"%2\" 1 "
" 0>\n")
.arg(x_pos)
.arg(val);
wirestr += QStringLiteral("<%1 -60 %1 -120 "
" 0 0 0 "
">\n")
.arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos - 20)
.arg(x_pos + x_shunt);
x_pos += x_shunt;
} else if (!tag.compare("TL"))
{
if (microsyn)
{
er = Substrate.er;
getMicrostrip(value, Freq, &Substrate, width, er);
QString val_width =
misc::num2str(width, 3, "m");
QString val_length =
misc::num2str(value2 / sqrt(er), 3, "m");
componentstr +=
QStringLiteral("<MLIN MS1 1 %3 -120 -26 20 0 0 \"Sub1\" 1 \"%1\" 1 \"%2\" "
"1 \"Hammerstad\" 0 \"Kirschning\" 0 \"26.85\" 0>\n")
.arg(val_width)
.arg(val_length)
.arg(x_pos + 60);
} else {
QString val_impedance = misc::num2str(value, 3, "Ohm");
QString val_length = misc::num2str(value2, 3, "m");
componentstr += QStringLiteral("<TLIN Line1 1 %3 -120 -26 20 0 0 \"%1\" 1 "
"\"%2\" 1 \"0 dB\" 0 \"26.85\" 0>\n")
.arg(val_impedance)
.arg(val_length)
.arg(x_pos + 60);
}
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos)
.arg(x_pos + 30);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos + 90)
.arg(x_pos + x_series);
x_pos += x_series;
} else if (!tag.compare("OU"))
{
if (microsyn)
{
er = Substrate.er;
getMicrostrip(value, Freq, &Substrate, width, er);
QString val_width = misc::num2str(width, 3, "m");
QString val_length = misc::num2str(value2 / sqrt(er), 3, "m");
componentstr +=
QStringLiteral("<MLIN MS1 1 %3 -180 30 -30 0 1 \"Sub1\" 1 \"%1\" 1 \"%2\" "
"1 \"Hammerstad\" 0 \"Kirschning\" 0 \"26.85\" 0>\n")
.arg(val_width)
.arg(val_length)
.arg(x_pos);
} else {
QString val_impedance = misc::num2str(value, 3, "Ohm");
QString val_length = misc::num2str(value2, 3, "m");
componentstr += QStringLiteral("<TLIN Line1 1 %3 -180 30 -30 0 1 \"%1\" 1 "
"\"%2\" 1 \"0 dB\" 0 \"26.85\" 0>\n")
.arg(val_impedance)
.arg(val_length)
.arg(x_pos);
}
wirestr += QStringLiteral("<%1 -150 %1 -120 "
" 0 0 0 "
">\n")
.arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos)
.arg(x_pos + x_shunt);
} else if (!tag.compare("OL"))
{
if (microsyn)
{
er = Substrate.er;
getMicrostrip(value, Freq, &Substrate, width, er);
QString val_width = misc::num2str(width, 3, "m");
QString val_length = misc::num2str(value2 / sqrt(er), 3, "m");
componentstr +=
QStringLiteral("<MLIN MS1 1 %3 -60 -26 30 0 1 \"Sub1\" 1 \"%1\" 1 \"%2\" "
"1 \"Hammerstad\" 0 \"Kirschning\" 0 \"26.85\" 0>\n")
.arg(val_width)
.arg(val_length)
.arg(x_pos);
} else {
QString val_impedance = misc::num2str(value, 3, "Ohm");
QString val_length = misc::num2str(value2, 3, "m");
componentstr += QStringLiteral("<TLIN Line1 1 %3 -60 -26 30 0 1 \"%1\" 1 "
"\"%2\" 1 \"0 dB\" 0 \"26.85\" 0>\n")
.arg(val_impedance)
.arg(val_length)
.arg(x_pos);
}
wirestr += QStringLiteral("<%1 -90 %1 -120 "
" 0 0 0 "
">\n")
.arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos - 20)
.arg(x_pos + x_shunt);
x_pos += x_shunt;
} else if (!tag.compare("SU"))
{
if (microsyn)
{
er = Substrate.er;
getMicrostrip(value, Freq, &Substrate, width, er);
QString val_width = misc::num2str(width, 3, "m");
QString val_length = misc::num2str(value2 / sqrt(er), 3, "m");
componentstr +=
QStringLiteral("<MLIN MS1 1 %3 -180 30 -30 0 1 \"Sub1\" 1 \"%1\" 1 \"%2\" "
"1 \"Hammerstad\" 0 \"Kirschning\" 0 \"26.85\" 0>\n")
.arg(val_width)
.arg(val_length)
.arg(x_pos);
} else {
QString val_impedance = misc::num2str(value, 3, "Ohm");
QString val_length = misc::num2str(value2, 3, "m");
componentstr += QStringLiteral("<TLIN Line1 1 %3 -180 30 -30 0 1 \"%1\" 1 "
"\"%2\" 1 \"0 dB\" 0 \"26.85\" 0>\n")
.arg(val_impedance)
.arg(val_length)
.arg(x_pos);
}
componentstr += QStringLiteral("<GND * 1 %1 -210 0 0 0 2>\n").arg(x_pos);
wirestr += QStringLiteral("<%1 -150 %1 -120 "
" 0 0 0 "
">\n")
.arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos)
.arg(x_pos + x_shunt);
} else if (!tag.compare("SL"))
{
if (microsyn)
{
er = Substrate.er;
getMicrostrip(value, Freq, &Substrate, width, er);
QString val_width = misc::num2str(width, 3, "m");
QString val_length = misc::num2str(value2 / sqrt(er), 3, "m");
componentstr +=
QStringLiteral("<MLIN MS1 1 %3 -60 30 -30 0 1 \"Sub1\" 1 \"%1\" 1 \"%2\" "
"1 \"Hammerstad\" 0 \"Kirschning\" 0 \"26.85\" 0>\n")
.arg(val_width)
.arg(val_length)
.arg(x_pos);
} else {
QString val_impedance = misc::num2str(value, 3, "Ohm");
QString val_length = misc::num2str(value2, 3, "m");
componentstr += QStringLiteral("<TLIN Line1 1 %3 -60 20 30 0 1 \"%1\" 1 "
"\"%2\" 1 \"0 dB\" 0 \"26.85\" 0>\n")
.arg(val_impedance)
.arg(val_length)
.arg(x_pos);
}
componentstr += QStringLiteral("<GND * 1 %1 -30 0 0 0 0>\n").arg(x_pos);
wirestr += QStringLiteral("<%1 -90 %1 -120 "
" 0 0 0 "
">\n")
.arg(x_pos);
wirestr += QStringLiteral("<%1 -120 %2 -120 "
" 0 0 0 "
">\n")
.arg(x_pos - 20)
.arg(x_pos + x_shunt);
x_pos += x_shunt;
} else if (!tag.compare("S2P"))
{
double freq_start = Freq / 2.0;
double freq_stop = 2.0 *Freq;
QString val_freq_start = misc::num2str(freq_start, 3, "Hz");
QString val_freq_stop = misc::num2str(freq_stop, 3, "Hz");
componentstr +=
QStringLiteral("<.SP SP1 1 0 100 0 67 0 0 \"lin\" 1 \"%1\" 1 \"%2\" 1 "
"\"300\" 1 \"no\" 0 \"1\" 0 \"2\" 0>\n")
.arg((val_freq_start))
.arg((val_freq_stop));
if (laddercode.indexOf("P2") == -1)
componentstr += QStringLiteral("<Eqn Eqn1 1 200 100 -28 15 0 0 "
"\"S11_dB=dB(S[1,1])\" 1 \"yes\" 0>\n");
else
componentstr += QStringLiteral("<Eqn Eqn1 1 200 100 -28 15 0 0 "
"\"S11_dB=dB(S[1,1])\" 1 \"S21_dB=dB(S[2,1])\" "
"1 \"S22_dB=dB(S[2,2])\" 1 \"yes\" 0>\n");
} else if (!tag.compare("ZL"))
{
double RL = value;
double XL = value2;
x_pos += 100;
if ((RL > 1e-3) && (XL < -1e-3))
{
QString val_Res = misc::num2str(RL, 3, "Ohm");
QString val_Cap = misc::num2str(1 / (fabs(XL) * 2 * pi * Freq), 3, "F");
componentstr +=
QString(
"<R R1 1 %1 -30 15 -26 0 -1 \"%2\" 1 \"26.85\" 0 \"US\" 0>\n")
.arg(x_pos)
.arg(val_Res);
componentstr += QStringLiteral("<C C1 1 %1 -90 15 -26 0 -1 \"%2\" 1 0>\n")
.arg(x_pos)
.arg(val_Cap);
paintingstr +=
QStringLiteral("<Text %1 50 12 #000000 0 \"%4-j%5 %2 @ %3\">\n")
.arg(x_pos)
.arg(QChar(0x2126))
.arg(misc::num2str(Freq, 3, "Hz"))
.arg(RL)
.arg(fabs(XL));
} else if ((RL > 1e-3) && (XL > 1e-3))
{
QString val_Res = misc::num2str(RL, 3, "Ohm");
QString val_Ind = misc::num2str(XL / (2 * pi * Freq), 3, "H");
componentstr +=
QString(
"<R R1 1 %1 -30 15 -26 0 -1 \"%2\" 1 \"26.85\" 0 \"US\" 0>\n")
.arg(x_pos)
.arg(val_Res);
componentstr += QStringLiteral("<L L1 1 %1 -90 15 -26 0 -1 \"%2\" 1 0>\n")
.arg(x_pos)
.arg(val_Ind);
paintingstr +=
QStringLiteral("<Text %1 50 12 #000000 0 \"%4+j%5 %2 @ %3\">\n")
.arg(x_pos)
.arg(QChar(0x2126))
.arg(misc::num2str(Freq, 3, "Hz"))
.arg(RL)
.arg(XL);
} else if ((RL > 1e-3) && (fabs(XL) < 1e-3))
{
QString val_Res = misc::num2str(RL, 3, "Ohm");
componentstr +=
QString(
"<R R1 1 %1 -30 15 -26 0 -1 \"%2\" 1 \"26.85\" 0 \"US\" 0>\n")
.arg(x_pos)
.arg(val_Res);
wirestr += QStringLiteral("<%1 -60 %1 -120>\n").arg(x_pos);
paintingstr += QStringLiteral("<Text %1 50 12 #000000 0 \"%4 %2 @ %3\">\n")
.arg(x_pos)
.arg(QChar(0x2126))
.arg(misc::num2str(Freq, 3, "Hz"))
.arg(RL);
} else if ((RL < 1e-3) && (XL > 1e-3))
{
QString val_Ind = misc::num2str(XL / (2 * pi * Freq), 3, "H");
componentstr +=
QString(
"<L L1 1 %1 -30 15 -26 0 -1 \"%2\" 1 \"26.85\" 0 \"US\" 0>\n")
.arg(x_pos)
.arg(val_Ind);
wirestr += QStringLiteral("<%1 -60 %1 -120>\n").arg(x_pos);
paintingstr +=
QStringLiteral("<Text %1 50 12 #000000 0 \"j%4 %2 @ %3\">\n")
.arg(x_pos)
.arg(QChar(0x2126))
.arg(misc::num2str(Freq, 3, "Hz"))
.arg(XL);
} else if ((RL < 1e-3) && (XL < -1e-3))
{
QString val_Cap = misc::num2str(1 / (fabs(XL) * 2 * pi * Freq), 3, "F");
componentstr +=
QString(
"<C C1 1 %1 -30 15 -26 0 -1 \"%2\" 1 \"26.85\" 0 \"US\" 0>\n")
.arg(x_pos)
.arg(val_Cap);
wirestr += QStringLiteral("<%1 -60 %1 -120>\n").arg(x_pos);
paintingstr +=
QStringLiteral("<Text %1 50 12 #000000 0 \"-j%4 %2 @ %3\">\n")
.arg(x_pos)
.arg(QChar(0x2126))
.arg(misc::num2str(Freq, 3, "Hz"))
.arg(fabs(XL));
}
wirestr += QStringLiteral("<%1 -120 %2 -120>\n")
.arg(x_pos - 100)
.arg(x_pos);
componentstr += QStringLiteral("<GND * 1 %1 0 0 -1 0 0>\n").arg(x_pos);
paintingstr +=
QStringLiteral("<Rectangle %1 -150 200 200 #000000 0 1 #c0c0c0 1 0>\n")
.arg(x_pos - 30);
}
}
if (microsyn)
componentstr +=
QStringLiteral("<SUBST Sub1 1 400 200 -30 24 0 0 \"%1\" 1 \"%2mm\" 1 \"%3um\" "
"1 \"%4\" 1 \"%5\" 1 \"%6\" 1>\n")
.arg(Substrate.er)
.arg(Substrate.height * 1e3)
.arg(Substrate.thickness * 1e6)
.arg(Substrate.tand)
.arg(Substrate.resistivity)
.arg(Substrate.roughness);
QString Schematic = "<Qucs Schematic " PACKAGE_VERSION ">\n";
Schematic += "<Components>\n";
Schematic += componentstr;
Schematic += "</Components>\n";
Schematic += "<Wires>\n";
Schematic += wirestr;
Schematic += "</Wires>\n";
Schematic += "<Paintings>\n";
Schematic += paintingstr;
Schematic += "</Paintings>\n";
QApplication::clipboard()->setText(Schematic, QClipboard::Clipboard);
}