Qucs-S S-parameter Viewer & RF Synthesis Tools
Loading...
Searching...
No Matches
SParameterCalculator.h
1/*
2 * Copyright (C) 2025 Andrés Martínez Mera - andresmmera@protonmail.com
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#ifndef SPARAMETERCALCULATOR_H
19#define SPARAMETERCALCULATOR_H
20
21#include <QFile>
22#include <QList>
23#include <QMap>
24#include <QRegularExpression>
25#include <QString>
26#include <QStringList>
27#include <QTextStream>
28#include <algorithm>
29#include <cmath>
30#include <complex>
31#include <iomanip>
32#include <iostream>
33#include <map>
34#include <sstream>
35#include <stdexcept>
36#include <string>
37#include <vector>
38
39#include "../Misc/general.h"
40
41using namespace std;
42using Complex = complex<double>;
43
44// Component types
45enum class ComponentType_SPAR {
46 RESISTOR,
47 CAPACITOR,
48 INDUCTOR,
49 VOLTAGE_SOURCE,
50 CURRENT_SOURCE,
51 TRANSMISSION_LINE,
52 OPEN_STUB,
53 SHORT_STUB,
54 COUPLED_LINE,
55 IDEAL_COUPLER,
56 COMPLEX_IMPEDANCE,
57 SPAR_BLOCK,
58 FREQUENCY_DEPENDENT_SPAR_BLOCK,
59 MICROSTRIP_LINE,
60 MICROSTRIP_STEP,
61 MICROSTRIP_OPEN,
62 MICROSTRIP_VIA,
63 MICROSTRIP_COUPLED_LINES
64};
65
66// Circuit component structure
68 ComponentType_SPAR type;
69 string name;
70 vector<int> nodes;
71 QMap<QString, double> value;
72 QMap<QString, Complex> Zvalue;
73 vector<vector<Complex>> Smatrix; // For the S-parameter device
74 double frequency; // For frequency-dependent components
75
76 QMap<QString, QList<double>> freqDepData;
77
78 // S-parameter
79 int numRFPorts;
80 double referenceImpedance;
81
82 Component_SPAR(ComponentType_SPAR t, const string& n, const vector<int>& nds,
83 const vector<vector<Complex>>& S, int rfPorts,
84 double Z0 = 50.0)
85 : type(t), name(n), nodes(nds), Smatrix(S), frequency(0.0),
86 numRFPorts(rfPorts), referenceImpedance(Z0) {}
87
88 Component_SPAR(ComponentType_SPAR t, const string& n, const vector<int>& nds,
89 QMap<QString, QList<double>> freqData, int rfPorts,
90 double Z0 = 50.0)
91 : type(t), name(n), nodes(nds), frequency(0.0), freqDepData(freqData),
92 numRFPorts(rfPorts), referenceImpedance(Z0) {}
93
94 Component_SPAR(ComponentType_SPAR t, const string& n, const vector<int>& nds,
95 QMap<QString, double> val);
97 ComponentType_SPAR t, const string& n, const vector<int>& nds,
98 QMap<QString, Complex> zval); // Constructor for complex impedances
99 Component_SPAR(ComponentType_SPAR t, const string& n, const vector<int>& nds,
100 const vector<vector<Complex>>& S)
101 : type(t), name(n), nodes(nds), Smatrix(S), frequency(0.0) {
102 } // S-parameter device
103
104 // FREQUENCY_DEPENDENT_IMPEDANCE
105 Component_SPAR(ComponentType_SPAR t, const string& n, const vector<int>& nds,
106 QMap<QString, QList<double>> freqData)
107 : type(t), name(n), nodes(nds), frequency(0.0), freqDepData(freqData) {}
108};
109
110// Network port definition
111struct Port {
112 int node;
113 double impedance; // Characteristic impedance (usually 50 ohms)
114
115 Port(int n, double z = 50.0);
116};
117
119private:
120 vector<Component_SPAR> components;
121 vector<Port> ports;
122 int numNodes;
123 double frequency;
124 QString currentNetlist;
125
126 // Matrix operations
127 vector<vector<Complex>> createMatrix(int rows, int cols);
128 vector<vector<Complex>> invertMatrix(const vector<vector<Complex>>& matrix);
129 Complex getImpedance(const Component_SPAR& comp, double freq);
130 vector<vector<Complex>> buildAdmittanceMatrix();
131
132 // Coupled line specific methods
133 void addCoupledLineToAdmittance(vector<vector<Complex>>& Y,
134 const Component_SPAR& comp);
135 vector<vector<Complex>> calculateCoupledLineYMatrix(double Z0e, double Z0o,
136 double length,
137 double freq);
138
139 // Ideal coupler specific methods
140 void addIdealCouplerToAdmittance(vector<vector<Complex>>& Y,
141 const Component_SPAR& comp);
142 vector<vector<Complex>>
143 calculateIdealCouplerYMatrix(double k, double phase_deg, double Z0);
144
145 // Ideal transmission line
146 void addTransmissionLineToAdmittance(vector<vector<Complex>>& Y,
147 const Component_SPAR& comp);
148
149 // Frequency dependent S-parameter file
150 vector<vector<Complex>>
151 interpolateFrequencyDependentSMatrix(const Component_SPAR& comp, double freq);
152 vector<vector<Complex>> extractSMatrixAtIndex(const Component_SPAR& comp,
153 int freqIndex);
154 void addFrequencyDependentSParamBlockToAdmittance(vector<vector<Complex>>& Y,
155 const Component_SPAR& comp);
156 vector<vector<Complex>> parseInlineSMatrix(const QString& matrixStr,
157 int numPorts);
158 void addOnePortSParamToAdmittance(vector<vector<Complex>>& Y,
159 const Component_SPAR& comp);
160 void addTwoPortSParamToAdmittance(vector<vector<Complex>>& Y,
161 const Component_SPAR& comp);
162 void addSParameterDevice(const string& name, const vector<int>& nodes,
163 const vector<vector<Complex>>& Smatrix,
164 int numRFPorts, double Z0);
165
167 // Microstrip line analysis methods
168 void addMicrostripLineToAdmittance(vector<vector<Complex>>& Y,
169 const Component_SPAR& comp);
170 void calcMicrostripPropagation(double W, double h, double er,
171 double t, double tand, double rho,
172 double frequency, double& alpha, double& beta,
173 double& zl, double& ereff);
174 void analyseQuasiStatic(double W, double h, double t, double er,
175 const string& Model, double& ZlEff, double& ErEff,
176 double& WEff);
177 void analyseDispersion(double W, double h, double er, double ZlEff,
178 double ErEff, double frequency, const string& Model,
179 double& ZlEffFreq, double& ErEffFreq);
180 void analyseLoss(double W, double t, double er, double rho, double D,
181 double tand, double ZlEff1, double ZlEff2, double ErEff,
182 double frequency, const string& Model, double& ac,
183 double& ad);
184
185 // Helper functions for microstrip calculations
186 void Hammerstad_ab(double u, double er, double& a, double& b);
187 void Hammerstad_er(double u, double er, double a, double b, double& e);
188 void Hammerstad_zl(double u, double& zl);
189 void Kirschning_er(double u, double fn, double er, double ErEff, double& ErEffFreq);
190 void Kirschning_zl(double ErEff, double ErEffFreq, double ZlEff, double& r17, double& ZlEffFreq);
191 void Getsinger_disp(double h, double er, double ErEff, double ZlEff,
192 double frequency, double& e, double& z);
194
196 // Microstrip step
197 void addMicrostripStepToAdmittance(vector<vector<Complex>>& Y,
198 const Component_SPAR& comp);
199 void calcMicrostripStepZ(double W1, double W2, double h, double er, double t,
200 double frequency, const string& SModel,
201 const string& DModel, Complex& z11, Complex& z12,
202 Complex& z21, Complex& z22);
204
206 // Microstrip open
207 void addMicrostripOpenToAdmittance(vector<vector<Complex>>& Y,
208 const Component_SPAR& comp);
209 Complex calcMicrostripOpenY(double W, double h, double er, double t,
210 double frequency, const string& Model,
211 const string& SModel, const string& DModel);
212 double calcMicrostripOpenCend(double W, double h, double er, double t,
213 double frequency, const string& Model,
214 const string& SModel, const string& DModel);
216
219 void addMicrostripViaToAdmittance(vector<vector<Complex>>& Y,
220 const Component_SPAR& comp);
221 Complex calcMicrostripViaImpedance(double D, double h, double t, double rho,
222 double frequency);
223 double calcMicrostripViaResistance(double D, double h, double t, double rho);
225
228 void addMicrostripCoupledLinesToAdmittance(vector<vector<Complex>>& Y,
229 const Component_SPAR& comp);
230 void calcMicrostripCoupledPropagation(double W, double S, double h,
231 double er, double t, double tand,
232 double rho, double frequency,
233 double& alpha_e, double& beta_e,
234 double& zl_e, double& ereff_e,
235 double& alpha_o, double& beta_o,
236 double& zl_o, double& ereff_o);
237
238 void analyseQuasiStaticCoupled(double W, double h, double s, double t,
239 double er, const string& Model, double& Zle,
240 double& Zlo, double& ErEffe, double& ErEffo);
241
242 void analyseDispersionCoupled(double W, double h, double s, double t,
243 double er, double Zle, double Zlo,
244 double ErEffe, double ErEffo, double frequency,
245 const string& DModel, double& ZleFreq,
246 double& ZloFreq, double& ErEffeFreq,
247 double& ErEffoFreq);
248
249 void analyseLossCoupled(double W, double S, double t, double er, double rho,
250 double D, double tand, double ZlEff1, double ZlEff2,
251 double ErEff, double frequency, const string& Model,
252 bool evenMode, double& ac, double& ad);
254
255 // Frequency sweep parameters
256 double f_start = 1e6;
257 double f_stop = 1e9;
258 int n_points = 20;
259
260 // Simulation data
261 std::vector<std::vector<std::vector<Complex>>> sweepResults;
262 QMap<QString, QList<double>> data;
263
264 double parseScaledValue(const QString& input,
265 QString unit_type = QString(""));
266
267public:
268 // Constructor
270
271 // Set and parse netlist from QString
272 bool setNetlist(const QString& netlist);
273
274 // Get current netlist
275 const QString& getNetlist() const { return currentNetlist; }
276
277 // Add component to the circuit (for programmatic building)
278 void addComponent(ComponentType_SPAR type, const string& name,
279 const vector<int>& nodes, QMap<QString, double> value);
280 void addComponent(ComponentType_SPAR type, const string& name,
281 const vector<int>& nodes, QMap<QString, Complex> Zvalue);
282 // FREQUENCY_DEPENDENT_IMPEDANCE
283 void addComponent(ComponentType_SPAR type, const string& name,
284 const vector<int>& nodes,
285 QMap<QString, QList<double>> freqDepData);
286
287 // Add port to the circuit (for programmatic building)
288 void addPort(int node, double impedance = 50.0);
289
290 // Calculate S-parameters at current frequency
291 vector<vector<Complex>> calculateSParameters();
292
293 // SPAR Block
294 vector<vector<Complex>> convertS2Y(const vector<vector<Complex>>& S,
295 double Z0);
296 void addSParamBlockToAdmittance(vector<vector<Complex>>& Y,
297 const Component_SPAR& comp);
298 void addSParameterBlock(const string& name, const vector<int>& nodes,
299 const vector<vector<Complex>>& Smatrix);
300
301 // Print S-parameters in a readable format
302 void printSParameters(const vector<vector<Complex>>& S);
303
304 // Export S-parameters to Touchstone format
305 void exportTouchstone(const QString& filename,
306 const vector<vector<Complex>>& S);
307
308 // Clear all components and ports
309 void clear();
310
311 // Getter methods
312 int getNumNodes() const { return numNodes; }
313 size_t getNumComponents() const { return components.size(); }
314 size_t getNumPorts() const { return ports.size(); }
315 double getFrequency() const { return frequency; }
316 void setFrequency(double freq) { frequency = freq; }
317
318 // Set frequency sweep parameters
319 void setFrequencySweep(double start, double stop, int points);
320
321 // Calculate sweep and store internally
322 void calculateSParameterSweep();
323
324 // Print all S-parameters for the stored sweep
325 void printSParameterSweep() const;
326
327 // Export frequency sweep to Touchstone format
328 void exportSweepTouchstone(const QString& filename) const;
329 QMap<QString, QList<double>> getData();
330
331private:
332 // Parse netlist content
333 bool parseNetlist();
334};
335
336#endif // SPARAMETERCALCULATOR_H
Definition SParameterCalculator.h:118
Definition SParameterCalculator.h:67
Definition SParameterCalculator.h:111