KiCad PCB EDA Suite
Loading...
Searching...
No Matches
coupled_microstrip.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2001 Gopal Narayanan <[email protected]>
3 * Copyright (C) 2002 Claudio Girardi <[email protected]>
4 * Copyright (C) 2005, 2006 Stefan Jahn <[email protected]>
5 * Modified for Kicad: 2018 Jean-Pierre Charras <jp.charras at wanadoo.fr>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this package; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
26
27
28namespace TC = TRANSLINE_CALCULATIONS;
30
31
33{
35
36 const double f = GetParameter( TCP::FREQUENCY );
37 const double rawEpsR = GetParameter( TCP::EPSILONR );
38 const double rawTanD = GetParameter( TCP::TAND );
39
40 // Overlay dispersed values so helpers reading EPSILONR / TAND via GetParameter
41 // pick them up. Raw inputs are restored before return.
44
45 // Compute thickness corrections
47
48 // Get effective dielectric constants
50
51 // Impedances for even- and odd-mode
53
54 // Apply the soldermask cover correction to both modes before dispersion and loss
55 // consume the static quantities. Same Wan-Hoorfar 2000 Delta q factor as microstrip;
56 // the even/odd split is preserved because each mode's static eps_eff picks up its own
57 // correction. Z0 for each mode scales by sqrt(uncoated/coated) so the homogeneous
58 // reference impedance remains consistent with the new eps_eff.
59 const double dispersedEpsR = GetParameter( TCP::EPSILONR );
60 const double dispersedTanD = GetParameter( TCP::TAND );
61 const double uOverH = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H );
62
63 const auto [ erEvenCoated, tanDEvenCoated ] =
64 ApplySoldermaskCorrection( er_eff_e_0, dispersedTanD, dispersedEpsR, uOverH, f );
65 const auto [ erOddCoated, tanDOddCoated ] =
66 ApplySoldermaskCorrection( er_eff_o_0, dispersedTanD, dispersedEpsR, uOverH, f );
67
68 if( erEvenCoated != er_eff_e_0 )
69 {
70 Z0_e_0 *= std::sqrt( er_eff_e_0 / erEvenCoated );
71 er_eff_e_0 = erEvenCoated;
72 }
73
74 if( erOddCoated != er_eff_o_0 )
75 {
76 Z0_o_0 *= std::sqrt( er_eff_o_0 / erOddCoated );
77 er_eff_o_0 = erOddCoated;
78 }
79
80 // Calculate freq dependence of er_eff_e, er_eff_o
82
83 // Calculate frequency dependence of Z0e, Z0o */
85
86 // Swap in the mask-blended tan delta for losses. Even and odd modes differ only by
87 // eps_eff, which has already been corrected, so using the odd-mode blended value for
88 // both is a second-order refinement; average them to avoid biasing either mode.
89 const double tanDBlended = 0.5 * ( tanDEvenCoated + tanDOddCoated );
90 SetParameter( TCP::TAND, tanDBlended );
91
92 // Calculate losses
94
95 // Calculate electrical lengths
96 line_angle();
97
98 // Calculate diff impedance
100
101 SetParameter( TCP::EPSILONR, rawEpsR );
102 SetParameter( TCP::TAND, rawTanD );
103}
104
105
107{
108 if( aOpts == SYNTHESIZE_OPTS::FIX_WIDTH )
109 return MinimiseZ0Error1D( TCP::PHYS_S, TCP::Z0_O, false );
110
111 if( aOpts == SYNTHESIZE_OPTS::FIX_SPACING )
113
114 double Z0_e, Z0_o, ang_l_dest;
115 double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err;
116 double eps = 1e-04;
117 double w_h, s_h, le, lo;
118
119 /* required value of Z0_e and Z0_o */
120 Z0_e = GetParameter( TCP::Z0_E );
121 Z0_o = GetParameter( TCP::Z0_O );
122
125 ang_l_dest = GetParameter( TCP::ANG_L );
126
127 /* calculate width and use for initial value in Newton's method */
128 synth_width();
131 f1 = f2 = 0;
132
133 int iters = 0;
134
135 /* rather crude Newton-Rhapson */
136 do
137 {
138 ++iters;
139
140 /* compute Jacobian */
141 syn_fun( &ft1, &ft2, s_h + eps, w_h, Z0_e, Z0_o );
142 j11 = ( ft1 - f1 ) / eps;
143 j21 = ( ft2 - f2 ) / eps;
144 syn_fun( &ft1, &ft2, s_h, w_h + eps, Z0_e, Z0_o );
145 j12 = ( ft1 - f1 ) / eps;
146 j22 = ( ft2 - f2 ) / eps;
147
148 /* compute next step; increments of s_h and w_h */
149 d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 );
150 d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 );
151
152 s_h += d_s_h;
153 w_h += d_w_h;
154
155 /* compute the error with the new values of s_h and w_h */
156 syn_fun( &f1, &f2, s_h, w_h, Z0_e, Z0_o );
157 err = sqrt( f1 * f1 + f2 * f2 );
158
159 /* converged ? */
160 } while( err > 1e-04 && iters < 250 );
161
162 if( err > 1e-04 )
163 return false;
164
165 /* denormalize computed width and spacing */
168
169 /* calculate physical length */
170 le = TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff_e ) * ang_l_dest / 2.0 / M_PI;
171 lo = TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff_o ) * ang_l_dest / 2.0 / M_PI;
172 SetParameter( TCP::PHYS_LEN, sqrt( le * lo ) );
173
174 Analyse();
175
176 SetParameter( TCP::ANG_L, ang_l_dest );
177 SetParameter( TCP::Z0_E, Z0_e );
178 SetParameter( TCP::Z0_O, Z0_o );
179
180 return true;
181}
182
183
185{
196
197 const double Z0_E = GetParameter( TCP::Z0_E );
198 const double Z0_O = GetParameter( TCP::Z0_O );
199 const double ANG_L = sqrt( ang_l_e * ang_l_o );
200 const double W = GetParameter( TCP::PHYS_WIDTH );
201 const double L = GetParameter( TCP::PHYS_LEN );
202 const double S = GetParameter( TCP::PHYS_S );
203
204 const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0;
205 const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0;
206 const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0;
207 const bool W_invalid = !std::isfinite( W ) || W <= 0;
208 const bool L_invalid = !std::isfinite( L ) || L < 0;
209 const bool S_invalid = !std::isfinite( S ) || S <= 0;
210
217}
218
219
221{
232
233 const double Z0_E = GetParameter( TCP::Z0_E );
234 const double Z0_O = GetParameter( TCP::Z0_O );
235 const double ANG_L = sqrt( ang_l_e * ang_l_o );
236 const double W = GetParameter( TCP::PHYS_WIDTH );
237 const double L = GetParameter( TCP::PHYS_LEN );
238 const double S = GetParameter( TCP::PHYS_S );
239
240 const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0;
241 const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0;
242 const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0;
243 const bool W_invalid = !std::isfinite( W ) || W <= 0;
244 const bool L_invalid = !std::isfinite( L ) || L < 0;
245 const bool S_invalid = !std::isfinite( S ) || S <= 0;
246
253}
254
255
257{
258 double delta_u;
259
260 if( t_h > 0.0 )
261 {
262 delta_u = ( 1.25 * t_h / M_PI )
263 * ( 1.0
264 + log( ( 2.0 + ( 4.0 * M_PI * u - 2.0 ) / ( 1.0 + exp( -100.0 * ( u - 1.0 / ( 2.0 * M_PI ) ) ) ) )
265 / t_h ) );
266 }
267 else
268 {
269 delta_u = 0.0;
270 }
271 return delta_u;
272}
273
274
275/*
276 * delta_u_thickness() - compute the thickness effect on normalized
277 * width for coupled microstrips
278 *
279 * References: Rolf Jansen, "High-Speed Computation of Single and
280 * Coupled Microstrip Parameters Including Dispersion, High-Order
281 * Modes, Loss and Finite Strip Thickness", IEEE Trans. MTT, vol. 26,
282 * no. 2, pp. 75-82, Feb. 1978
283 */
285{
286 double e_r, u, g, t_h;
287 double delta_u, delta_t, delta_u_e, delta_u_o;
288
290 u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalized line width */
291 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */
292 t_h = GetParameter( TCP::T ) / GetParameter( TCP::H ); /* normalized strip thickness */
293
294 if( t_h > 0.0 )
295 {
296 /* single microstrip correction for finite strip thickness */
297 delta_u = delta_u_thickness_single( u, t_h );
298 delta_t = t_h / ( g * e_r );
299 /* thickness correction for the even- and odd-mode */
300 delta_u_e = delta_u * ( 1.0 - 0.5 * exp( -0.69 * delta_u / delta_t ) );
301 delta_u_o = delta_u_e + delta_t;
302 }
303 else
304 {
305 delta_u_e = delta_u_o = 0.0;
306 }
307
310}
311
312
314{
315 /* prepare parameters for single microstrip computations */
318 m_aux_microstrip.SetParameter( TCP::H, GetParameter( TCP::H ) );
319 m_aux_microstrip.SetParameter( TCP::T, 0.0 );
320
321 //m_aux_microstrip.m_parameters[H_T ) = m_parameters[H_T );
322 m_aux_microstrip.SetParameter( TCP::H_T, 1e12 ); /* arbitrarily high */
325 m_aux_microstrip.microstrip_Z0();
326 m_aux_microstrip.dispersion();
327}
328
329
330double COUPLED_MICROSTRIP::filling_factor_even( double u, double g, double e_r )
331{
332 double v, v3, v4, a_e, b_e, q_inf;
333
334 v = u * ( 20.0 + g * g ) / ( 10.0 + g * g ) + g * exp( -g );
335 v3 = v * v * v;
336 v4 = v3 * v;
337 a_e = 1.0 + log( ( v4 + v * v / 2704.0 ) / ( v4 + 0.432 ) ) / 49.0 + log( 1.0 + v3 / 5929.741 ) / 18.7;
338 b_e = 0.564 * pow( ( ( e_r - 0.9 ) / ( e_r + 3.0 ) ), 0.053 );
339
340 /* filling factor, with width corrected for thickness */
341 q_inf = pow( ( 1.0 + 10.0 / v ), -a_e * b_e );
342
343 return q_inf;
344}
345
346
347double COUPLED_MICROSTRIP::filling_factor_odd( double u, double g, double e_r )
348{
349 double b_odd = 0.747 * e_r / ( 0.15 + e_r );
350 double c_odd = b_odd - ( b_odd - 0.207 ) * exp( -0.414 * u );
351 double d_odd = 0.593 + 0.694 * exp( -0.562 * u );
352
353 /* filling factor, with width corrected for thickness */
354 double q_inf = exp( -c_odd * pow( g, d_odd ) );
355
356 return q_inf;
357}
358
359
361{
362 double q_c;
363
364 if( h2h <= 39 )
365 q_c = tanh( 1.626 + 0.107 * h2h - 1.733 / sqrt( h2h ) );
366 else
367 q_c = 1.0;
368
369 return q_c;
370}
371
372
374{
375 double q_c;
376
377 if( h2h <= 7 )
378 q_c = tanh( 9.575 / ( 7.0 - h2h ) - 2.965 + 1.68 * h2h - 0.311 * h2h * h2h );
379 else
380 q_c = 1.0;
381
382 return q_c;
383}
384
385
387{
388 double u_t_e, u_t_o, g, h2, h2h;
389 double a_o, t_h, q, q_c, q_t, q_inf;
390 double er_eff_single;
391 double er;
392
394
395 /* compute zero-thickness single line parameters */
397 er_eff_single = m_aux_microstrip.er_eff_0;
398
399 h2 = GetParameter( TCP::H_T );
400 u_t_e = w_t_e / GetParameter( TCP::H ); /* normalized even_mode line width */
401 u_t_o = w_t_o / GetParameter( TCP::H ); /* normalized odd_mode line width */
402 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */
403 h2h = h2 / GetParameter( TCP::H ); /* normalized cover height */
404 t_h = GetParameter( TCP::T ) / GetParameter( TCP::H ); /* normalized strip thickness */
405
406 /* filling factor, computed with thickness corrected width */
407 q_inf = filling_factor_even( u_t_e, g, er );
408 /* cover effect */
409 q_c = delta_q_cover_even( h2h );
410 /* thickness effect */
411 q_t = m_aux_microstrip.delta_q_thickness( u_t_e, t_h );
412 /* resultant filling factor */
413 q = ( q_inf - q_t ) * q_c;
414 /* static even-mode effective dielectric constant */
415 er_eff_e_0 = 0.5 * ( er + 1.0 ) + 0.5 * ( er - 1.0 ) * q;
416
417 /* filling factor, with width corrected for thickness */
418 q_inf = filling_factor_odd( u_t_o, g, er );
419 /* cover effect */
420 q_c = delta_q_cover_odd( h2h );
421 /* thickness effect */
422 q_t = m_aux_microstrip.delta_q_thickness( u_t_o, t_h );
423 /* resultant filling factor */
424 q = ( q_inf - q_t ) * q_c;
425
426 a_o = 0.7287 * ( er_eff_single - 0.5 * ( er + 1.0 ) ) * ( 1.0 - exp( -0.179 * u_t_o ) );
427
428 /* static odd-mode effective dielectric constant */
429 er_eff_o_0 = ( 0.5 * ( er + 1.0 ) + a_o - er_eff_single ) * q + er_eff_single;
430}
431
432
433double COUPLED_MICROSTRIP::delta_Z0_even_cover( double g, double u, double h2h )
434{
435 double f_e, g_e, delta_Z0_even;
436 double x, y, A, B, C, D, E, F;
437
438 A = -4.351 / pow( 1.0 + h2h, 1.842 );
439 B = 6.639 / pow( 1.0 + h2h, 1.861 );
440 C = -2.291 / pow( 1.0 + h2h, 1.90 );
441 f_e = 1.0 - atanh( A + ( B + C * u ) * u );
442
443 x = pow( 10.0, 0.103 * g - 0.159 );
444 y = pow( 10.0, 0.0492 * g - 0.073 );
445 D = 0.747 / sin( 0.5 * M_PI * x );
446 E = 0.725 * sin( 0.5 * M_PI * y );
447 F = pow( 10.0, 0.11 - 0.0947 * g );
448 g_e = 270.0 * ( 1.0 - tanh( D + E * sqrt( 1.0 + h2h ) - F / ( 1.0 + h2h ) ) );
449
450 delta_Z0_even = f_e * g_e;
451
452 return delta_Z0_even;
453}
454
455
456double COUPLED_MICROSTRIP::delta_Z0_odd_cover( double g, double u, double h2h )
457{
458 double f_o, g_o, delta_Z0_odd;
459 double G, J, K, L;
460
461 J = tanh( pow( 1.0 + h2h, 1.585 ) / 6.0 );
462 f_o = pow( u, J );
463
464 G = 2.178 - 0.796 * g;
465
466 if( g > 0.858 )
467 K = log10( 20.492 * pow( g, 0.174 ) );
468 else
469 K = 1.30;
470
471 if( g > 0.873 )
472 L = 2.51 * pow( g, -0.462 );
473 else
474 L = 2.674;
475
476 g_o = 270.0 * ( 1.0 - tanh( G + K * sqrt( 1.0 + h2h ) - L / ( 1.0 + h2h ) ) );
477
478 delta_Z0_odd = f_o * g_o;
479
480 return delta_Z0_odd;
481}
482
483
485{
486 double er_eff, h2, u_t_e, u_t_o, g, h2h;
487 double Q_1, Q_2, Q_3, Q_4, Q_5, Q_6, Q_7, Q_8, Q_9, Q_10;
488 double delta_Z0_e_0, delta_Z0_o_0, Z0_single, er_eff_single;
489
490 h2 = GetParameter( TCP::H_T );
491 u_t_e = w_t_e / GetParameter( TCP::H ); /* normalized even-mode line width */
492 u_t_o = w_t_o / GetParameter( TCP::H ); /* normalized odd-mode line width */
493 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */
494 h2h = h2 / GetParameter( TCP::H ); /* normalized cover height */
495
496 Z0_single = m_aux_microstrip.Z0_0;
497 er_eff_single = m_aux_microstrip.er_eff_0;
498
499 /* even-mode */
500 er_eff = er_eff_e_0;
501 Q_1 = 0.8695 * pow( u_t_e, 0.194 );
502 Q_2 = 1.0 + 0.7519 * g + 0.189 * pow( g, 2.31 );
503 Q_3 = 0.1975 + pow( ( 16.6 + pow( ( 8.4 / g ), 6.0 ) ), -0.387 )
504 + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 3.4, 10.0 ) ) ) / 241.0;
505 Q_4 = 2.0 * Q_1 / ( Q_2 * ( exp( -g ) * pow( u_t_e, Q_3 ) + ( 2.0 - exp( -g ) ) * pow( u_t_e, -Q_3 ) ) );
506 /* static even-mode impedance */
507 Z0_e_0 = Z0_single * sqrt( er_eff_single / er_eff ) / ( 1.0 - sqrt( er_eff_single ) * Q_4 * Z0_single / TC::ZF0 );
508 /* correction for cover */
509 delta_Z0_e_0 = delta_Z0_even_cover( g, u_t_e, h2h ) / sqrt( er_eff );
510
511 Z0_e_0 = Z0_e_0 - delta_Z0_e_0;
512
513 /* odd-mode */
514 er_eff = er_eff_o_0;
515 Q_5 = 1.794 + 1.14 * log( 1.0 + 0.638 / ( g + 0.517 * pow( g, 2.43 ) ) );
516 Q_6 = 0.2305 + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 5.8, 10.0 ) ) ) / 281.3
517 + log( 1.0 + 0.598 * pow( g, 1.154 ) ) / 5.1;
518 Q_7 = ( 10.0 + 190.0 * g * g ) / ( 1.0 + 82.3 * g * g * g );
519 Q_8 = exp( -6.5 - 0.95 * log( g ) - pow( g / 0.15, 5.0 ) );
520 Q_9 = log( Q_7 ) * ( Q_8 + 1.0 / 16.5 );
521 Q_10 = ( Q_2 * Q_4 - Q_5 * exp( log( u_t_o ) * Q_6 * pow( u_t_o, -Q_9 ) ) ) / Q_2;
522
523 /* static odd-mode impedance */
524 Z0_o_0 = Z0_single * sqrt( er_eff_single / er_eff ) / ( 1.0 - sqrt( er_eff_single ) * Q_10 * Z0_single / TC::ZF0 );
525 /* correction for cover */
526 delta_Z0_o_0 = delta_Z0_odd_cover( g, u_t_o, h2h ) / sqrt( er_eff );
527
528 Z0_o_0 = Z0_o_0 - delta_Z0_o_0;
529}
530
531
533{
534 double P_1, P_2, P_3, P_4, P_5, P_6, P_7;
535 double P_8, P_9, P_10, P_11, P_12, P_13, P_14, P_15;
536 double F_e, F_o;
537 double er_eff, u, g, f_n;
538
539 u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalize line width */
540 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalize line spacing */
541
542 /* normalized frequency [GHz * mm] */
543 f_n = GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::H ) / 1e06;
544
545 er_eff = er_eff_e_0;
546 P_1 = 0.27488 + ( 0.6315 + 0.525 / pow( 1.0 + 0.0157 * f_n, 20.0 ) ) * u - 0.065683 * exp( -8.7513 * u );
547 P_2 = 0.33622 * ( 1.0 - exp( -0.03442 * GetParameter( TCP::EPSILONR ) ) );
548 P_3 = 0.0363 * exp( -4.6 * u ) * ( 1.0 - exp( -pow( f_n / 38.7, 4.97 ) ) );
549 P_4 = 1.0 + 2.751 * ( 1.0 - exp( -pow( GetParameter( TCP::EPSILONR ) / 15.916, 8.0 ) ) );
550 P_5 = 0.334 * exp( -3.3 * pow( GetParameter( TCP::EPSILONR ) / 15.0, 3.0 ) ) + 0.746;
551 P_6 = P_5 * exp( -pow( f_n / 18.0, 0.368 ) );
552 P_7 = 1.0 + 4.069 * P_6 * pow( g, 0.479 ) * exp( -1.347 * pow( g, 0.595 ) - 0.17 * pow( g, 2.5 ) );
553
554 F_e = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 * P_7 ) * f_n, 1.5763 );
555 /* even-mode effective dielectric constant */
556 er_eff_e = GetParameter( TCP::EPSILONR ) - ( GetParameter( TCP::EPSILONR ) - er_eff ) / ( 1.0 + F_e );
558
559 er_eff = er_eff_o_0;
560 P_8 = 0.7168 * ( 1.0 + 1.076 / ( 1.0 + 0.0576 * ( GetParameter( TCP::EPSILONR ) - 1.0 ) ) );
561 P_9 = P_8
562 - 0.7913 * ( 1.0 - exp( -pow( f_n / 20.0, 1.424 ) ) )
563 * atan( 2.481 * pow( GetParameter( TCP::EPSILONR ) / 8.0, 0.946 ) );
564 P_10 = 0.242 * pow( GetParameter( TCP::EPSILONR ) - 1.0, 0.55 );
565 P_11 = 0.6366 * ( exp( -0.3401 * f_n ) - 1.0 ) * atan( 1.263 * pow( u / 3.0, 1.629 ) );
566 P_12 = P_9 + ( 1.0 - P_9 ) / ( 1.0 + 1.183 * pow( u, 1.376 ) );
567 P_13 = 1.695 * P_10 / ( 0.414 + 1.605 * P_10 );
568 P_14 = 0.8928 + 0.1072 * ( 1.0 - exp( -0.42 * pow( f_n / 20.0, 3.215 ) ) );
569 P_15 = fabs( 1.0 - 0.8928 * ( 1.0 + P_11 ) * P_12 * exp( -P_13 * pow( g, 1.092 ) ) / P_14 );
570
571 F_o = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 ) * f_n * P_15, 1.5763 );
572 /* odd-mode effective dielectric constant */
573 er_eff_o = GetParameter( TCP::EPSILONR ) - ( GetParameter( TCP::EPSILONR ) - er_eff ) / ( 1.0 + F_o );
575}
576
577
579{
580 double e_r_eff_e_0, e_r_eff_o_0, Z0_h_e, Z0_h_o, delta;
581 double K, R_s, Q_c_e, Q_c_o, alpha_c_e, alpha_c_o;
582
583 e_r_eff_e_0 = er_eff_e_0;
584 e_r_eff_o_0 = er_eff_o_0;
585 Z0_h_e = Z0_e_0 * sqrt( e_r_eff_e_0 ); /* homogeneous stripline impedance */
586 Z0_h_o = Z0_o_0 * sqrt( e_r_eff_o_0 ); /* homogeneous stripline impedance */
588
589 if( GetParameter( TCP::FREQUENCY ) > 0.0 )
590 {
591 /* current distribution factor (same for the two modes) */
592 K = exp( -1.2 * pow( ( Z0_h_e + Z0_h_o ) / ( 2.0 * TC::ZF0 ), 0.7 ) );
593 /* skin resistance */
594 R_s = 1.0 / ( GetParameter( TCP::SIGMA ) * delta );
595 /* correction for surface roughness */
596 R_s *= 1.0 + ( ( 2.0 / M_PI ) * atan( 1.40 * pow( ( GetParameter( TCP::ROUGH ) / delta ), 2.0 ) ) );
597
598 /* even-mode strip inductive quality factor */
599 Q_c_e = ( M_PI * Z0_h_e * GetParameter( TCP::PHYS_WIDTH ) * GetParameter( TCP::FREQUENCY ) )
600 / ( R_s * TC::C0 * K );
601 /* even-mode losses per unit length */
602 alpha_c_e = ( 20.0 * M_PI / log( 10.0 ) ) * GetParameter( TCP::FREQUENCY ) * sqrt( e_r_eff_e_0 )
603 / ( TC::C0 * Q_c_e );
604
605 /* odd-mode strip inductive quality factor */
606 Q_c_o = ( M_PI * Z0_h_o * GetParameter( TCP::PHYS_WIDTH ) * GetParameter( TCP::FREQUENCY ) )
607 / ( R_s * TC::C0 * K );
608 /* odd-mode losses per unit length */
609 alpha_c_o = ( 20.0 * M_PI / log( 10.0 ) ) * GetParameter( TCP::FREQUENCY ) * sqrt( e_r_eff_o_0 )
610 / ( TC::C0 * Q_c_o );
611 }
612 else
613 {
614 alpha_c_e = alpha_c_o = 0.0;
615 }
616
617 atten_cond_e = alpha_c_e * GetParameter( TCP::PHYS_LEN );
618 atten_cond_o = alpha_c_o * GetParameter( TCP::PHYS_LEN );
619}
620
621
623{
624 double e_r, e_r_eff_e_0, e_r_eff_o_0;
625 double alpha_d_e, alpha_d_o;
626
628 e_r_eff_e_0 = er_eff_e_0;
629 e_r_eff_o_0 = er_eff_o_0;
630
631 alpha_d_e = ( 20.0 * M_PI / log( 10.0 ) ) * ( GetParameter( TCP::FREQUENCY ) / TC::C0 )
632 * ( e_r / sqrt( e_r_eff_e_0 ) ) * ( ( e_r_eff_e_0 - 1.0 ) / ( e_r - 1.0 ) ) * GetParameter( TCP::TAND );
633 alpha_d_o = ( 20.0 * M_PI / log( 10.0 ) ) * ( GetParameter( TCP::FREQUENCY ) / TC::C0 )
634 * ( e_r / sqrt( e_r_eff_o_0 ) ) * ( ( e_r_eff_o_0 - 1.0 ) / ( e_r - 1.0 ) ) * GetParameter( TCP::TAND );
635
638}
639
640
647
648
650{
651 double e_r_eff_e, e_r_eff_o;
652 double v_e, v_o, lambda_g_e, lambda_g_o;
653
654 e_r_eff_e = er_eff_e;
655 e_r_eff_o = er_eff_o;
656
657 /* even-mode velocity */
658 v_e = TC::C0 / sqrt( e_r_eff_e );
659 /* odd-mode velocity */
660 v_o = TC::C0 / sqrt( e_r_eff_o );
661 /* even-mode wavelength */
662 lambda_g_e = v_e / GetParameter( TCP::FREQUENCY );
663 /* odd-mode wavelength */
664 lambda_g_o = v_o / GetParameter( TCP::FREQUENCY );
665 /* electrical angles */
666 ang_l_e = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g_e; /* in radians */
667 ang_l_o = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g_o; /* in radians */
668}
669
670
672{
673 // Differential impedance of a coupled pair driven in odd mode is exactly twice the
674 // odd-mode characteristic impedance (Pozar, "Microwave Engineering" 4th ed., §7.6).
675 // Odd mode is not the same as single-ended impedance, so avoid approximations found
676 // on websites that use static single ended impedance as the starting point.
677 // Read the dispersed Z0_O left by Z0_dispersion() rather than the static Z0_o_0 so
678 // Zdiff tracks frequency above a few GHz where Kirschning-Jansen raises the odd-mode
679 // impedance by several percent.
680
681 Zdiff = 2.0 * GetParameter( TCP::Z0_O );
682}
683
684
685/*
686 * Z0_dispersion() - calculate frequency dependency of characteristic impedances.
687 *
688 * Kirschning & Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent
689 * Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT 32(1):83-90,
690 * Jan. 1984 (errata: MTT 33(3):288, Mar. 1985). The Q_0..Q_29 closed-form chain below
691 * implements the dispersive even- and odd-mode impedance correction tables from that
692 * paper.
693 */
695{
696 double Q_0;
697 double Q_11, Q_12, Q_13, Q_14, Q_15, Q_16, Q_17, Q_18, Q_19, Q_20, Q_21;
698 double Q_22, Q_23, Q_24, Q_25, Q_26, Q_27, Q_28, Q_29;
699 double r_e, q_e, p_e, d_e, C_e;
700 double e_r_eff_o_f, e_r_eff_o_0;
701 double e_r_eff_single_f, e_r_eff_single_0, Z0_single_f;
702 double f_n, g, u, e_r;
703 double R_1, R_2, R_7, R_10, R_11, R_12, R_15, R_16, tmpf;
704
706
707 u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalize line width */
708 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalize line spacing */
709
710 /* normalized frequency [GHz * mm] */
711 f_n = GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::H ) / 1e06;
712
713 e_r_eff_single_f = m_aux_microstrip.GetParameter( TCP::EPSILON_EFF );
714 e_r_eff_single_0 = m_aux_microstrip.er_eff_0;
715 Z0_single_f = m_aux_microstrip.GetParameter( TCP::Z0 );
716
717 e_r_eff_o_f = er_eff_o;
718 e_r_eff_o_0 = er_eff_o_0;
719
720 Q_11 = 0.893 * ( 1.0 - 0.3 / ( 1.0 + 0.7 * ( e_r - 1.0 ) ) );
721 Q_12 = 2.121 * ( pow( f_n / 20.0, 4.91 ) / ( 1.0 + Q_11 * pow( f_n / 20.0, 4.91 ) ) ) * exp( -2.87 * g )
722 * pow( g, 0.902 );
723 Q_13 = 1.0 + 0.038 * pow( e_r / 8.0, 5.1 );
724 Q_14 = 1.0 + 1.203 * pow( e_r / 15.0, 4.0 ) / ( 1.0 + pow( e_r / 15.0, 4.0 ) );
725 Q_15 = 1.887 * exp( -1.5 * pow( g, 0.84 ) ) * pow( g, Q_14 )
726 / ( 1.0 + 0.41 * pow( f_n / 15.0, 3.0 ) * pow( u, 2.0 / Q_13 ) / ( 0.125 + pow( u, 1.626 / Q_13 ) ) );
727 Q_16 = ( 1.0 + 9.0 / ( 1.0 + 0.403 * pow( e_r - 1.0, 2 ) ) ) * Q_15;
728 Q_17 = 0.394 * ( 1.0 - exp( -1.47 * pow( u / 7.0, 0.672 ) ) ) * ( 1.0 - exp( -4.25 * pow( f_n / 20.0, 1.87 ) ) );
729 Q_18 = 0.61 * ( 1.0 - exp( -2.13 * pow( u / 8.0, 1.593 ) ) ) / ( 1.0 + 6.544 * pow( g, 4.17 ) );
730 Q_19 = 0.21 * g * g * g * g
731 / ( ( 1.0 + 0.18 * pow( g, 4.9 ) ) * ( 1.0 + 0.1 * u * u ) * ( 1.0 + pow( f_n / 24.0, 3.0 ) ) );
732 Q_20 = ( 0.09 + 1.0 / ( 1.0 + 0.1 * pow( e_r - 1, 2.7 ) ) ) * Q_19;
733 Q_21 = fabs( 1.0 - 42.54 * pow( g, 0.133 ) * exp( -0.812 * g ) * pow( u, 2.5 ) / ( 1.0 + 0.033 * pow( u, 2.5 ) ) );
734
735 r_e = pow( f_n / 28.843, 12 );
736 q_e = 0.016 + pow( 0.0514 * e_r * Q_21, 4.524 );
737 p_e = 4.766 * exp( -3.228 * pow( u, 0.641 ) );
738 d_e = 5.086 * q_e * ( r_e / ( 0.3838 + 0.386 * q_e ) ) * ( exp( -22.2 * pow( u, 1.92 ) ) / ( 1.0 + 1.2992 * r_e ) )
739 * ( pow( e_r - 1.0, 6.0 ) / ( 1.0 + 10 * pow( e_r - 1.0, 6.0 ) ) );
740 C_e = 1.0 + 1.275 * ( 1.0 - exp( -0.004625 * p_e * pow( e_r, 1.674 ) * pow( f_n / 18.365, 2.745 ) ) ) - Q_12 + Q_16
741 - Q_17 + Q_18 + Q_20;
742
743
744 R_1 = 0.03891 * pow( e_r, 1.4 );
745 R_2 = 0.267 * pow( u, 7.0 );
746 R_7 = 1.206 - 0.3144 * exp( -R_1 ) * ( 1.0 - exp( -R_2 ) );
747 R_10 = 0.00044 * pow( e_r, 2.136 ) + 0.0184;
748 tmpf = pow( f_n / 19.47, 6.0 );
749 R_11 = tmpf / ( 1.0 + 0.0962 * tmpf );
750 R_12 = 1.0 / ( 1.0 + 0.00245 * u * u );
751 R_15 = 0.707 * R_10 * pow( f_n / 12.3, 1.097 );
752 R_16 = 1.0 + 0.0503 * e_r * e_r * R_11 * ( 1.0 - exp( -pow( u / 15.0, 6.0 ) ) );
753 Q_0 = R_7 * ( 1.0 - 1.1241 * ( R_12 / R_16 ) * exp( -0.026 * pow( f_n, 1.15656 ) - R_15 ) );
754
755 /* even-mode frequency-dependent characteristic impedances */
756 SetParameter( TCP::Z0_E, Z0_e_0 * pow( 0.9408 * pow( e_r_eff_single_f, C_e ) - 0.9603, Q_0 )
757 / pow( ( 0.9408 - d_e ) * pow( e_r_eff_single_0, C_e ) - 0.9603, Q_0 ) );
758
759 Q_29 = 15.16 / ( 1.0 + 0.196 * pow( e_r - 1.0, 2.0 ) );
760 tmpf = pow( e_r - 1.0, 3.0 );
761 Q_28 = 0.149 * tmpf / ( 94.5 + 0.038 * tmpf );
762 tmpf = pow( e_r - 1.0, 1.5 );
763 Q_27 = 0.4 * pow( g, 0.84 ) * ( 1.0 + 2.5 * tmpf / ( 5.0 + tmpf ) );
764 tmpf = pow( ( e_r - 1.0 ) / 13.0, 12.0 );
765 Q_26 = 30.0 - 22.2 * ( tmpf / ( 1.0 + 3.0 * tmpf ) ) - Q_29;
766 tmpf = ( e_r - 1.0 ) * ( e_r - 1.0 );
767 Q_25 = ( 0.3 * f_n * f_n / ( 10.0 + f_n * f_n ) ) * ( 1.0 + 2.333 * tmpf / ( 5.0 + tmpf ) );
768 Q_24 = 2.506 * Q_28 * pow( u, 0.894 ) * pow( ( 1.0 + 1.3 * u ) * f_n / 99.25, 4.29 ) / ( 3.575 + pow( u, 0.894 ) );
769 Q_23 = 1.0 + 0.005 * f_n * Q_27 / ( ( 1.0 + 0.812 * pow( f_n / 15.0, 1.9 ) ) * ( 1.0 + 0.025 * u * u ) );
770 Q_22 = 0.925 * pow( f_n / Q_26, 1.536 ) / ( 1.0 + 0.3 * pow( f_n / 30.0, 1.536 ) );
771
772 /* odd-mode frequency-dependent characteristic impedances */
773 SetParameter( TCP::Z0_O, Z0_single_f
774 + ( Z0_o_0 * pow( e_r_eff_o_f / e_r_eff_o_0, Q_22 ) - Z0_single_f * Q_23 )
775 / ( 1.0 + Q_24 + pow( 0.46 * g, 2.2 ) * Q_25 ) );
776}
777
778
779void COUPLED_MICROSTRIP::syn_err_fun( double* f1, double* f2, double s_h, double w_h, double e_r, double w_h_se,
780 double w_h_so )
781{
782 double g, he;
783
784 g = cosh( 0.5 * M_PI * s_h );
785 he = cosh( M_PI * w_h + 0.5 * M_PI * s_h );
786
787 *f1 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g + 1.0 ) / ( g + 1.0 ) );
788 *f2 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g - 1.0 ) / ( g - 1.0 ) );
789
790 if( e_r <= 6.0 )
791 *f2 += ( 4.0 / ( M_PI * ( 1.0 + e_r / 2.0 ) ) ) * acosh( 1.0 + 2.0 * w_h / s_h );
792 else
793 *f2 += ( 1.0 / M_PI ) * acosh( 1.0 + 2.0 * w_h / s_h );
794
795 *f1 -= w_h_se;
796 *f2 -= w_h_so;
797}
798
799
801{
802 double Z0, e_r;
803 double w_h_se, w_h_so, w_h, a, ce, co, s_h;
804 double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err;
805 double eps = 1e-04;
806
807 f1 = f2 = 0;
809
810 Z0 = GetParameter( TCP::Z0_E ) / 2.0;
811 /* Wheeler formula for single microstrip synthesis */
812 a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0;
813 w_h_se = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a;
814
815 Z0 = GetParameter( TCP::Z0_O ) / 2.0;
816 /* Wheeler formula for single microstrip synthesis */
817 a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0;
818 w_h_so = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a;
819
820 ce = cosh( 0.5 * M_PI * w_h_se );
821 co = cosh( 0.5 * M_PI * w_h_so );
822 /* first guess at m_parameters[PHYS_S )/h */
823 s_h = ( 2.0 / M_PI ) * acosh( ( ce + co - 2.0 ) / ( co - ce ) );
824 /* first guess at w/h */
825 w_h = acosh( ( ce * co - 1.0 ) / ( co - ce ) ) / M_PI - s_h / 2.0;
826
829
830 syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so );
831
832 /* rather crude Newton-Rhapson; we need this because the estimate of */
833 /* w_h is often quite far from the true value (see Akhtarzad S. et al.) */
834 do
835 {
836 /* compute Jacobian */
837 syn_err_fun( &ft1, &ft2, s_h + eps, w_h, e_r, w_h_se, w_h_so );
838 j11 = ( ft1 - f1 ) / eps;
839 j21 = ( ft2 - f2 ) / eps;
840 syn_err_fun( &ft1, &ft2, s_h, w_h + eps, e_r, w_h_se, w_h_so );
841 j12 = ( ft1 - f1 ) / eps;
842 j22 = ( ft2 - f2 ) / eps;
843
844 /* compute next step */
845 d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 );
846 d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 );
847
848 //g_print("j11 = %e\tj12 = %e\tj21 = %e\tj22 = %e\n", j11, j12, j21, j22);
849 //g_print("det = %e\n", j11*j22 - j21*j22);
850 //g_print("d_s_h = %e\td_w_h = %e\n", d_s_h, d_w_h);
851
852 s_h += d_s_h;
853 w_h += d_w_h;
854
855 /* check the error */
856 syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so );
857
858 err = sqrt( f1 * f1 + f2 * f2 );
859 /* converged ? */
860 } while( err > 1e-04 );
861
862
865}
866
867
868void COUPLED_MICROSTRIP::syn_fun( double* f1, double* f2, double s_h, double w_h, double Z0_e, double Z0_o )
869{
872
873 /* compute coupled microstrip parameters */
874 Analyse();
875
876 *f1 = GetParameter( TCP::Z0_E ) - Z0_e;
877 *f2 = GetParameter( TCP::Z0_O ) - Z0_o;
878}
void Z0_dispersion()
Calculate frequency dependency of characteristic impedances.
void delta_u_thickness()
Compute the thickness effect on normalized width for coupled microstrips.
void er_eff_static()
Compute the static effective dielectric constants.
void diff_impedance()
Calculate the differential impedance of the coupled microstrips.
double delta_u_thickness_single(double, double)
Computes the thickness effect on normalized width for a single microstrip line.
MICROSTRIP m_aux_microstrip
Runs intermediate single-track calculations.
void line_angle()
Compute electrical length in radians.
void synth_width()
Calculate widths given Z0 and e_r.
void syn_err_fun(double *, double *, double, double, double, double, double)
Error function to minimise when synthesising trace geometry.
void attenuation()
Compute attenuation.
double filling_factor_even(double, double, double)
Compute the filling factor for the coupled microstrip even mode without cover and zero conductor thic...
double delta_Z0_odd_cover(double, double, double)
Compute the odd mode impedance correction for a homogeneous microstrip due to the cover.
void compute_single_line()
Computes initial parameters for a single microstrip.
void SetAnalysisResults() override
Sets the output values and status following analysis.
void er_eff_freq()
Compute er_eff as a function of frequency.
void conductor_losses()
Compute conductor losses per unit length.
void Analyse() override
Analyse track geometry parameters to output Z0 and Ang_L.
void SetSynthesisResults() override
Sets the output values and status following synthesis.
void syn_fun(double *, double *, double, double, double, double)
double delta_q_cover_even(double)
Compute the cover effect on filling factor for the even mode.
double delta_q_cover_odd(double)
Compute the cover effect on filling factor for the odd mode.
bool Synthesize(SYNTHESIZE_OPTS aOpts) override
Synthesis track geometry parameters to match given Z0.
double filling_factor_odd(double, double, double)
Compute the filling factor for the coupled microstrip odd mode without cover and zero conductor thick...
void Z0_even_odd()
Compute the static even- and odd-mode static impedances.
void dielectric_losses()
Compute dielectric losses per unit length.
double delta_Z0_even_cover(double, double, double)
Compute the even mode impedance correction for a homogeneous microstrip due to the cover.
double GetDispersedEpsilonR(double aF) const
Dispersed permittivity at aF. Returns raw EPSILONR when the model is inactive.
double GetDispersedTanDelta(double aF) const
Dispersed loss tangent at aF. Returns raw TAND when the model is inactive.
double GetParameter(const TRANSLINE_PARAMETERS aParam) const
Gets the given calculation property.
void SetParameter(const TRANSLINE_PARAMETERS aParam, const double aValue)
Sets the given calculation property.
void SetSynthesisResult(TRANSLINE_PARAMETERS aParam, const double aValue, const TRANSLINE_STATUS aStatus=TRANSLINE_STATUS::OK)
Sets a synthesis result.
void UpdateDielectricModel()
Refit the Djordjevic-Sarkar model from the current parameter map.
std::pair< double, double > ApplySoldermaskCorrection(double aEpsEffUncoated, double aTanDeltaSubstrate, double aEpsRSubstrate, double aWOverH, double aF) const
Apply a three-layer (substrate / soldermask / air) correction to an un-coated (eps_eff,...
double SkinDepth() const
Calculate skin depth.
bool MinimiseZ0Error1D(TRANSLINE_PARAMETERS aOptimise, TRANSLINE_PARAMETERS aMeasure, bool aRecalculateLength=false)
minimizeZ0Error1D
void SetAnalysisResult(TRANSLINE_PARAMETERS aParam, const double aValue, const TRANSLINE_STATUS aStatus=TRANSLINE_STATUS::OK)
Sets an analysis result.
static double UnitPropagationDelay(double aEpsilonEff)
Calculates the unit propagation delay (ps/cm) for the given effective permittivity.
TRANSLINE_PARAMETERS TCP
double atanh(double x)
double acosh(double x)
@ S
Solder (HASL/SMOBC)
#define F(x, y, z)
Definition md5_hash.cpp:15
#define G(x, y, z)
Definition md5_hash.cpp:16
#define D(x)
Definition ptree.cpp:41
VECTOR2I v4(1, 1)
VECTOR2I v3(-2, 1)
int delta
#define M_PI
SYNTHESIZE_OPTS
Options for specifying synthesis inputs, targets, or strategies.
TRANSLINE_PARAMETERS
All possible parameters used (as inputs or outputs) by the transmission line calculations.