diff --git a/qucs/qucs/dialogs/matchdialog.cpp b/qucs/qucs/dialogs/matchdialog.cpp index f4d3d69ba9..a01ecbdb2b 100644 --- a/qucs/qucs/dialogs/matchdialog.cpp +++ b/qucs/qucs/dialogs/matchdialog.cpp @@ -6,7 +6,12 @@ email : michael.margraf@alumni.tu-berlin.de copyright : (C) 2012, 2013, 2016 by Qucs Team (see AUTHORS file) - Upgrade (2016) : Andres Martinez-Mera + 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 + Claudio Girardi ***************************************************************************/ /*************************************************************************** @@ -718,7 +723,7 @@ void MatchDialog::slotButtCreate() bool SP_block = AddSPBlock->isChecked(); // Add S-parameter block? bool open_short = OpenRadioButton->isChecked(); // Open stub or short circuit stub configuration int order = OrderEdit->text().toInt()+1; // Order of the multisection lambda/4 matching - + bool success = true; double gamma_MAX = MaxRippleEdit->text().toDouble(); // Maximum ripple (Chebyshev weighting only) tSubstrate Substrate; @@ -740,13 +745,13 @@ void MatchDialog::slotButtCreate() - S12real*S21real + S12imag*S21imag; double DetImag = S11real*S22imag + S11imag*S22real - S12real*S21imag - S12imag*S21real; - calc2PortMatch(S11real, S11imag, S22real, S22imag, DetReal, DetImag, Z1, Z2, Freq, micro_syn, SP_block, open_short, Substrate, order, gamma_MAX, BalancedStubs); + success = calc2PortMatch(S11real, S11imag, S22real, S22imag, DetReal, DetImag, Z1, Z2, Freq, micro_syn, SP_block, open_short, Substrate, order, gamma_MAX, BalancedStubs); } else{ - calcMatchingCircuit(S11real, S11imag, Z1, Freq, micro_syn, SP_block, open_short, Substrate, order, gamma_MAX, BalancedStubs); + success = calcMatchingCircuit(S11real, S11imag, Z1, Freq, micro_syn, SP_block, open_short, Substrate, order, gamma_MAX, BalancedStubs); } - QucsMain->slotEditPaste(true); + QucsMain->slotEditPaste(success); accept(); } @@ -837,15 +842,15 @@ QString MatchDialog::calcMatchingLC(double r_real, double r_imag, double Z0, dou QString laddercode="", series_element, shunt_element; // serial component if (X1 < 0.0) // capacitance ? - series_element = QString("CS%1;").arg(-1.0 / Omega / X1); + series_element = QString("CS:%1;").arg(-1.0 / Omega / X1); else // inductance - series_element = QString("LS%1;").arg(X1 / Omega); + series_element = QString("LS:%1;").arg(X1 / Omega); // parallel component if (X2 < 0.0) // inductance ? - shunt_element = QString("LP%1;").arg(-1.0 / Omega / X2); + shunt_element = QString("LP:%1;").arg(-1.0 / Omega / X2); else // capacitance - shunt_element = QString("CP%1;").arg(X2 / Omega); + shunt_element = QString("CP:%1;").arg(X2 / Omega); (r_real < 0) ? laddercode = shunt_element + series_element: laddercode = series_element + shunt_element; @@ -853,180 +858,62 @@ QString MatchDialog::calcMatchingLC(double r_real, double r_imag, double Z0, dou } -// ---------------------------------------------------------------------------------- -// This function calculates a matching network for a single port using a transmission line and -// a stub (short or open). It can also convert the transmission lines microstrip lines -// See Microwave Engineering. David Pozar. John Wiley and Sons. 4th Edition. Pg 234-240 -bool MatchDialog::calcMatchingCircuitSingleStub(double r_real, double r_imag, double Z0, double Freq, bool microsyn, bool SP_Block, bool open_short, tSubstrate Substrate, bool BalancedStubs) -{ - QString laddercode = calcSingleStub(r_real, r_imag, Z0, Freq, open_short, BalancedStubs); - double RL=r_real, XL=r_imag; - int schcode=-1; - r2z(RL, XL, Z0); - QString Schematic = "\n"; - - if (SP_Block) schcode = 3; - - int x_pos = 0; - QString wirestr = ""; - QString componentstr = ""; - QString paintingstr = ""; - SchematicParser(laddercode, x_pos, componentstr, wirestr, paintingstr, schcode, Freq, Z0, RL, XL, Substrate, microsyn); - - return CreateSchematic(componentstr, wirestr, paintingstr); -} - -// ---------------------------------------------------------------------------------- -// This function calculates a matching network for a single port using a transmission line and -// two stubs (short or open). It can also convert the transmission lines microstrip lines -// See Microwave Engineering. David Pozar. John Wiley and Sons. 4th Edition. Pg 241-245 -bool MatchDialog::calcMatchingCircuitDoubleStub(double r_real, double r_imag, double Z0, double Freq, bool microsyn, bool SP_Block, bool open_short, tSubstrate Substrate, bool BalancedStubs) -{ - QString laddercode = calcDoubleStub(r_real, r_imag, Z0, Freq, open_short, BalancedStubs); - double RL=r_real, XL=r_imag; - int schcode = -1; - r2z(RL, XL, Z0); - QString Schematic = "\n"; - - if (SP_Block) schcode = 3; - - int x_pos = 0; - QString wirestr = ""; - QString componentstr = ""; - QString paintingstr = ""; - SchematicParser(laddercode, x_pos, componentstr, wirestr, paintingstr, schcode, Freq, Z0, RL, XL, Substrate, microsyn); - - return CreateSchematic(componentstr, wirestr, paintingstr); -} - - -// ---------------------------------------------------------------------------------- -// This function calculates a matching network for a single port using cascaded sections -// of lambda/4 lines. It can also convert these lines microstrip lines -// See Microwave Engineering. David Pozar. John Wiley and Sons. 4th Edition. Pg 252-256 -bool MatchDialog::calcMatchingCircuitCascadedLambda4(double r_real, double r_imag, double Z0, double Freq, bool microsyn, bool SP_Block, tSubstrate Substrate, double gamma, int order) -{ - QString laddercode; - (BinRadio->isChecked()) ? laddercode = calcBinomialLines(r_real, r_imag, Z0, order, Freq) : laddercode = calcChebyLines(r_real, r_imag, Z0, gamma, order, Freq); - double RL = r_real, XL=r_imag; - int schcode = -1; - r2z(RL, XL, Z0); - - QString Schematic = "\n"; - - if (SP_Block) schcode = 3; - - int x_pos = 0; - QString wirestr = ""; - QString componentstr = ""; - QString paintingstr = ""; - SchematicParser(laddercode, x_pos, componentstr, wirestr, paintingstr, schcode, Freq, Z0, RL, XL, Substrate, microsyn); - - return CreateSchematic(componentstr, wirestr, paintingstr); -} - - // ----------------------------------------------------------------------- // This function calls the specific matching network function so as to get the desired matching topology -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) +// Returns true if the synthesis worked as expected or false if it wasn't +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: // LC - if(!calcMatchingCircuitLC(S11real, S11imag, Z0, Freq, SP_block))return false; + laddercode = calcMatchingLC(S11real, S11imag, Z0, Freq);//It calculates the LC matching circuit. break; case 1: // Single stub - if(!calcMatchingCircuitSingleStub(S11real, S11imag, Z0, Freq, micro_syn, SP_block, open_short, Substrate, BalancedStubs))return false; + laddercode = calcSingleStub(S11real, S11imag, Z0, Freq, open_short, BalancedStubs); break; case 2: // Double stub - if(!calcMatchingCircuitDoubleStub(S11real, S11imag, Z0, Freq, micro_syn, SP_block, open_short, Substrate, BalancedStubs))return false; + laddercode = calcDoubleStub(S11real, S11imag, Z0, Freq, open_short, BalancedStubs); break; case 3: // Quarter wave cascaded sections - if(!calcMatchingCircuitCascadedLambda4(S11real, S11imag, Z0, Freq, micro_syn, SP_block, Substrate, gamma_MAX, order))return false; + (BinRadio->isChecked()) ? laddercode = calcBinomialLines(S11real, S11imag, Z0, order, Freq) : laddercode = calcChebyLines(S11real, S11imag, Z0, gamma_MAX, order, Freq); break; case 4: // Cascaded LC sections - if(!calcMatchingCircuitCascadedLCSections(S11real, S11imag, Z0, Freq, SP_block, order))return false; + laddercode = calcMatchingCascadedLCSections(S11real, S11imag, Z0, Freq, order-1); break; case 5: // Lambda/8 + Lambda/4 impedance transformer - if(!calcMatchingCircuitLambda8Lambda4(S11real, S11imag, Z0, Freq, SP_block))return false; + // Reference: Inder J. Bahl. "Fundamentals of RF and microwave transistor amplifiers". + // John Wiley and Sons. 2009. Pages 159-160 + laddercode = calcMatchingLambda8Lambda4(S11real, S11imag, Z0, Freq); break; } - return true; -} - -// ----------------------------------------------------------------------- -// This function calculates one port LC matching -bool MatchDialog::calcMatchingCircuitLC(double r_real, double r_imag, double Z0, double Freq, bool SP_Block) -{ - QString laddercode = calcMatchingLC(r_real, r_imag, Z0, Freq);//It calculates the LC matching circuit. - double RL=r_real, XL=r_imag; - int schcode=-1; - r2z(RL, XL, Z0); - - //Header - QString Schematic = "\n"; - - if (SP_Block) schcode = 3; - - int x_pos = 0; + if (laddercode.isEmpty()) return false; + + double RL=S11real, XL=S11imag; QString wirestr = ""; QString componentstr = ""; QString paintingstr = ""; - tSubstrate Subs; - - SchematicParser(laddercode, x_pos, componentstr, wirestr, paintingstr, schcode, Freq, Z0, RL, XL, Subs, false); - - return CreateSchematic(componentstr, wirestr, paintingstr); -} - - - -//------------------------------------------------------------------------ -//This function generates the Qucs schematic of a cascaded LC matching network -// Reference: Inder J. Bahl. "Fundamentals of RF and microwave transistor amplifiers". John Wiley and Sons. 2009. Pages 169 - 170 -bool MatchDialog::calcMatchingCircuitCascadedLCSections(double r_real, double r_imag, double Z0, double Freq, bool SP_Block, int N) -{ - QString laddercode = calcMatchingCascadedLCSections(r_real, r_imag, Z0, Freq, N-1); - double RL=r_real, XL=r_imag; - int schcode = -1; - r2z(RL, XL, Z0); - - //Header - QString Schematic = "\n"; - - if (SP_Block) schcode = 3; - int x_pos = 0; - QString wirestr = ""; - QString componentstr = ""; - QString paintingstr = ""; - tSubstrate Subs; - SchematicParser(laddercode, x_pos, componentstr, wirestr, paintingstr, schcode, Freq, Z0, RL, XL, Subs, false); - - return CreateSchematic(componentstr, wirestr, paintingstr); -} -//------------------------------------------------------------------------ -// This function generates the Qucs schematic of a lambda/4 + lambda/8 transformer -// Reference: Inder J. Bahl. "Fundamentals of RF and microwave transistor amplifiers". John Wiley and Sons. 2009. Pages 159-160 -bool MatchDialog::calcMatchingCircuitLambda8Lambda4(double r_real, double r_imag, double Z0, double Freq, bool SP_Block) -{ - QString laddercode = calcMatchingLambda8Lambda4(r_real, r_imag, Z0, Freq); - double RL=r_real, XL=r_imag; - int schcode = -1; r2z(RL, XL, Z0); + RL = round(RL*1e2)/1e2;//Rounding to 2 decimals (just for painting purposes) + XL = round(XL*1e2)/1e2; + + if (SP_Block) + { + laddercode.append("S2P:Freq;"); + laddercode.prepend(QString("P1:%1;").arg(Z0)); + laddercode.append(QString("ZL:%1#%2;").arg(RL).arg(XL)); + } + else//Add tags instead of a S-param simulation + { + laddercode.prepend("LBL:Port 1;"); + laddercode.append("LBL:Port 2;"); + } + SchematicParser(laddercode, x_pos, Freq, Substrate, micro_syn); + return true;//The schematic was successfully created - if (SP_Block) schcode = 3; - - int x_pos = 0; - QString wirestr = ""; - QString componentstr = ""; - QString paintingstr = ""; - tSubstrate Subs; - SchematicParser(laddercode, x_pos, componentstr, wirestr, paintingstr, schcode, Freq, Z0, RL, XL, Subs, false); - - return CreateSchematic(componentstr, wirestr, paintingstr); } // ----------------------------------------------------------------------- @@ -1097,34 +984,32 @@ bool MatchDialog::calc2PortMatch(double S11real, double S11imag, // The result is a string which gives the structure of the matching network QString InputLadderCode = calcBiMatch(S11real, S11imag, S22real, S22imag, DetReal, DetImag, Z1, Freq, open_short, gamma_MAX, order, BalancedStubs); - if(InputLadderCode.isEmpty()) return false; + if(InputLadderCode.isEmpty()) return false;//Synthesis error // Output port network QString OutputLadderCode = calcBiMatch(S22real, S22imag, S11real, S11imag, DetReal, DetImag, Z2, Freq, open_short, gamma_MAX, order, BalancedStubs); - if(OutputLadderCode.isEmpty()) return false; + if(OutputLadderCode.isEmpty()) return false;//Synthesis error else OutputLadderCode = flipLadderCode(OutputLadderCode); - int schcode = -1; - if (SP_Block) schcode = 0; + if (SP_Block) + { + InputLadderCode.prepend(QString("S2P:%1;").arg(Freq));//Add the s-param simulation to the circuit code + InputLadderCode.prepend(QString("P1:%1;").arg(Z1));//Port 1 + OutputLadderCode.append(QString("P2:%1;").arg(Z2));//Port 2 + } + else + {//Use labels instead of the S-param simulation + InputLadderCode.prepend(QString("LBL:Port 1;"));//Port 1 + OutputLadderCode.append(QString("LBL:Port 2;"));//Port 2 + } + QString laddercode = InputLadderCode + QString("DEV:0") + OutputLadderCode; int x_pos = 0; - QString input_wirestr = "", output_wirestr = ""; - QString input_componentstr = "", output_componentstr = ""; - QString paintingstr = ""; - - if (schcode == -1) paintingstr += QString("\n").arg(x_pos);//Add 'Port 1' label - x_pos += 50; - SchematicParser(InputLadderCode, x_pos, input_componentstr, input_wirestr, paintingstr, schcode, Freq, Z1, 50, 0, Substrate, microsyn); - if (SP_Block) schcode = 2; - paintingstr += QString("\n").arg(x_pos+70);//Add 'Device' label - paintingstr += QString("\n").arg(x_pos+50);//Box surrounding the 'Device' label - x_pos += 200; - SchematicParser(OutputLadderCode, x_pos, output_componentstr, output_wirestr, paintingstr, schcode, Freq, 0, Z2, 0, Substrate, microsyn); - if (schcode == -1) paintingstr += QString("\n").arg(x_pos+50);//Add 'Port 2' label - return CreateSchematic(input_componentstr + output_componentstr, input_wirestr+output_wirestr, paintingstr); + SchematicParser(laddercode, x_pos, Freq, Substrate, microsyn); + return true; } @@ -1270,7 +1155,7 @@ void MatchDialog::getMicrostrip(double Z0, double freq, tSubstrate *substrate, //-------------------------------------------------------------------------------- // Calculates a matching network according to the stub+line method -// See Microwave Engineering. David Pozar. John Wiley and Sons. 4th Edition. Pg 234-241 +// Reference: 'Microwave Engineering'. David Pozar. John Wiley and Sons. 4th Edition. Pg 234-241 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; @@ -1337,10 +1222,10 @@ QString MatchDialog::calcSingleStub(double r_real, double r_imag, double Z0, dou //String code QString laddercode; - if ((open_short) && (!BalancedStubs)) laddercode = QString("OL%1#%2;TL%1#%3;").arg(Z0).arg(lstub).arg(d);//Line + Open stub - if ((open_short) && (BalancedStubs)) laddercode = QString("OU%1#%2;OL%1#%2;TL%1#%3;").arg(Z0).arg(lstub).arg(d);//Open circuit balanced stubs - if ((!open_short) && (!BalancedStubs)) laddercode = QString("SL%1#%2;TL%1#%3;").arg(Z0).arg(lstub).arg(d);//Line + Short circuited stub - if ((!open_short) && (BalancedStubs)) laddercode = QString("SU%1#%2;SL%1#%2;TL%1#%3;").arg(Z0).arg(lstub).arg(d);//Short circuited balanced stubs + if ((open_short) && (!BalancedStubs)) laddercode = QString("OL:%1#%2;TL:%1#%3;").arg(Z0).arg(lstub).arg(d);//Line + Open stub + if ((open_short) && (BalancedStubs)) laddercode = QString("OU:%1#%2;OL:%1#%2;TL:%1#%3;").arg(Z0).arg(lstub).arg(d);//Open circuit balanced stubs + if ((!open_short) && (!BalancedStubs)) laddercode = QString("SL:%1#%2;TL:%1#%3;").arg(Z0).arg(lstub).arg(d);//Line + Short circuited stub + if ((!open_short) && (BalancedStubs)) laddercode = QString("SU:%1#%2;SL:%1#%2;TL:%1#%3;").arg(Z0).arg(lstub).arg(d);//Short circuited balanced stubs return laddercode; @@ -1349,7 +1234,7 @@ QString MatchDialog::calcSingleStub(double r_real, double r_imag, double Z0, dou //-------------------------------------------------------------------------------- // Calculates a matching network according to the stub+line+stub method -// See Microwave Engineering. David Pozar. John Wiley and Sons. 4th Edition. Pg 241-245 +// Reference: 'Microwave Engineering', David Pozar. John Wiley and Sons. 4th Edition. Pg 241-245 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; @@ -1405,10 +1290,10 @@ QString MatchDialog::calcDoubleStub(double r_real, double r_imag, double Z0, dou } QString laddercode; - if ((open_short)&&(BalancedStubs))laddercode = QString("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 = QString("OL%1#%2;TL%1#%3;OL%1#%4").arg(Z0).arg(lstub2).arg(d).arg(lstub1); - if ((!open_short)&&(BalancedStubs))laddercode = QString("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 = QString("SL%1#%2;TL%1#%3;SL%1#%4").arg(Z0).arg(lstub2).arg(d).arg(lstub1); + if ((open_short)&&(BalancedStubs))laddercode = QString("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 = QString("OL:%1#%2;TL:%1#%3;OL:%1#%4").arg(Z0).arg(lstub2).arg(d).arg(lstub1); + if ((!open_short)&&(BalancedStubs))laddercode = QString("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 = QString("SL:%1#%2;TL:%1#%3;SL:%1#%4").arg(Z0).arg(lstub2).arg(d).arg(lstub1); return laddercode; @@ -1429,7 +1314,7 @@ int BinomialCoeffs(int n, int k) //----------------------------------------------------------------------------------- // This function calculates a multistage lambda/4 matching using binomial weigthing -// See Microwave Engineering. David Pozar. John Wiley and Sons. 4th Edition. Pg 252-256 +// Reference: 'Microwave Engineering'. David Pozar. John Wiley and Sons. 4th Edition. Pg 252-256 QString MatchDialog::calcBinomialLines(double r_real, double r_imag, double Z0, int order, double Freq) { double RL = r_real, XL = r_imag; @@ -1453,14 +1338,14 @@ QString MatchDialog::calcBinomialLines(double r_real, double r_imag, double Z0, Ci = BinomialCoeffs(order-1, i-1); Zi = exp(log(Zaux) + (Ci/pow(2,order-1))*log(RL/Z0)); Zaux=Zi; - laddercode+=QString("TL%1#%2;").arg(Zi).arg(l4); + laddercode+=QString("TL:%1#%2;").arg(Zi).arg(l4); } return laddercode; } //----------------------------------------------------------------------------------- // This function calculates a multistage lambda/4 matching using the Chebyshev weigthing. -// See Microwave Engineering. David Pozar. John Wiley and Sons. 4th Edition. Pg 256-261 +// Reference 'Microwave Engineering'. David Pozar. John Wiley and Sons. 4th Edition. Pg 256-261 QString MatchDialog::calcChebyLines(double r_real, double r_imag, double Z0, double gamma, int order, double Freq) { int N = order-1;// Number of sections @@ -1531,7 +1416,7 @@ QString MatchDialog::calcChebyLines(double r_real, double r_imag, double Z0, dou { (RL RS)//Flip string { @@ -1600,86 +1487,23 @@ QString MatchDialog::calcMatchingLambda8Lambda4(double r_real, double r_imag, do r2z(RL, XL, Z0); double Zmm = sqrt(RL*RL+XL*XL); double Zm = sqrt((Z0*RL*Zmm)/(Zmm-XL)); - return QString("TL%1#%2;TL%3#%4").arg(Zm).arg(l4).arg(Zmm).arg(l8); + return QString("TL:%1#%2;TL:%3#%4").arg(Zm).arg(l4).arg(Zmm).arg(l8); } -//----------------------------------------------------------------------------- -// Given the components, wires and paintings, it creates the schematic and copies on the clipboard -bool MatchDialog::CreateSchematic(QString components, QString wires, QString paintings) -{ - //Header - QString Schematic = "\n"; - - //Add components - Schematic += "\n"; - Schematic+=components; - Schematic += "\n"; - - //Add wires - Schematic+= "\n"; - Schematic += wires; - Schematic+= "\n"; - - //Add paintings - Schematic += "\n"; - Schematic += paintings; - Schematic += "\n"; - - QApplication::clipboard()->setText(Schematic, QClipboard::Clipboard); - return true; -} - -// Given a string code of inductors, capacitors and transmission lines, it generates the Qucs network. Notice that the schematic is split into -// three part: components, wires and paintings, all of them are passed by reference. -int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & componentstr, QString & wirestr, QString & paintingstr, int schcode, double Freq, double Z0, double RL, double XL, tSubstrate Substrate, bool microsyn) +// Given a string code of inductors, capacitors and transmission lines, it generates the Qucs network. Notice that the schematic is split into three parts: components, wires and paintings, all of them are passed by reference. +void MatchDialog::SchematicParser(QString laddercode, int & x_pos, double Freq, tSubstrate Substrate, bool microsyn) { QStringList strlist = laddercode.split(";"); - QString component; - bool isSinglePort = paintingstr.isEmpty(); + QString component, tag, label; + qDebug() << laddercode; double value, value2, er, width; int x_series = 120, x_shunt = 20;//x-axis spacing depending on whether the component is placed in a series or shunt configuration - //Clear input strings (just in case) - componentstr = ""; - wirestr = ""; - - - RL = round(RL*1e2)/1e2; - XL = round(XL*1e2)/1e2; - - // Schematic code - // 0: Port 1 + S parameter simulation - // 1: Port 1 - // 2: Port 2 - // 3: Port 1, Port 2 and S parameter simulation - - if ((schcode == 1)||(schcode == 0) || (schcode == 3))//Port 1 - { - QString val_Z0 = misc::num2str(Z0, 2) + "Ohm"; - componentstr += QString("\n").arg(val_Z0).arg(x_pos); - componentstr += QString("\n").arg(x_pos); - wirestr += QString("<%1 -60 %1 -120>\n").arg(x_pos); - wirestr += QString("<%1 -120 %2 -120>\n").arg(x_pos).arg(x_pos+120); - x_pos +=120; - } - - if ((schcode == 0) || (schcode == 3))//Add S parameter simulation - { - //Add the frequency range for the S-param simulation - double freq_start = std::max(0., Freq-1e9); - double freq_stop = Freq+1e9; - componentstr += QString("<.SP SP1 1 0 100 0 67 0 0 \"lin\" 1 \"%2Hz\" 1 \"%3Hz\" 1 \"300\" 1 \"no\" 0 \"1\" 0 \"2\" 0>\n").arg((freq_start)).arg((freq_stop)); - if (XL != 0) componentstr += QString("\n"); - else componentstr += QString("\n"); - } - - if ((isSinglePort) && (schcode == -1)) - { - paintingstr += QString("\n").arg(x_pos-50);//Add 'Port 1' label - } + //Clear schematic strings + QString componentstr = "", wirestr = "", paintingstr = ""; -// The string format is as follows: "XX;XX;...XX;" + // The string format is as follows: "XX;XX;...XX;" // where XX, YY, ZZ define the type of component and its configuration. // LS: Series inductance // CS: Series capacitor @@ -1690,22 +1514,72 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp // OL: Open stub (facing down) // SU: Short circuited stub (facing up) // SL: Short circuited stub (facing down) +// P1: Port 1 +// LBL: LBL +// P2: Port 2 +// DEV: Device label +// S2P: S-param simulation block for (int i = 0; i < strlist.count(); i++) { + // Each token of the string descriptor has the following format: 'tag:;''tag:#;' + //First, extract the tag component = strlist.at(i); + int index_colon = component.indexOf(":"); + tag = component.mid(0, index_colon); + + //Now we remove the tag and the colon from the string + component.remove(0, index_colon+1); + //At this point, we have the component parameters. In case of having more than one parameter, they are separated by # int index = component.indexOf("#"); //Transmission lines are characterised by its impedance and its length whereas capacitors and inductors only depend on // its capacitance and inductance, respectively. So, the code below is aimed to handle such difference if (index != -1)//The component has two values { - value = component.mid(2, index-2).toDouble(); + value = component.mid(0, index).toDouble(); value2 = component.mid(index+1).toDouble(); } - else value = component.mid(2).toDouble(); - component = component.mid(0, 2); + else + { + if (!tag.compare("LBL"))//The value is a string + { + label = component; + } + else//The value is a double number. For a clearer representation in the schematic, it will be rounded off to 2 decimal positions + { + value = component.toDouble(); + } + } - if (!component.compare("LS"))//Series inductor + // The following if-else structure is responsible for placing the components, wires and paintings in the schematic + if (!tag.compare("P1"))//Port 1 component + { + componentstr += QString("\n").arg(value).arg(x_pos); + componentstr += QString("\n").arg(x_pos); + wirestr += QString("<%1 -60 %1 -120>\n").arg(x_pos); + wirestr += QString("<%1 -120 %2 -120>\n").arg(x_pos).arg(x_pos+120); + x_pos +=120; + } + else if (!tag.compare("LBL"))//Label + { + paintingstr += QString("\n").arg(x_pos).arg(component);//Add 'Port 1' or 'Port 2' label + x_pos += 50; + } + else if (!tag.compare("P2"))//Port 2 component (it need to be different from P1 because of the wiring) + { + x_pos += 100; + componentstr += QString("\n").arg(value).arg(x_pos); + componentstr += QString("\n").arg(x_pos); + wirestr += QString("<%1 -60 %1 -120>\n").arg(x_pos);//Vertical wire + wirestr += QString("<%1 -120 %2 -120>\n").arg(x_pos-100).arg(x_pos);//Horizontal wire + } + else if(!tag.compare("DEV"))//Device painting + { + paintingstr += QString("\n").arg(x_pos+70);//Add 'Device' label + paintingstr += QString("\n").arg(x_pos+50);//Box surrounding the 'Device' label + x_pos += 200; + } + else if (!tag.compare("LS"))//Series inductor { QString val = misc::num2str(value, 2) + "H";//Add suffix nH, uH and round off to 2 decimals componentstr += QString("\n").arg(x_pos+60).arg(val); @@ -1713,7 +1587,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos+90).arg(x_pos+x_series); x_pos += x_series; } - else if (!component.compare("CS"))//Series capacitor + else if (!tag.compare("CS"))//Series capacitor { QString val = misc::num2str(value, 2) + "F";//Add suffix pF, nF and round off to 2 decimals componentstr += QString("\n").arg(x_pos+60).arg(val); @@ -1721,7 +1595,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos+90).arg(x_pos+x_series); x_pos += x_series; } - else if (!component.compare("LP"))//Shunt inductor + else if (!tag.compare("LP"))//Shunt inductor { QString val = misc::num2str(value, 2) + "H";//Add suffix nH, uH and round off to 2 decimals componentstr += QString("\n").arg(x_pos); @@ -1730,7 +1604,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos-20).arg(x_pos+x_shunt); x_pos += x_shunt; } - else if (!component.compare("CP"))//Shunt capacitor + else if (!tag.compare("CP"))//Shunt capacitor { QString val = misc::num2str(value, 2) + "F";//Add suffix pF, nF and round off to 2 decimals componentstr += QString("\n").arg(x_pos); @@ -1739,7 +1613,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos-20).arg(x_pos+x_shunt); x_pos += x_shunt; } - else if (!component.compare("TL"))//Transmission line + else if (!tag.compare("TL"))//Transmission line { if (microsyn)//Microstrip implementation { @@ -1759,7 +1633,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos+90).arg(x_pos+x_series); x_pos += x_series; } - else if (!component.compare("OU"))//Open stub (upper) + else if (!tag.compare("OU"))//Open stub (upper) { if (microsyn)//Microstrip implementation { @@ -1779,7 +1653,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos).arg(x_pos+x_shunt); //Here x_pos is not incremented since upper stubs does not overlap any other component } - else if (!component.compare("OL"))//Open stub (lower) + else if (!tag.compare("OL"))//Open stub (lower) { if (microsyn)//Microstrip implementation { @@ -1799,7 +1673,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos-20).arg(x_pos+x_shunt); x_pos += x_shunt; } - else if (!component.compare("SU"))//Short circuited stub (upper) + else if (!tag.compare("SU"))//Short circuited stub (upper) { if (microsyn)//Microstrip implementation { @@ -1820,7 +1694,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos).arg(x_pos+x_shunt); //Here x_pos is not incremented since upper stubs does not overlap any other component } - else if (!component.compare("SL"))//Short circuited stub (lower) + else if (!tag.compare("SL"))//Short circuited stub (lower) { if (microsyn)//Microstrip implementation { @@ -1841,23 +1715,24 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp wirestr += QString("<%1 -120 %2 -120 "" 0 0 0 "">\n").arg(x_pos-20).arg(x_pos+x_shunt); x_pos += x_shunt; } - - } - - if ((schcode == 2)|| (schcode == 3))//Port 2 - { - x_pos += 100; - if (fabs(XL) < 1e-3)//The load is real so we can use a conventional port + else if (!tag.compare("S2P"))//S-param simulation block { - QString val_Res = misc::num2str(RL, 2) + "Ohm"; - componentstr += QString("\n").arg(val_Res).arg(x_pos); - componentstr += QString("\n").arg(x_pos); - wirestr += QString("<%1 -60 %1 -120>\n").arg(x_pos);//Vertical wire - wirestr += QString("<%1 -120 %2 -120>\n").arg(x_pos-100).arg(x_pos);//Horizontal wire + //Add the frequency range for the S-param simulation + double freq_start = std::max(0., value-1e9); + double freq_stop = Freq+1e9; + componentstr += QString("<.SP SP1 1 0 100 0 67 0 0 \"lin\" 1 \"%2Hz\" 1 \"%3Hz\" 1 \"300\" 1 \"no\" 0 \"1\" 0 \"2\" 0>\n").arg((freq_start)).arg((freq_stop)); + + if (laddercode.indexOf("P2") == -1) //One port simulation + componentstr += QString("\n"); + else //Two ports simulation + componentstr += QString("\n"); } - else//The load has a reactive part... Since Qucs cannot handle complex ports we can use a tuned load, valid for narrowband + else if (!tag.compare("ZL"))//Complex load { - if ((RL > 1e-3)&&(XL < 1e-3))// R + C + double RL = value; + double XL = value2; + x_pos += 100; + if ((RL > 1e-3)&&(XL < -1e-3))// R + C { QString val_Res = misc::num2str(RL, 2) + "Ohm"; QString val_Cap = misc::num2str(1/(fabs(XL)*2*pi*Freq), 2) + "F";//Need to use abs() because XL < 0 @@ -1865,7 +1740,7 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp componentstr += QString("\n").arg(x_pos).arg(val_Cap); paintingstr += QString("\n").arg(x_pos).arg(QChar (0x2126)).arg(Freq*1e-9).arg(RL).arg(fabs(XL)); } - if ((RL > 1e-3)&&(XL > 1e-3))//R + L + else if ((RL > 1e-3)&&(XL > 1e-3))//R + L { QString val_Res = misc::num2str(RL, 2) + "Ohm"; QString val_Ind = misc::num2str(XL/(2*pi*Freq), 2) + "H"; @@ -1873,21 +1748,21 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp componentstr += QString("\n").arg(x_pos).arg(val_Ind); paintingstr += QString("\n").arg(x_pos).arg(QChar (0x2126)).arg(Freq*1e-9).arg(RL).arg(XL); } - if ((RL > 1e-3)&&(fabs(XL) < 1e-3))//R + else if ((RL > 1e-3)&&(fabs(XL) < 1e-3))//R { QString val_Res = misc::num2str(RL, 2) + "Ohm"; componentstr += QString("\n").arg(x_pos).arg(val_Res); wirestr += QString("<%1 -60 %1 -120>\n").arg(x_pos);//Vertical wire paintingstr += QString("\n").arg(x_pos).arg(QChar (0x2126)).arg(Freq*1e-9).arg(RL); } - if ((RL < 1e-3)&&(XL > 1e-3))//L + else if ((RL < 1e-3)&&(XL > 1e-3))//L { QString val_Ind = misc::num2str(XL/(2*pi*Freq), 2) + "H"; componentstr += QString("\n").arg(x_pos).arg(val_Ind); wirestr += QString("<%1 -60 %1 -120>\n").arg(x_pos);//Vertical wire paintingstr += QString("\n").arg(x_pos).arg(QChar (0x2126)).arg(Freq*1e-9).arg(XL); } - if ((RL < 1e-3)&&(XL < 1e-3))//C + else if ((RL < 1e-3)&&(XL < -1e-3))//C { QString val_Cap = misc::num2str(1/(fabs(XL)*2*pi*Freq), 2) + "F";//Need to use abs() because XL < 0 componentstr += QString("\n").arg(x_pos).arg(val_Cap); @@ -1901,13 +1776,30 @@ int MatchDialog::SchematicParser(QString laddercode, int & x_pos, QString & comp paintingstr += QString("\n").arg(x_pos-30); } } - if ((isSinglePort) && (schcode == -1)) - { - paintingstr += QString("\n").arg(x_pos+50);//Add 'Port 2' label - } + + // Substrate if (microsyn)componentstr += QString("\n").arg(Substrate.er).arg(Substrate.height*1e3).arg(Substrate.thickness*1e6).arg(Substrate.tand).arg(Substrate.resistivity).arg(Substrate.roughness); - return 0; + //Header + QString Schematic = "\n"; + + //Add components + Schematic += "\n"; + Schematic+=componentstr; + Schematic += "\n"; + + //Add wires + Schematic+= "\n"; + Schematic += wirestr; + Schematic+= "\n"; + + //Add paintings + Schematic += "\n"; + Schematic += paintingstr; + Schematic += "\n"; + + QApplication::clipboard()->setText(Schematic, QClipboard::Clipboard); + } diff --git a/qucs/qucs/dialogs/matchdialog.h b/qucs/qucs/dialogs/matchdialog.h index 188bdd75b0..4b8835e85e 100644 --- a/qucs/qucs/dialogs/matchdialog.h +++ b/qucs/qucs/dialogs/matchdialog.h @@ -21,6 +21,7 @@ #include #include #include +#include class Element; @@ -78,38 +79,26 @@ class MatchDialog : public QDialog { static void z2r(double&, double&, double); bool calcMatchingCircuit(double, double,double, double, bool, bool, bool, tSubstrate, int, double, bool); - + enum SchematicCode {SNG_PORT, SNG_PORT_SPAR_SIM, DBL_PORT, DBL_PORT_SPAR_SIM}; + //------------------------------------------------------------------------------------------------------- + // These functions calculate the specified matching network and and generate the circuit description code QString calcMatchingLC(double, double, double, double); - bool calcMatchingCircuitLC(double, double, double, double, bool); - QString calcMatchingCascadedLCSections(double, double, double, double, int); - bool calcMatchingCircuitCascadedLCSections(double, double, double, double, bool, int); - - bool calcMatchingCircuitSingleStub(double, double, double, double, bool, bool, bool, tSubstrate, bool); QString calcSingleStub(double, double, double, double, bool, bool); - - bool calcMatchingCircuitDoubleStub(double RL, double XL, double, double, bool, bool, bool, tSubstrate, bool); QString calcDoubleStub(double, double, double, double, bool, bool); - - bool calcMatchingCircuitLambda8Lambda4(double, double, double, double, bool); QString calcMatchingLambda8Lambda4(double, double, double, double); - - - bool calcMatchingCircuitCascadedLambda4(double, double, double, double, bool, bool, tSubstrate, double, int); - QString calcBinomialLines(double, double, double, int, double); QString calcChebyLines(double, double, double, double, int, double); + //-------------------------------------------------------------------------------------------------------- + QString calcBiMatch(double, double, double, double, double, double, double, double, bool, double, int, bool); bool calc2PortMatch(double, double, double, double, double, double, double, double, double, bool, bool, bool, tSubstrate, int, double, bool); - int SchematicParser(QString, int &, QString &, QString &, QString & ,int, double, double, double, double, tSubstrate, bool); + void SchematicParser(QString, int &, double, tSubstrate, bool);// This function convert the circuit description code into a Qucs schematic - bool CreateSchematic(QString, QString, QString); void getMicrostrip(double, double, tSubstrate *, double &, double &); - - void setFrequency(double); void setTwoPortMatch(bool on) { TwoCheck->setChecked(on); TwoCheck->setEnabled(false); }