My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
coplanar.cpp
Go to the documentation of this file.
1 /*
2  * coplanar.cpp - coplanar class implementation
3  *
4  * Copyright (C) 2008 Michael Margraf <michael.margraf@alumni.tu-berlin.de>
5  * Copyright (C) 2005, 2006 Stefan Jahn <stefan@lkcc.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or (at
10  * your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this package; see the file COPYING. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <math.h>
29 #include <float.h>
30 
31 #ifdef __MINGW32__
32 # define finite(x) _finite(x)
33 # ifndef isnan
34 # define isnan(x) _isnan(x)
35 # endif
36 # ifndef isinf
37 # define isinf(x) (!_finite(x) && !_isnan(x))
38 # endif
39 #endif
40 #if defined (__SVR4) && defined (__sun)
41 # define isinf(x) (!finite(x) && (x) == (x))
42 #endif
43 #ifndef M_PI_2
44 #define M_PI_2 1.5707963267948966192313216916397514
45 #endif
46 #ifndef INFINITY
47 #define INFINITY -log (0.0);
48 #endif
49 
50 #include "units.h"
51 #include "transline.h"
52 #include "coplanar.h"
53 
55 {
56  backMetal = false;
57 }
58 
60 {
61  backMetal = true;
62 }
63 
64 // -------------------------------------------------------------------
65 void coplanar::getProperties()
66 {
67  f = getProperty ("Freq", UNIT_FREQ, FREQ_HZ);
68  w = getProperty ("W", UNIT_LENGTH, LENGTH_M);
69  s = getProperty ("S", UNIT_LENGTH, LENGTH_M);
70  len = getProperty ("L", UNIT_LENGTH, LENGTH_M);
71  h = getProperty ("H", UNIT_LENGTH, LENGTH_M);
72  t = getProperty ("T", UNIT_LENGTH, LENGTH_M);
73 
74  er = getProperty ("Er");
75  tand = getProperty ("Tand");
76  sigma = getProperty ("Cond");
77  Z0 = getProperty ("Z0", UNIT_RES, RES_OHM);
78  ang_l = getProperty ("Ang_l", UNIT_ANG, ANG_RAD);
79 }
80 
81 // -------------------------------------------------------------------
82 void coplanar::calc()
83 {
85 
86  // other local variables (quasi-static constants)
87  double k1, kk1, kpk1, k2, k3, q1, q2, q3 = 0, qz, er0 = 0;
88  double zl_factor;
89 
90  // compute the necessary quasi-static approx. (K1, K3, er(0) and Z(0))
91  k1 = w / (w + s + s);
92  kk1 = ellipk (k1);
93  kpk1 = ellipk (sqrt (1 - k1 * k1));
94  q1 = kk1 / kpk1;
95 
96  // backside is metal
97  if (backMetal) {
98  k3 = tanh ((M_PI / 4) * (w / h)) / tanh ((M_PI / 4) * (w + s + s) / h);
99  q3 = ellipk (k3) / ellipk (sqrt (1 - k3 * k3));
100  qz = 1 / (q1 + q3);
101  er0 = 1 + q3 * qz * (er - 1);
102  zl_factor = ZF0 / 2 * qz;
103  }
104  // backside is air
105  else {
106  k2 = sinh ((M_PI / 4) * (w / h)) / sinh ((M_PI / 4) * (w + s + s) / h);
107  q2 = ellipk (k2) / ellipk (sqrt (1 - k2 * k2));
108  er0 = 1 + (er - 1) / 2 * q2 / q1;
109  zl_factor = ZF0 / 4 / q1;
110  }
111 
112  // adds effect of strip thickness
113  if (t > 0) {
114  double d, se, We, ke, qe;
115  d = (t * 1.25 / M_PI) * (1 + log (4 * M_PI * w / t));
116  se = s - d;
117  We = w + d;
118 
119  // modifies k1 accordingly (k1 = ke)
120  ke = We / (We + se + se); // ke = k1 + (1 - k1 * k1) * d / 2 / s;
121  qe = ellipk (ke) / ellipk (sqrt (1 - ke * ke));
122  // backside is metal
123  if (backMetal) {
124  qz = 1 / (qe + q3);
125  er0 = 1 + q3 * qz * (er - 1);
126  zl_factor = ZF0 / 2 * qz;
127  }
128  // backside is air
129  else {
130  zl_factor = ZF0 / 4 / qe;
131  }
132 
133  // modifies er0 as well
134  er0 = er0 - (0.7 * (er0 - 1) * t / s) / (q1 + (0.7 * t / s));
135  }
136 
137  // pre-compute square roots
138  double sr_er = sqrt (er);
139  double sr_er0 = sqrt (er0);
140 
141  // cut-off frequency of the TE0 mode
142  double fte = (C0 / 4) / (h * sqrt (er - 1));
143 
144  // dispersion factor G
145  double p = log (w / h);
146  double u = 0.54 - (0.64 - 0.015 * p) * p;
147  double v = 0.43 - (0.86 - 0.54 * p) * p;
148  double G = exp (u * log (w / s) + v);
149 
150  // loss constant factors (computed only once for efficency sake)
151  double ac = 0;
152  if (t > 0) {
153  // equations by GHIONE
154  double n = (1 - k1) * 8 * M_PI / (t * (1 + k1));
155  double a = w / 2;
156  double b = a + s;
157  ac = (M_PI + log (n * a)) / a + (M_PI + log (n * b)) / b;
158  }
159  double ac_factor = ac / (4 * ZF0 * kk1 * kpk1 * (1 - k1 * k1));
160  double ad_factor = (er / (er - 1)) * tand * M_PI / C0;
161 
162 
163  // ....................................................
164  double sr_er_f = sr_er0;
165 
166  // add the dispersive effects to er0
167  sr_er_f += (sr_er - sr_er0) / (1 + G * pow (f / fte, -1.8));
168 
169  // for now, the loss are limited to strip losses (no radiation
170  // losses yet) losses in neper/length
171  atten_cond = 20.0 / log(10.0) * len
172  * ac_factor * sr_er0 * sqrt (M_PI * MU0 * f / sigma);
173  atten_dielectric = 20.0 / log(10.0) * len
174  * ad_factor * f * (sr_er_f * sr_er_f - 1) / sr_er_f;
175 
176  ang_l = 2.0 * M_PI * len * sr_er_f * f / C0; /* in radians */
177 
178  er_eff = sr_er_f * sr_er_f;
179  Z0 = zl_factor / sr_er_f;
180 }
181 
182 // -------------------------------------------------------------------
183 void coplanar::show_results()
184 {
185  setProperty ("Z0", Z0, UNIT_RES, RES_OHM);
186  setProperty ("Ang_l", ang_l, UNIT_ANG, ANG_RAD);
187 
188  setResult (0, er_eff, "");
189  setResult (1, atten_cond, "dB");
190  setResult (2, atten_dielectric, "dB");
191 
192  double val = convertProperty ("T", skindepth, UNIT_LENGTH, LENGTH_M);
193  setResult (3, val, getUnit ("T"));
194 }
195 
196 // -------------------------------------------------------------------
198 {
199  getProperties();
200 
201  /* compute coplanar parameters */
202  calc();
203 
204  /* print results in the subwindow */
205  show_results();
206 }
207 
208 
209 #define MAX_ERROR 0.000001
210 
211 // -------------------------------------------------------------------
213 {
214  double Z0_dest, Z0_current, Z0_result, increment, slope, error;
215  int iteration;
216 
217  getProperties();
218 
219  /* required value of Z0 */
220  Z0_dest = Z0;
221 
222  /* Newton's method */
223  iteration = 0;
224 
225  /* compute coplanar parameters */
226  calc();
227  Z0_current = Z0;
228 
229  error = fabs(Z0_dest - Z0_current);
230 
231  while (error > MAX_ERROR) {
232  iteration++;
233  if(isSelected ("W")) {
234  increment = w / 100.0;
235  w += increment;
236  }
237  else {
238  increment = s / 100.0;
239  s += increment;
240  }
241  /* compute coplanar parameters */
242  calc();
243  Z0_result = Z0;
244  /* f(w(n)) = Z0 - Z0(w(n)) */
245  /* f'(w(n)) = -f'(Z0(w(n))) */
246  /* f'(Z0(w(n))) = (Z0(w(n)) - Z0(w(n+delw))/delw */
247  /* w(n+1) = w(n) - f(w(n))/f'(w(n)) */
248  slope = (Z0_result - Z0_current) / increment;
249  slope = (Z0_dest - Z0_current) / slope - increment;
250  if(isSelected ("W"))
251  w += slope;
252  else
253  s += slope;
254  if (w <= 0.0)
255  w = increment;
256  if (s <= 0.0)
257  s = increment;
258  /* find new error */
259  /* compute coplanar parameters */
260  calc();
261  Z0_current = Z0;
262  error = fabs(Z0_dest - Z0_current);
263  if (iteration > 100)
264  break;
265  }
266 
267  setProperty ("W", w, UNIT_LENGTH, LENGTH_M);
268  setProperty ("S", s, UNIT_LENGTH, LENGTH_M);
269  /* calculate physical length */
270  ang_l = getProperty ("Ang_l", UNIT_ANG, ANG_RAD);
271  len = C0 / f / sqrt(er_eff) * ang_l / 2.0 / M_PI; /* in m */
272  setProperty ("L", len, UNIT_LENGTH, LENGTH_M);
273 
274  /* compute coplanar parameters */
275  calc();
276 
277  /* print results in the subwindow */
278  show_results();
279 }
280 
281 
282 
283 /* *****************************************************************
284  ********** **********
285  ********** mathematical functions **********
286  ********** **********
287  ***************************************************************** */
288 
289 #define NR_EPSI 2.2204460492503131e-16
290 
291 /* The function computes the complete elliptic integral of first kind
292  K() and the second kind E() using the arithmetic-geometric mean
293  algorithm (AGM) by Abramowitz and Stegun. */
294 void coplanar::ellipke (double arg, double &k, double &e) {
295  int iMax = 16;
296  if (arg == 1.0) {
297  k = INFINITY; // infinite
298  e = 0;
299  }
300  else if (isinf (arg) && arg < 0) {
301  k = 0;
302  e = INFINITY; // infinite
303  }
304  else {
305  double a, b, c, f, s, fk = 1, fe = 1, t, da = arg;
306  int i;
307  if (arg < 0) {
308  fk = 1 / sqrt (1 - arg);
309  fe = sqrt (1 - arg);
310  da = -arg / (1 - arg);
311  }
312  a = 1;
313  b = sqrt (1 - da);
314  c = sqrt (da);
315  f = 0.5;
316  s = f * c * c;
317  for (i = 0; i < iMax; i++) {
318  t = (a + b) / 2;
319  c = (a - b) / 2;
320  b = sqrt (a * b);
321  a = t;
322  f *= 2;
323  s += f * c * c;
324  if (c / a < NR_EPSI) break;
325  }
326  if (i >= iMax) {
327  k = 0; e = 0;
328  }
329  else {
330  k = M_PI_2 / a;
331  e = M_PI_2 * (1 - s) / a;
332  if (arg < 0) {
333  k *= fk;
334  e *= fe;
335  }
336  }
337  }
338 }
339 
340 /* We need to know only K(k), and if possible KISS. */
341 double coplanar::ellipk (double k) {
342  double r, lost;
343  ellipke (k, r, lost);
344  return r;
345 }