Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/dialogs/matchdialog.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                matchdialog.cpp
00003                               -----------------
00004     begin                : Fri Jul 22 2005
00005     copyright            : (C) 2005 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #ifdef HAVE_CONFIG_H
00019 # include <config.h>
00020 #endif
00021 
00022 #include "matchdialog.h"
00023 #include "main.h"
00024 #include "qucs.h"
00025 #include "element.h"
00026 #include "../components/capacitor.h"
00027 #include "../components/inductor.h"
00028 #include "../components/ground.h"
00029 #include "misc.h"
00030 
00031 #include <QLabel>
00032 #include <QHBoxLayout>
00033 #include <QVBoxLayout>
00034 #include <QLineEdit>
00035 #include <QComboBox>
00036 #include <QCheckBox>
00037 #include <QValidator>
00038 #include <QPushButton>
00039 #include <QMessageBox>
00040 #include <QApplication>
00041 #include <QClipboard>
00042 #include <QGroupBox>
00043 
00044 #include <cmath>
00045 
00046 
00047 MatchDialog::MatchDialog(QWidget *parent)
00048       : QDialog(parent) 
00049 {
00050   setWindowTitle(tr("Create Matching Circuit"));
00051   DoubleVal = new QDoubleValidator(this);
00052 
00053   all = new QVBoxLayout(this);
00054 
00055   TwoCheck = new QCheckBox(tr("calculate two-port matching"));
00056   all->addWidget(TwoCheck);
00057   TwoCheck->setChecked(true);
00058   connect(TwoCheck, SIGNAL(toggled(bool)), SLOT(slotSetTwoPort(bool)));
00059 
00060   // ...........................................................
00061   QGroupBox *ImpBox = new QGroupBox(tr("Reference Impedance"));
00062   all->addWidget(ImpBox);
00063   QHBoxLayout *ImpLayout = new QHBoxLayout();
00064   Port1Label = new QLabel(tr("Port 1"));
00065   Ref1Edit = new QLineEdit("50");
00066   Ref1Edit->setValidator(DoubleVal);
00067   Ohm1Label = new QLabel(tr("ohms"));
00068   connect(Ref1Edit, SIGNAL(textChanged(const QString&)),
00069     SLOT(slotImpedanceChanged(const QString&)));
00070   Port2Label = new QLabel(tr("Port 2"));
00071   Ref2Edit = new QLineEdit("50");
00072   Ref2Edit->setValidator(DoubleVal);
00073   Ohm2Label = new QLabel(tr("ohms"));
00074   ImpLayout->addWidget(Port1Label);
00075   ImpLayout->addWidget(Ref1Edit);
00076   ImpLayout->addWidget(Ohm1Label);
00077   ImpLayout->addSpacing(50);
00078   ImpLayout->addWidget(Port2Label);
00079   ImpLayout->addWidget(Ref2Edit);
00080   ImpLayout->addWidget(Ohm2Label);
00081   ImpBox->setLayout(ImpLayout);
00082 
00083   // ...........................................................
00084   QGroupBox *SParBox = new QGroupBox(tr("S Parameter"));
00085   all->addWidget(SParBox);
00086   QVBoxLayout *SParLayout = new QVBoxLayout();
00087   SParBox->setLayout(SParLayout);
00088 
00089   QHBoxLayout *h1 = new QHBoxLayout();
00090   h1->setSpacing(3);
00091   FormatLabel = new QLabel(tr("Input format"));
00092   h1->addWidget(FormatLabel);
00093   FormatCombo = new QComboBox();
00094   h1->addWidget(FormatCombo);
00095   FormatCombo->insertItem(tr("real/imag"));
00096   FormatCombo->insertItem(tr("mag/deg"));
00097   connect(FormatCombo, SIGNAL(activated(int)), SLOT(slotChangeMode(int)));
00098   h1->addStretch(5);
00099   SParLayout->addLayout(h1);
00100 
00101   QHBoxLayout *h3 = new QHBoxLayout();
00102   h3->setSpacing(3);
00103   QVBoxLayout *VBox1 = new QVBoxLayout();
00104   h3->addLayout(VBox1);
00105     S11Label = new QLabel(tr("S11"));
00106     S21Label = new QLabel(tr("S21"));
00107     VBox1->addWidget(S11Label);
00108     VBox1->addWidget(S21Label);
00109   QVBoxLayout *VBox2 = new QVBoxLayout();
00110   h3->addLayout(VBox2);
00111     S11magEdit = new QLineEdit("0.5");
00112     S11magEdit->setValidator(DoubleVal);
00113     S21magEdit = new QLineEdit("0.5");
00114     S21magEdit->setValidator(DoubleVal);
00115     VBox2->addWidget(S11magEdit);
00116     VBox2->addWidget(S21magEdit);
00117   QVBoxLayout *VBox3 = new QVBoxLayout();
00118   h3->addLayout(VBox3);
00119     S11sLabel = new QLabel("+j");
00120     S21sLabel = new QLabel("+j");
00121     VBox3->addWidget(S11sLabel);
00122     VBox3->addWidget(S21sLabel);
00123   QVBoxLayout *VBox4 = new QVBoxLayout();
00124   h3->addLayout(VBox4);
00125     S11degEdit = new QLineEdit("0");
00126     S11degEdit->setValidator(DoubleVal);
00127     S21degEdit = new QLineEdit("0");
00128     S21degEdit->setValidator(DoubleVal);
00129     VBox4->addWidget(S11degEdit);
00130     VBox4->addWidget(S21degEdit);
00131   QVBoxLayout *VBox5 = new QVBoxLayout();
00132   h3->addLayout(VBox5);
00133     S11uLabel = new QLabel(" ");
00134     S21uLabel = new QLabel(" ");
00135     VBox5->addWidget(S11uLabel);
00136     VBox5->addWidget(S21uLabel);
00137   h3->addStretch(5);
00138   QVBoxLayout *VBox6 = new QVBoxLayout();
00139   h3->addLayout(VBox6);
00140     S12Label = new QLabel(tr("S12"));
00141     S22Label = new QLabel(tr("S22"));
00142     VBox6->addWidget(S12Label);
00143     VBox6->addWidget(S22Label);
00144   QVBoxLayout *VBox7 = new QVBoxLayout();
00145   h3->addLayout(VBox7);
00146     S12magEdit = new QLineEdit("0");
00147     S12magEdit->setValidator(DoubleVal);
00148     S22magEdit = new QLineEdit("0.5");
00149     S22magEdit->setValidator(DoubleVal);
00150     VBox7->addWidget(S12magEdit);
00151     VBox7->addWidget(S22magEdit);
00152   QVBoxLayout *VBox8 = new QVBoxLayout();
00153   h3->addLayout(VBox8);
00154     S12sLabel = new QLabel("+j");
00155     S22sLabel = new QLabel("+j");
00156     VBox8->addWidget(S12sLabel);
00157     VBox8->addWidget(S22sLabel);
00158   QVBoxLayout *VBox9 = new QVBoxLayout();
00159   h3->addLayout(VBox9);
00160     S12degEdit = new QLineEdit("0");
00161     S12degEdit->setValidator(DoubleVal);
00162     S22degEdit = new QLineEdit("0");
00163     S22degEdit->setValidator(DoubleVal);
00164     VBox9->addWidget(S12degEdit);
00165     VBox9->addWidget(S22degEdit);
00166   QVBoxLayout *VBox0 = new QVBoxLayout();
00167   h3->addLayout(VBox0);
00168     S12uLabel = new QLabel(" ");
00169     S22uLabel = new QLabel(" ");
00170     VBox0->addWidget(S12uLabel);
00171     VBox0->addWidget(S22uLabel);
00172   SParLayout->addLayout(h3);
00173 
00174   connect(S21magEdit, SIGNAL(textChanged(const QString&)),
00175     SLOT(slotImpedanceChanged(const QString&)));
00176   connect(S21degEdit, SIGNAL(textChanged(const QString&)),
00177     SLOT(slotImpedanceChanged(const QString&)));
00178   connect(S11magEdit, SIGNAL(textChanged(const QString&)),
00179     SLOT(slotReflexionChanged(const QString&)));
00180   connect(S11degEdit, SIGNAL(textChanged(const QString&)),
00181     SLOT(slotReflexionChanged(const QString&)));
00182 
00183 
00184   QHBoxLayout *h2 = new QHBoxLayout();
00185   h2->setSpacing(3);
00186   FrequencyLabel = new QLabel(tr("Frequency:"));
00187   FrequencyEdit = new QLineEdit();
00188   FrequencyEdit->setValidator(DoubleVal);
00189   h2->addWidget(FrequencyLabel);
00190   h2->addWidget(FrequencyEdit);
00191   UnitCombo = new QComboBox();
00192   UnitCombo->insertItem("Hz");
00193   UnitCombo->insertItem("kHz");
00194   UnitCombo->insertItem("MHz");
00195   UnitCombo->insertItem("GHz");
00196   h2->addWidget(UnitCombo);
00197   h2->addStretch(5);
00198   SParLayout->addLayout(h2);
00199 
00200   // ...........................................................
00201   QHBoxLayout *h0 = new QHBoxLayout();
00202   h0->setSpacing(5);
00203   all->addLayout(h0);
00204   h0->addStretch(5);
00205   QPushButton *buttCreate = new QPushButton(tr("Create"));
00206   QPushButton *buttCancel = new QPushButton(tr("Cancel"));
00207   h0->addWidget(buttCreate);
00208   h0->addWidget(buttCancel);
00209   connect(buttCreate, SIGNAL(clicked()), SLOT(slotButtCreate()));
00210   connect(buttCancel, SIGNAL(clicked()), SLOT(reject()));
00211 
00212   slotReflexionChanged("");  // calculate impedance
00213   setFrequency(1e9);  // set 1GHz
00214   resize(520, 100);
00215 }
00216 
00217 MatchDialog::~MatchDialog()
00218 {
00219   delete all;
00220   delete DoubleVal;
00221 }
00222 
00223 // -----------------------------------------------------------------------
00224 void MatchDialog::setFrequency(double Freq_)
00225 {
00226   int Expo = int(log10(Freq_) / 3.0);
00227   if(Expo < 0) Expo = 0;
00228   else if(Expo > 3) Expo = 3;
00229   UnitCombo->setCurrentItem(Expo);
00230   Freq_ /= pow(10.0, double(3*Expo));
00231   FrequencyEdit->setText(QString::number(Freq_));
00232 }
00233 
00234 // -----------------------------------------------------------------------
00235 // Is called when the checkbox for two-port matching changes.
00236 void MatchDialog::slotSetTwoPort(bool on)
00237 {
00238   if(on) { // two-port matching ?
00239     S11Label->setText(tr("S11"));
00240     S21Label->setText(tr("S21"));
00241     S12magEdit->setEnabled(true);
00242     S22magEdit->setEnabled(true);
00243     S12degEdit->setEnabled(true);
00244     S22degEdit->setEnabled(true);
00245     S12Label->setEnabled(true);
00246     S22Label->setEnabled(true);
00247     S12sLabel->setEnabled(true);
00248     S22sLabel->setEnabled(true);
00249     S12degEdit->setEnabled(true);
00250     S22degEdit->setEnabled(true);
00251     S12uLabel->setEnabled(true);
00252     S22uLabel->setEnabled(true);
00253     Port2Label->setEnabled(true);
00254     Ref2Edit->setEnabled(true);
00255     Ohm2Label->setEnabled(true);
00256   }
00257   else {
00258     S11Label->setText(tr("Reflexion Coefficient"));
00259     S21Label->setText(tr("Impedance (ohms)"));
00260     S12magEdit->setEnabled(false);
00261     S22magEdit->setEnabled(false);
00262     S12degEdit->setEnabled(false);
00263     S22degEdit->setEnabled(false);
00264     S12Label->setEnabled(false);
00265     S22Label->setEnabled(false);
00266     S12sLabel->setEnabled(false);
00267     S22sLabel->setEnabled(false);
00268     S12degEdit->setEnabled(false);
00269     S22degEdit->setEnabled(false);
00270     S12uLabel->setEnabled(false);
00271     S22uLabel->setEnabled(false);
00272     Port2Label->setEnabled(false);
00273     Ref2Edit->setEnabled(false);
00274     Ohm2Label->setEnabled(false);
00275   }
00276 }
00277 
00278 // -----------------------------------------------------------------------
00279 // Is called when the combobox changes between mag/deg and real/imag.
00280 void MatchDialog::slotChangeMode(int Index)
00281 {
00282   if(Index) { // polar ?
00283     S11sLabel->setText("/");
00284     S12sLabel->setText("/");
00285     S21sLabel->setText("/");
00286     S22sLabel->setText("/");
00287     S11uLabel->setText(QString::fromUtf8("°"));
00288     S12uLabel->setText(QString::fromUtf8("°"));
00289     S21uLabel->setText(QString::fromUtf8("°"));
00290     S22uLabel->setText(QString::fromUtf8("°"));
00291 
00292     double Real = S11magEdit->text().toDouble();
00293     double Imag = S11degEdit->text().toDouble();
00294     c2p(Real, Imag);
00295     S11magEdit->setText(QString::number(Real));
00296     S11degEdit->setText(QString::number(Imag));
00297 
00298     Real = S12magEdit->text().toDouble();
00299     Imag = S12degEdit->text().toDouble();
00300     c2p(Real, Imag);
00301     S12magEdit->setText(QString::number(Real));
00302     S12degEdit->setText(QString::number(Imag));
00303 
00304     Real = S21magEdit->text().toDouble();
00305     Imag = S21degEdit->text().toDouble();
00306     c2p(Real, Imag);
00307     S21magEdit->setText(QString::number(Real));
00308     S21degEdit->setText(QString::number(Imag));
00309 
00310     Real = S22magEdit->text().toDouble();
00311     Imag = S22degEdit->text().toDouble();
00312     c2p(Real, Imag);
00313     S22magEdit->setText(QString::number(Real));
00314     S22degEdit->setText(QString::number(Imag));
00315   }
00316   else {  // cartesian
00317     S11sLabel->setText("+j");
00318     S12sLabel->setText("+j");
00319     S21sLabel->setText("+j");
00320     S22sLabel->setText("+j");
00321     S11uLabel->setText(" ");
00322     S12uLabel->setText(" ");
00323     S21uLabel->setText(" ");
00324     S22uLabel->setText(" ");
00325 
00326     double Mag   = S11magEdit->text().toDouble();
00327     double Phase = S11degEdit->text().toDouble();
00328     p2c(Mag, Phase);
00329     S11magEdit->setText(QString::number(Mag));
00330     S11degEdit->setText(QString::number(Phase));
00331 
00332     Mag   = S12magEdit->text().toDouble();
00333     Phase = S12degEdit->text().toDouble();
00334     p2c(Mag, Phase);
00335     S12magEdit->setText(QString::number(Mag));
00336     S12degEdit->setText(QString::number(Phase));
00337 
00338     Mag   = S21magEdit->text().toDouble();
00339     Phase = S21degEdit->text().toDouble();
00340     p2c(Mag, Phase);
00341     S21magEdit->setText(QString::number(Mag));
00342     S21degEdit->setText(QString::number(Phase));
00343 
00344     Mag   = S22magEdit->text().toDouble();
00345     Phase = S22degEdit->text().toDouble();
00346     p2c(Mag, Phase);
00347     S22magEdit->setText(QString::number(Mag));
00348     S22degEdit->setText(QString::number(Phase));
00349   }
00350 }
00351 
00352 // -----------------------------------------------------------------------
00353 // Is called if the user changed the impedance. -> The reflexion
00354 // coefficient is calculated.
00355 void MatchDialog::slotImpedanceChanged(const QString&)
00356 {
00357   if(TwoCheck->isChecked())  return;
00358 
00359   double Z0   = Ref1Edit->text().toDouble();
00360   double Real = S21magEdit->text().toDouble();
00361   double Imag = S21degEdit->text().toDouble();
00362   z2r(Real, Imag, Z0);
00363   S11magEdit->blockSignals(true); // do not call "changed-slot"
00364   S11magEdit->setText(QString::number(Real));
00365   S11magEdit->blockSignals(false);
00366   S11degEdit->blockSignals(true); // do not call "changed-slot"
00367   S11degEdit->setText(QString::number(Imag));
00368   S11degEdit->blockSignals(false);
00369 }
00370 
00371 // -----------------------------------------------------------------------
00372 // Is called if the user changed the reflexion coefficient. -> The impedance
00373 // is calculated.
00374 void MatchDialog::slotReflexionChanged(const QString&)
00375 {
00376   if(TwoCheck->isChecked())  return;
00377 
00378   double Z0   = Ref1Edit->text().toDouble();
00379   double Real = S11magEdit->text().toDouble();
00380   double Imag = S11degEdit->text().toDouble();
00381   r2z(Real, Imag, Z0);
00382   S21magEdit->blockSignals(true); // do not call "changed-slot"
00383   S21magEdit->setText(QString::number(Real));
00384   S21magEdit->blockSignals(false);
00385   S21degEdit->blockSignals(true); // do not call "changed-slot"
00386   S21degEdit->setText(QString::number(Imag));
00387   S21degEdit->blockSignals(false);
00388 }
00389 
00390 // -----------------------------------------------------------------------
00391 // Is called if the "Create"-button is pressed.
00392 void MatchDialog::slotButtCreate()
00393 {
00394   double Z1   = Ref1Edit->text().toDouble();
00395   double Z2   = Ref2Edit->text().toDouble();
00396   double Freq = FrequencyEdit->text().toDouble() *
00397                 pow(10.0, 3.0*double(UnitCombo->currentItem()));
00398 
00399   double S11real = S11magEdit->text().toDouble();
00400   double S11imag = S11degEdit->text().toDouble();
00401   double S12real = S12magEdit->text().toDouble();
00402   double S12imag = S12degEdit->text().toDouble();
00403   double S21real = S21magEdit->text().toDouble();
00404   double S21imag = S21degEdit->text().toDouble();
00405   double S22real = S22magEdit->text().toDouble();
00406   double S22imag = S22degEdit->text().toDouble();
00407   if(FormatCombo->currentItem()) {  // are they polar ?
00408     p2c(S11real, S11imag);
00409     p2c(S12real, S12imag);
00410     p2c(S21real, S21imag);
00411     p2c(S22real, S22imag);
00412   }
00413 
00414   if(TwoCheck->isChecked()) {  // two-port matching ?
00415     // determinante of S-parameter matrix
00416     double DetReal = S11real*S22real - S11imag*S22imag
00417                    - S12real*S21real + S12imag*S21imag;
00418     double DetImag = S11real*S22imag + S11imag*S22real
00419                    - S12real*S21imag - S12imag*S21real;
00420 
00421     if(!MatchDialog::calc2PortMatch(S11real, S11imag, S22real, S22imag,
00422                                     DetReal, DetImag, Z1, Z2, Freq))
00423       return;
00424   }
00425   else
00426     if(!calcMatchingCircuit(S11real, S11imag, Z1, Freq))
00427       return;
00428 
00429   QucsMain->slotEditPaste(true);
00430   accept();
00431 }
00432 
00433 
00434 // -----------------------------------------------------------------------
00435 // transform real/imag into mag/deg (cartesian to polar)
00436 void MatchDialog::c2p(double& Real, double& Imag)
00437 {
00438   double Real_ = Real;
00439   Real = sqrt(Real*Real + Imag*Imag);     // magnitude
00440   Imag = 180.0/pi * atan2(Imag, Real_); // phase in degree
00441 }
00442 
00443 // -----------------------------------------------------------------------
00444 // transform mag/deg into real/imag (polar to cartesian)
00445 void MatchDialog::p2c(double& Real, double& Imag)
00446 {
00447   double Real_ = Real;
00448   Real = Real_ * cos(Imag * pi/180.0);  // real part
00449   Imag = Real_ * sin(Imag * pi/180.0);  // imaginary part
00450 }
00451 
00452 // -----------------------------------------------------------------------
00453 // transform reflexion coefficient into impedance
00454 void MatchDialog::r2z(double& Real, double& Imag, double Z0)
00455 {
00456   double tmp  = Z0 / ((1.0-Real)*(1.0-Real) + Imag*Imag);
00457   Real  = (1.0 - Real*Real - Imag*Imag) * tmp;
00458   Imag *= 2.0 * tmp;
00459 }
00460 
00461 // -----------------------------------------------------------------------
00462 // transform impedance into reflexion coefficient
00463 void MatchDialog::z2r(double& Real, double& Imag, double Z0)
00464 {
00465   double tmp  = (Real+Z0)*(Real+Z0) + Imag*Imag;
00466   Real  = (Real*Real + Imag*Imag - Z0*Z0) / tmp;
00467   Imag *= 2.0 * Z0 / tmp;
00468 }
00469 
00470 // -----------------------------------------------------------------------
00471 // Calculate matching circuit. Returns string like "sp:1nH:5pF"
00472 QString MatchDialog::calcMatching(double r_real, double r_imag,
00473         double Z0, double Freq)
00474 {
00475   double Zreal = r_real, Zimag = r_imag;
00476   r2z(Zreal, Zimag, Z0);
00477 
00478   if (Zreal < 0.0) {
00479     if (Zreal < -1e-13) {
00480       QMessageBox::critical(0, tr("Error"),
00481   tr("Real part of impedance must be greater zero,\nbut is %1 !").arg(Zreal));
00482       return QString("");  // matching not possible
00483     }
00484 
00485     // In high-Q circuits, Zreal often becomes somewhat about -1e-16
00486     // because of numerical inaccuracy.
00487     Zreal = 0.0;
00488   }
00489 
00490 
00491   double X1, X2, Omega = 2.0 * pi * Freq;
00492   QString Str;
00493   if(r_real < 0) {
00494     // ...................................................
00495     // first serial than parallel component (possible if Zreal <= Z0)
00496     Str = "sp";
00497     X1 = sqrt(Zreal * (Z0 - Zreal));
00498     if (Zimag < 0.0)  X1 *= -1.0;   // always use shortest matching path
00499     X1 -= Zimag;
00500 
00501     // parallel component
00502     X2 = (Zimag + X1) / (Zreal*Zreal + (Zimag + X1)*(Zimag + X1));
00503   }
00504   else {
00505 
00506     Str = "ps";
00507     X1 = Zreal + Zimag*Zimag / Zreal - Z0;
00508     // ...................................................
00509     // first parallel than serial component (possible if X >= 0.0)
00510     X1 = sqrt(Z0 * X1);
00511     if (Zimag > 0.0)  X1 *= -1.0;   // always use shortest matching path
00512 
00513     // parallel component
00514     X2 = Zimag / (Zreal*Zreal + Zimag*Zimag) + X1 / (Z0*Z0 + X1*X1);
00515   }
00516 
00517 
00518   // serial component
00519   if (X1 < 0.0)   // capacitance ?
00520     Str += ':' + misc::num2str(-1.0 / Omega / X1) + 'F';
00521   else   // inductance
00522     Str += ':' + misc::num2str(X1 / Omega) + 'H';
00523 
00524   // parallel component
00525   if (X2 < 0.0)   // inductance ?
00526     Str += ':' + misc::num2str(-1.0 / Omega / X2) + 'H';
00527   else   // capacitance
00528     Str += ':' + misc::num2str(X2 / Omega) + 'F';
00529 
00530   return Str;
00531 }
00532 
00533 // -----------------------------------------------------------------------
00534 bool MatchDialog::calcMatchingCircuit(double r_real, double r_imag,
00535           double Z0, double Freq)
00536 {
00537   QString Schematic =
00538       "<Qucs Schematic " PACKAGE_VERSION ">\n"
00539       "<Components>\n";
00540 
00541 
00542   QString Str = calcMatching(r_real, r_imag, Z0, Freq);
00543   if(Str.isEmpty())  return false;
00544 
00545   if(Str.section(':', 0,0) == "sp") {
00546     // ...................................................
00547     // first serial than parallel component
00548 
00549     if(Str.section(':', 1,1).right(1) == "F")
00550       Schematic += "<C C1";
00551     else
00552       Schematic += "<L L1";
00553     Schematic += " 1 100 10 -26 10 0 0 \"" + Str.section(':', 1,1) + "\" 1>\n";
00554 
00555     if(Str.section(':', 2,2).right(1) == "F")
00556       Schematic += "<C C2";
00557     else
00558       Schematic += "<L L2";
00559     Schematic += " 1 30 80 17 -26 0 1 \"" + Str.section(':', 2,2) + "\" 1>\n";
00560 
00561     Schematic +=
00562        "<GND * 1 30 110 0 0 0 0>\n"
00563        "</Components>\n"
00564        "<Wires>\n"
00565        "<10 10 30 10 \"\" 0 0 0 \"\">\n"
00566        "<30 10 70 10 \"\" 0 0 0 \"\">\n"
00567        "<30 10 30 50 \"\" 0 0 0 \"\">\n";
00568   }
00569   else {
00570     // ...................................................
00571     // first parallel than serial component
00572 
00573     if(Str.section(':', 1,1).right(1) == "F")
00574       Schematic += "<C C1";
00575     else
00576       Schematic += "<L L1";
00577     Schematic += " 1 50 10 -26 10 0 0 \"" + Str.section(':', 1,1) + "\" 1>\n";
00578 
00579     if(Str.section(':', 2,2).right(1) == "F")
00580       Schematic += "<C C2";
00581     else
00582       Schematic += "<L L2";
00583     Schematic += " 1 130 70 17 -26 0 1 \"" + Str.section(':', 2,2) + "\" 1>\n";
00584 
00585     Schematic +=
00586        "<GND * 1 130 100 0 0 0 0>\n"
00587        "</Components>\n"
00588        "<Wires>\n"
00589        "<130 10 130 40 \"\" 0 0 0 \"\">\n"
00590        "<130 10 150 10 \"\" 0 0 0 \"\">\n"
00591        "<80 10 130 10 \"\" 0 0 0 \"\">\n";
00592   }
00593 
00594   Schematic += QString(
00595      "</Wires>\n"
00596      "<Diagrams>\n"
00597      "</Diagrams>\n"
00598      "<Paintings>\n"
00599      "  <Text -20 -10 12 #000000 0 \"%1 Ohm\">\n"
00600      "  <Text 120 -10 12 #000000 0 \"device\">\n"
00601      "</Paintings>\n").arg(Z0);
00602 
00603   QApplication::clipboard()->setText(Schematic, QClipboard::Clipboard);
00604   return true;
00605 }
00606 
00607 // -----------------------------------------------------------------------
00608 // Fundamental calculations for concurrent 2-port matching.
00609 QString MatchDialog::calcBiMatch(double S11real, double S11imag,
00610             double S22real, double S22imag, double DetReal, double DetImag,
00611             double Z0, double Freq)
00612 {
00613   double B = 1.0 + S11real*S11real + S11imag*S11imag
00614                  - S22real*S22real - S22imag*S22imag
00615                  - DetReal*DetReal - DetImag*DetImag;
00616   double Creal = S11real - S22real*DetReal - S22imag*DetImag;
00617   double Cimag = S22real*DetImag - S11imag - S22imag*DetReal;
00618   double Cmag  = 2.0 * (Creal*Creal + Cimag*Cimag);
00619   Creal /= Cmag;
00620   Cimag /= Cmag;
00621 
00622   double Rreal = B*B - 2.0*Cmag;
00623   double Rimag;
00624   if(Rreal < 0.0) {
00625     Rimag = Cimag * B - Creal * sqrt(-Rreal);
00626     Rreal = Creal * B + Cimag * sqrt(-Rreal);
00627   }
00628   else {
00629     Rreal  = B - sqrt(Rreal);
00630     Rimag  = Cimag * Rreal;
00631     Rreal *= Creal;
00632   }
00633 
00634   return calcMatching(Rreal, -Rimag, Z0, Freq);
00635 }
00636 
00637 // -----------------------------------------------------------------------
00638 bool MatchDialog::calc2PortMatch(double S11real, double S11imag,
00639             double S22real, double S22imag, double DetReal, double DetImag,
00640             double Z1, double Z2, double Freq)
00641 {
00642   QString Input = calcBiMatch(S11real, S11imag, S22real, S22imag,
00643                               DetReal, DetImag, Z1, Freq);
00644   if(Input.isEmpty()) return false;
00645 
00646   QString Output = calcBiMatch(S22real, S22imag, S11real, S11imag,
00647                               DetReal, DetImag, Z2, Freq);
00648   if(Output.isEmpty()) return false;
00649 
00650   QString Schematic =
00651       "<Qucs Schematic " PACKAGE_VERSION ">\n"
00652       "<Components>\n";
00653 
00654 
00655   // ...................................................
00656   // create input circuit
00657   if(Input.section(':', 0,0) == "sp") {
00658     // first serial than parallel component
00659 
00660     if(Input.section(':', 1,1).right(1) == "F")
00661       Schematic += "<C C1";
00662     else
00663       Schematic += "<L L1";
00664     Schematic += " 1 -50 10 -26 10 0 0 \"" + Input.section(':', 1,1) + "\" 1>\n";
00665 
00666     if(Input.section(':', 2,2).right(1) == "F")
00667       Schematic += "<C C2";
00668     else
00669       Schematic += "<L L2";
00670     Schematic += " 1 -120 80 17 -26 0 1 \"" + Input.section(':', 2,2) + "\" 1>\n";
00671 
00672     Schematic += "<GND * 1 -120 110 0 0 0 0>\n";
00673   }
00674   else {
00675     // first parallel than serial component
00676 
00677     if(Input.section(':', 1,1).right(1) == "F")
00678       Schematic += "<C C1";
00679     else
00680       Schematic += "<L L1";
00681     Schematic += " 1 -140 10 -26 10 0 0 \"" + Input.section(':', 1,1) + "\" 1>\n";
00682 
00683     if(Input.section(':', 2,2).right(1) == "F")
00684       Schematic += "<C C2";
00685     else
00686       Schematic += "<L L2";
00687     Schematic += " 1 -60 70 17 -26 0 1 \"" + Input.section(':', 2,2) + "\" 1>\n";
00688 
00689     Schematic += "<GND * 1 -60 100 0 0 0 0>\n";
00690   }
00691 
00692 
00693   // ...................................................
00694   // create output circuit
00695   if(Output.section(':', 0,0) == "sp") {
00696     // first serial than parallel component
00697 
00698     if(Output.section(':', 1,1).right(1) == "F")
00699       Schematic += "<C C1";
00700     else
00701       Schematic += "<L L1";
00702     Schematic += " 1 50 10 -26 10 0 0 \"" + Output.section(':', 1,1) + "\" 1>\n";
00703 
00704     if(Output.section(':', 2,2).right(1) == "F")
00705       Schematic += "<C C2";
00706     else
00707       Schematic += "<L L2";
00708     Schematic += " 1 120 80 17 -26 0 1 \"" + Output.section(':', 2,2) + "\" 1>\n";
00709 
00710     Schematic += "<GND * 1 120 110 0 0 0 0>\n";
00711   }
00712   else {
00713     // ...................................................
00714     // first parallel than serial component
00715 
00716     if(Output.section(':', 1,1).right(1) == "F")
00717       Schematic += "<C C1";
00718     else
00719       Schematic += "<L L1";
00720     Schematic += " 1 140 10 -26 10 0 0 \"" + Output.section(':', 1,1) + "\" 1>\n";
00721 
00722     if(Output.section(':', 2,2).right(1) == "F")
00723       Schematic += "<C C2";
00724     else
00725       Schematic += "<L L2";
00726     Schematic += " 1 60 70 17 -26 0 1 \"" + Output.section(':', 2,2) + "\" 1>\n";
00727 
00728     Schematic += "<GND * 1 60 100 0 0 0 0>\n";
00729   }
00730   Schematic += "</Components>\n"
00731                "<Wires>\n";
00732 
00733 
00734   // ...................................................
00735   // create wires for input circuit
00736   if(Input.section(':', 0,0) == "sp") // first serial than parallel component
00737     Schematic +=
00738        "<-140 10 -120 10 \"\" 0 0 0 \"\">\n"
00739        "<-120 10 -80 10 \"\" 0 0 0 \"\">\n"
00740        "<-120 10 -120 50 \"\" 0 0 0 \"\">\n";
00741   else    // first parallel than serial component
00742     Schematic +=
00743        "<-60 10 -60 40 \"\" 0 0 0 \"\">\n"
00744        "<-60 10 -40 10 \"\" 0 0 0 \"\">\n"
00745        "<-110 10 -60 10 \"\" 0 0 0 \"\">\n";
00746 
00747 
00748   // ...................................................
00749   // create wires for output circuit
00750   if(Output.section(':', 0,0) == "sp") // first serial than parallel component
00751     Schematic +=
00752        "<140 10 120 10 \"\" 0 0 0 \"\">\n"
00753        "<120 10 80 10 \"\" 0 0 0 \"\">\n"
00754        "<120 10 120 50 \"\" 0 0 0 \"\">\n";
00755   else    // first parallel than serial component
00756     Schematic +=
00757        "<60 10 60 40 \"\" 0 0 0 \"\">\n"
00758        "<60 10 40 10 \"\" 0 0 0 \"\">\n"
00759        "<110 10 60 10 \"\" 0 0 0 \"\">\n";
00760 
00761   Schematic +=
00762      "</Wires>\n"
00763      "<Diagrams>\n"
00764      "</Diagrams>\n"
00765      "<Paintings>\n"
00766      "  <Text -200 -10 12 #000000 0 \"Port 1\">\n"
00767      "  <Text -20 -10 12 #000000 0 \"device\">\n"
00768      "  <Text 160 -10 12 #000000 0 \"Port 2\">\n"
00769      "</Paintings>\n";
00770 
00771   QApplication::clipboard()->setText(Schematic, QClipboard::Clipboard);
00772   return true;
00773 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines