forked from Qucs/qucs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtaperedline.cpp
executable file
·268 lines (241 loc) · 9.26 KB
/
taperedline.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/*
* taperedline.cpp - ideal tapered transmission line class implementation
*
* Copyright (C) 2015 Claudio Girardi <in3otd@qsl.net>
* Copyright (C) 2015 Andres Martinez-Mera <andresmartinezmera@gmail.com>
*
* This 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, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this package; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* $Id$
*
*/
/* References
[1] Microwave Engineering. David M Pozar. John Wiley and Sons. 4th edition. Pages 261-267
[2] "Conversions between S, Z, Y, h, ABCD and T parameters which are Valid for Complex source and load impedances".
Dean A. Frickey. IEEE Transaction on Microwave Theory and Techniques. Vol 42. No 2. February 1994
[3] "Handbook of Mathematical functions with Formulas, Graphs and Mathematical Tables". Milton Abramowitz.
US department of commerce (1964). Link: http://people.math.sfu.ca/~cbm/aands/page_375.htm
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "component.h"
#include "taperedline.h"
using namespace qucs;
taperedline::taperedline () : circuit (2) {
type = CIR_TAPEREDLINE;
}
//------------------------------------------------------------------
// This function calculates the ABCD matrix of an arbitrarily tapered
// line by diving it into differential slots and calculating their ABCD matrix.
void taperedline::calcABCDparams(nr_double_t frequency)
{
nr_double_t L = getPropertyDouble ("L");//Length
nr_double_t alpha = getPropertyDouble ("Alpha");//Loss coefficient
alpha = std::log(alpha) *.5;//The attenuation coefficient needs to be converted into Neper/m units
nr_double_t lstep = L/Nsteps; //Size of the differential elements
nr_double_t beta = 2*pi*frequency/C0; //Propagation constant
nr_complex_t gamma = nr_complex_t (alpha, beta); //Complex propagation constant
matrix ABCD_ = eye(2);//Overall ABCD matrix
matrix ABCDaux = eye(2);//Auxiliar matrix for performing the iterative product
nr_double_t Zi;
nr_complex_t a, b, c, d;
// ABCD coefficients
a = cosh(gamma*lstep);
b = sinh(gamma*lstep); // need to be multiplied by Zi
c = sinh(gamma*lstep); // need to be divided by Zi
d = cosh(gamma*lstep);
nr_double_t l = lstep/2.0; // compute impedance in the middle of the section
for (int idx = 0 ; idx < Nsteps; idx++)
{
// The line is discretized in finite elements. The size of these elements can be considered a differential
// length since the impedance change across the actual section is small.
// Taking into account the cascading property of the ABCD matrix, the overall
// ABCD matrix can be calculated as the product of the individual ABCD matrices.
Zi = Zprofile[idx];
ABCDaux.set(0,0,a);
ABCDaux.set(0,1,Zi*b);
ABCDaux.set(1,0,c/Zi);
ABCDaux.set(1,1,d);
//Iterative product
ABCD_=ABCD_*ABCDaux;
l += lstep; // move to the next section
}
// Overall ABCD coefficients
ABCD = ABCD_;
}
//------------------------------------------------------------------
// Exponential impedance profile
nr_double_t taperedline::calcExponential(nr_double_t l, nr_double_t L, nr_double_t Z1, nr_double_t Z2)
{
nr_double_t a = (1/L)*std::log(Z2/Z1);
return Z1*std::exp(a*l);
}
//------------------------------------------------------------------
// Linear impedance profile
nr_double_t taperedline::calcLinear(nr_double_t l, nr_double_t L, nr_double_t Z1, nr_double_t Z2)
{
return Z1+l*(Z2-Z1)/L;
}
//------------------------------------------------------------------
// Triangular impedance profile
nr_double_t taperedline::calcTriangular(nr_double_t l, nr_double_t L, nr_double_t Z1, nr_double_t Z2)
{
if (l < L/2)
{
return Z1*std::exp((2*l*l/(L*L))*std::log(Z2/Z1));
}
return Z1*std::exp(((4*l/L) - (2*l*l/(L*L)) -1)*std::log(Z2/Z1));
}
//------------------------------------------------------------------
// Klopfenstein impedance profile
nr_double_t taperedline::calcKlopfenstein(nr_double_t l, nr_double_t L, nr_double_t Z1, nr_double_t Z2, nr_double_t gamma_max)
{
nr_double_t gamma0 = 0.5*std::log(Z2/Z1);
nr_double_t A = std::acosh(gamma0/gamma_max);
return (std::exp(0.5*std::log(Z1*Z2) + (gamma0/std::cosh(A))*A*A*phi(2.*(l/L)-1., A)));
}
void taperedline::calcImpedanceProfile()
{
nr_double_t L = getPropertyDouble ("L");//Length
nr_double_t Z1 = getPropertyDouble ("Z1");//Port 1 impedance
nr_double_t Z2 = getPropertyDouble ("Z2");//Port 2 impedance
if (Z1 > Z2)//Handling Z1 > Z2 case
{
logprint (LOG_ERROR, "WARNING: The impedance at port 1 is bigger than the impedance at port 2 ((Z1 = %g Ohm ) > (Z2 = %g Ohm))\n", Z1, Z2);
nr_double_t Zaux = Z2;
Z2 = Z1;
Z1 = Zaux;
}
nr_double_t gamma_max = getPropertyDouble ("Gamma_max");;//Maximum ripple (Klopfenstein weighting only)
nr_double_t lstep = L/Nsteps; //Size of the differential elements
int idx=0;
nr_double_t l = lstep/2.0;
for (idx = 0, l = lstep/2.0 ; idx < Nsteps; idx++, l += lstep)
{
// The line is discretized in finite elements. The size of these elements can be considered a differential
// length since the impedance change across the actual section is small.
// Taking into account the cascading property of the ABCD matrix, the overall
// ABCD matrix can be calculated as the product of the individual ABCD matrices.
if (!strcmp (getPropertyString ("Weighting"), "Exponential"))
{
Zprofile[idx] = calcExponential(l, L, Z1, Z2);
}
else
{
if (!strcmp (getPropertyString ("Weighting"), "Linear"))
{
Zprofile[idx] = calcLinear(l, L, Z1, Z2);
}
else
{
if (!strcmp (getPropertyString ("Weighting"), "Triangular"))
{
Zprofile[idx] = calcTriangular(l, L, Z1, Z2);
}
else//Klopfenstein
{
Zprofile[idx] = calcKlopfenstein(l, L, Z1, Z2, gamma_max);
}
}
}
}
}
//------------------------------------------------------------------
// Auxiliar function for Klopfenstein profile calculation
// The recursive calculation algorithm is from
// Grossberg, M. A., "Extremely rapid computation of the Klopfenstein
// impedance taper," IEEE Proc., vol.56, no.9, pp.1629-1630, Sept. 1968
//
// In practice less than 10 iterations are needed in most cases
nr_double_t taperedline::phi(nr_double_t x, nr_double_t A)
{
nr_double_t ak = 1.0;
nr_double_t bk = x *.5;
nr_double_t ck = bk;
nr_double_t phi = bk;
for (int k = 1; k < 20; k++) {
ck *= (1.0 - x*x);
bk = (ck + 2.0*k*bk) / (2.0*k + 1.0);
ak = A*A / (4.0*k*(k + 1.0)) * ak;
phi += ak*bk;
if (abs(ak*bk) < 1e-7) break;
}
return phi;
}
void taperedline::calcSP (nr_double_t frequency) {
calcABCDparams(frequency);
matrix Stmp = qucs::atos(ABCD, z0, z0);
setMatrixS(Stmp);
}
void taperedline::calcNoiseSP (nr_double_t) {
nr_double_t l = getPropertyDouble ("L");
if (l < 0) return;
// calculate noise using Bosma's theorem
nr_double_t T = getPropertyDouble ("Temp");
matrix s = getMatrixS ();
matrix e = eye (getSize ());
setMatrixN (celsius2kelvin (T) / T0 * (e - s * transpose (conj (s))));
}
void taperedline::calcNoiseAC (nr_double_t) {
nr_double_t l = getPropertyDouble ("L");
if (l < 0) return;
// calculate noise using Bosma's theorem
nr_double_t T = getPropertyDouble ("Temp");
setMatrixN (4.0 * celsius2kelvin (T) / T0 * real (getMatrixY ()));
}
void taperedline::initDC (void) {
allocMatrixMNA ();
// open circuit
clearY ();
}
void taperedline::initAC (void) {
setVoltageSources (0);
allocMatrixMNA ();
calcImpedanceProfile();
}
void taperedline::initSP(void)
{
allocMatrixS ();
calcImpedanceProfile();
}
void taperedline::calcAC (nr_double_t frequency) {
calcABCDparams(frequency);
nr_double_t L = getPropertyDouble ("L");
if (L != 0.0) {
nr_complex_t y11 = ABCD.get(1,1)/ABCD.get(0,1);
nr_complex_t y12 = -det(ABCD)/ABCD.get(0,1);
nr_complex_t y21 = -1./ABCD.get(0,1);
nr_complex_t y22 = ABCD.get(0,0)/ABCD.get(0,1);
setY (NODE_1, NODE_1, y11); setY (NODE_2, NODE_2, y22);
setY (NODE_1, NODE_2, y12); setY (NODE_2, NODE_1, y21);
}
}
// properties
PROP_REQ [] = {
{ "Z1", PROP_REAL, { 50, PROP_NO_STR }, PROP_POS_RANGE },
{ "Z2", PROP_REAL, { 100, PROP_NO_STR }, PROP_POS_RANGE },
{ "L", PROP_REAL, { 75e-3, PROP_NO_STR }, PROP_NO_RANGE },
{ "Weighting", PROP_STR, { PROP_NO_VAL, "Exponential" },
PROP_RNG_STR4 ("Exponential", "Linear", "Triangular", "Klopfenstein") },
PROP_NO_PROP };
PROP_OPT [] = {
{ "Gamma_max", PROP_REAL, { 0.1, PROP_NO_STR }, PROP_POS_RANGEX },
{ "Alpha", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGEX },
{ "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
PROP_NO_PROP };
struct define_t taperedline::cirdef =
{ "TAPEREDLINE", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };