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. If not, see <https://www.gnu.org/licenses/>.
20 */
21
24
25
26namespace TC = TRANSLINE_CALCULATIONS;
28
29
31{
33
34 const double f = GetParameter( TCP::FREQUENCY );
35 const double rawEpsR = GetParameter( TCP::EPSILONR );
36 const double rawTanD = GetParameter( TCP::TAND );
37
38 // Overlay dispersed values so helpers reading EPSILONR / TAND via GetParameter
39 // pick them up. Raw inputs are restored before return.
42
43 // Compute thickness corrections
45
46 // Get effective dielectric constants
48
49 // Impedances for even- and odd-mode
51
52 // Apply the soldermask cover correction to both modes before dispersion and loss
53 // consume the static quantities. Same Wan-Hoorfar 2000 Delta q factor as microstrip;
54 // the even/odd split is preserved because each mode's static eps_eff picks up its own
55 // correction. Z0 for each mode scales by sqrt(uncoated/coated) so the homogeneous
56 // reference impedance remains consistent with the new eps_eff.
57 const double dispersedEpsR = GetParameter( TCP::EPSILONR );
58 const double dispersedTanD = GetParameter( TCP::TAND );
59 const double uOverH = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H );
60
61 const auto [ erEvenCoated, tanDEvenCoated ] =
62 ApplySoldermaskCorrection( er_eff_e_0, dispersedTanD, dispersedEpsR, uOverH, f );
63 const auto [ erOddCoated, tanDOddCoated ] =
64 ApplySoldermaskCorrection( er_eff_o_0, dispersedTanD, dispersedEpsR, uOverH, f );
65
66 if( erEvenCoated != er_eff_e_0 )
67 {
68 Z0_e_0 *= std::sqrt( er_eff_e_0 / erEvenCoated );
69 er_eff_e_0 = erEvenCoated;
70 }
71
72 if( erOddCoated != er_eff_o_0 )
73 {
74 Z0_o_0 *= std::sqrt( er_eff_o_0 / erOddCoated );
75 er_eff_o_0 = erOddCoated;
76 }
77
78 // Calculate freq dependence of er_eff_e, er_eff_o
80
81 // Calculate frequency dependence of Z0e, Z0o */
83
84 // Swap in the mask-blended tan delta for losses. Even and odd modes differ only by
85 // eps_eff, which has already been corrected, so using the odd-mode blended value for
86 // both is a second-order refinement; average them to avoid biasing either mode.
87 const double tanDBlended = 0.5 * ( tanDEvenCoated + tanDOddCoated );
88 SetParameter( TCP::TAND, tanDBlended );
89
90 // Calculate losses
92
93 // Calculate electrical lengths
94 line_angle();
95
96 // Calculate diff impedance
98
99 SetParameter( TCP::EPSILONR, rawEpsR );
100 SetParameter( TCP::TAND, rawTanD );
101}
102
103
105{
106 if( aOpts == SYNTHESIZE_OPTS::FIX_WIDTH )
107 return MinimiseZ0Error1D( TCP::PHYS_S, TCP::Z0_O, false );
108
109 if( aOpts == SYNTHESIZE_OPTS::FIX_SPACING )
111
112 double Z0_e, Z0_o, ang_l_dest;
113 double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err;
114 double eps = 1e-04;
115 double w_h, s_h, le, lo;
116
117 /* required value of Z0_e and Z0_o */
118 Z0_e = GetParameter( TCP::Z0_E );
119 Z0_o = GetParameter( TCP::Z0_O );
120
123 ang_l_dest = GetParameter( TCP::ANG_L );
124
125 /* calculate width and use for initial value in Newton's method */
126 synth_width();
129 f1 = f2 = 0;
130
131 int iters = 0;
132
133 /* rather crude Newton-Rhapson */
134 do
135 {
136 ++iters;
137
138 /* compute Jacobian */
139 syn_fun( &ft1, &ft2, s_h + eps, w_h, Z0_e, Z0_o );
140 j11 = ( ft1 - f1 ) / eps;
141 j21 = ( ft2 - f2 ) / eps;
142 syn_fun( &ft1, &ft2, s_h, w_h + eps, Z0_e, Z0_o );
143 j12 = ( ft1 - f1 ) / eps;
144 j22 = ( ft2 - f2 ) / eps;
145
146 /* compute next step; increments of s_h and w_h */
147 d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 );
148 d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 );
149
150 s_h += d_s_h;
151 w_h += d_w_h;
152
153 /* compute the error with the new values of s_h and w_h */
154 syn_fun( &f1, &f2, s_h, w_h, Z0_e, Z0_o );
155 err = sqrt( f1 * f1 + f2 * f2 );
156
157 /* converged ? */
158 } while( err > 1e-04 && iters < 250 );
159
160 if( err > 1e-04 )
161 return false;
162
163 /* denormalize computed width and spacing */
166
167 /* calculate physical length */
168 le = TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff_e ) * ang_l_dest / 2.0 / M_PI;
169 lo = TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff_o ) * ang_l_dest / 2.0 / M_PI;
170 SetParameter( TCP::PHYS_LEN, sqrt( le * lo ) );
171
172 Analyse();
173
174 SetParameter( TCP::ANG_L, ang_l_dest );
175 SetParameter( TCP::Z0_E, Z0_e );
176 SetParameter( TCP::Z0_O, Z0_o );
177
178 return true;
179}
180
181
183{
194
195 const double Z0_E = GetParameter( TCP::Z0_E );
196 const double Z0_O = GetParameter( TCP::Z0_O );
197 const double ANG_L = sqrt( ang_l_e * ang_l_o );
198 const double W = GetParameter( TCP::PHYS_WIDTH );
199 const double L = GetParameter( TCP::PHYS_LEN );
200 const double S = GetParameter( TCP::PHYS_S );
201
202 const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0;
203 const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0;
204 const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0;
205 const bool W_invalid = !std::isfinite( W ) || W <= 0;
206 const bool L_invalid = !std::isfinite( L ) || L < 0;
207 const bool S_invalid = !std::isfinite( S ) || S <= 0;
208
215}
216
217
219{
230
231 const double Z0_E = GetParameter( TCP::Z0_E );
232 const double Z0_O = GetParameter( TCP::Z0_O );
233 const double ANG_L = sqrt( ang_l_e * ang_l_o );
234 const double W = GetParameter( TCP::PHYS_WIDTH );
235 const double L = GetParameter( TCP::PHYS_LEN );
236 const double S = GetParameter( TCP::PHYS_S );
237
238 const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0;
239 const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0;
240 const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0;
241 const bool W_invalid = !std::isfinite( W ) || W <= 0;
242 const bool L_invalid = !std::isfinite( L ) || L < 0;
243 const bool S_invalid = !std::isfinite( S ) || S <= 0;
244
251}
252
253
255{
256 double delta_u;
257
258 if( t_h > 0.0 )
259 {
260 delta_u = ( 1.25 * t_h / M_PI )
261 * ( 1.0
262 + log( ( 2.0 + ( 4.0 * M_PI * u - 2.0 ) / ( 1.0 + exp( -100.0 * ( u - 1.0 / ( 2.0 * M_PI ) ) ) ) )
263 / t_h ) );
264 }
265 else
266 {
267 delta_u = 0.0;
268 }
269 return delta_u;
270}
271
272
273/*
274 * delta_u_thickness() - compute the thickness effect on normalized
275 * width for coupled microstrips
276 *
277 * References: Rolf Jansen, "High-Speed Computation of Single and
278 * Coupled Microstrip Parameters Including Dispersion, High-Order
279 * Modes, Loss and Finite Strip Thickness", IEEE Trans. MTT, vol. 26,
280 * no. 2, pp. 75-82, Feb. 1978
281 */
283{
284 double e_r, u, g, t_h;
285 double delta_u, delta_t, delta_u_e, delta_u_o;
286
288 u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalized line width */
289 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */
290 t_h = GetParameter( TCP::T ) / GetParameter( TCP::H ); /* normalized strip thickness */
291
292 if( t_h > 0.0 )
293 {
294 /* single microstrip correction for finite strip thickness */
295 delta_u = delta_u_thickness_single( u, t_h );
296 delta_t = t_h / ( g * e_r );
297 /* thickness correction for the even- and odd-mode */
298 delta_u_e = delta_u * ( 1.0 - 0.5 * exp( -0.69 * delta_u / delta_t ) );
299 delta_u_o = delta_u_e + delta_t;
300 }
301 else
302 {
303 delta_u_e = delta_u_o = 0.0;
304 }
305
308}
309
310
312{
313 /* prepare parameters for single microstrip computations */
316 m_aux_microstrip.SetParameter( TCP::H, GetParameter( TCP::H ) );
317 m_aux_microstrip.SetParameter( TCP::T, 0.0 );
318
319 //m_aux_microstrip.m_parameters[H_T ) = m_parameters[H_T );
320 m_aux_microstrip.SetParameter( TCP::H_T, 1e12 ); /* arbitrarily high */
323 m_aux_microstrip.microstrip_Z0();
324 m_aux_microstrip.dispersion();
325}
326
327
328double COUPLED_MICROSTRIP::filling_factor_even( double u, double g, double e_r )
329{
330 double v, v3, v4, a_e, b_e, q_inf;
331
332 v = u * ( 20.0 + g * g ) / ( 10.0 + g * g ) + g * exp( -g );
333 v3 = v * v * v;
334 v4 = v3 * v;
335 a_e = 1.0 + log( ( v4 + v * v / 2704.0 ) / ( v4 + 0.432 ) ) / 49.0 + log( 1.0 + v3 / 5929.741 ) / 18.7;
336 b_e = 0.564 * pow( ( ( e_r - 0.9 ) / ( e_r + 3.0 ) ), 0.053 );
337
338 /* filling factor, with width corrected for thickness */
339 q_inf = pow( ( 1.0 + 10.0 / v ), -a_e * b_e );
340
341 return q_inf;
342}
343
344
345double COUPLED_MICROSTRIP::filling_factor_odd( double u, double g, double e_r )
346{
347 double b_odd = 0.747 * e_r / ( 0.15 + e_r );
348 double c_odd = b_odd - ( b_odd - 0.207 ) * exp( -0.414 * u );
349 double d_odd = 0.593 + 0.694 * exp( -0.562 * u );
350
351 /* filling factor, with width corrected for thickness */
352 double q_inf = exp( -c_odd * pow( g, d_odd ) );
353
354 return q_inf;
355}
356
357
359{
360 double q_c;
361
362 if( h2h <= 39 )
363 q_c = tanh( 1.626 + 0.107 * h2h - 1.733 / sqrt( h2h ) );
364 else
365 q_c = 1.0;
366
367 return q_c;
368}
369
370
372{
373 double q_c;
374
375 if( h2h <= 7 )
376 q_c = tanh( 9.575 / ( 7.0 - h2h ) - 2.965 + 1.68 * h2h - 0.311 * h2h * h2h );
377 else
378 q_c = 1.0;
379
380 return q_c;
381}
382
383
385{
386 double u_t_e, u_t_o, g, h2, h2h;
387 double a_o, t_h, q, q_c, q_t, q_inf;
388 double er_eff_single;
389 double er;
390
392
393 /* compute zero-thickness single line parameters */
395 er_eff_single = m_aux_microstrip.er_eff_0;
396
397 h2 = GetParameter( TCP::H_T );
398 u_t_e = w_t_e / GetParameter( TCP::H ); /* normalized even_mode line width */
399 u_t_o = w_t_o / GetParameter( TCP::H ); /* normalized odd_mode line width */
400 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */
401 h2h = h2 / GetParameter( TCP::H ); /* normalized cover height */
402 t_h = GetParameter( TCP::T ) / GetParameter( TCP::H ); /* normalized strip thickness */
403
404 /* filling factor, computed with thickness corrected width */
405 q_inf = filling_factor_even( u_t_e, g, er );
406 /* cover effect */
407 q_c = delta_q_cover_even( h2h );
408 /* thickness effect */
409 q_t = m_aux_microstrip.delta_q_thickness( u_t_e, t_h );
410 /* resultant filling factor */
411 q = ( q_inf - q_t ) * q_c;
412 /* static even-mode effective dielectric constant */
413 er_eff_e_0 = 0.5 * ( er + 1.0 ) + 0.5 * ( er - 1.0 ) * q;
414
415 /* filling factor, with width corrected for thickness */
416 q_inf = filling_factor_odd( u_t_o, g, er );
417 /* cover effect */
418 q_c = delta_q_cover_odd( h2h );
419 /* thickness effect */
420 q_t = m_aux_microstrip.delta_q_thickness( u_t_o, t_h );
421 /* resultant filling factor */
422 q = ( q_inf - q_t ) * q_c;
423
424 a_o = 0.7287 * ( er_eff_single - 0.5 * ( er + 1.0 ) ) * ( 1.0 - exp( -0.179 * u_t_o ) );
425
426 /* static odd-mode effective dielectric constant */
427 er_eff_o_0 = ( 0.5 * ( er + 1.0 ) + a_o - er_eff_single ) * q + er_eff_single;
428}
429
430
431double COUPLED_MICROSTRIP::delta_Z0_even_cover( double g, double u, double h2h )
432{
433 double f_e, g_e, delta_Z0_even;
434 double x, y, A, B, C, D, E, F;
435
436 A = -4.351 / pow( 1.0 + h2h, 1.842 );
437 B = 6.639 / pow( 1.0 + h2h, 1.861 );
438 C = -2.291 / pow( 1.0 + h2h, 1.90 );
439 f_e = 1.0 - atanh( A + ( B + C * u ) * u );
440
441 x = pow( 10.0, 0.103 * g - 0.159 );
442 y = pow( 10.0, 0.0492 * g - 0.073 );
443 D = 0.747 / sin( 0.5 * M_PI * x );
444 E = 0.725 * sin( 0.5 * M_PI * y );
445 F = pow( 10.0, 0.11 - 0.0947 * g );
446 g_e = 270.0 * ( 1.0 - tanh( D + E * sqrt( 1.0 + h2h ) - F / ( 1.0 + h2h ) ) );
447
448 delta_Z0_even = f_e * g_e;
449
450 return delta_Z0_even;
451}
452
453
454double COUPLED_MICROSTRIP::delta_Z0_odd_cover( double g, double u, double h2h )
455{
456 double f_o, g_o, delta_Z0_odd;
457 double G, J, K, L;
458
459 J = tanh( pow( 1.0 + h2h, 1.585 ) / 6.0 );
460 f_o = pow( u, J );
461
462 G = 2.178 - 0.796 * g;
463
464 if( g > 0.858 )
465 K = log10( 20.492 * pow( g, 0.174 ) );
466 else
467 K = 1.30;
468
469 if( g > 0.873 )
470 L = 2.51 * pow( g, -0.462 );
471 else
472 L = 2.674;
473
474 g_o = 270.0 * ( 1.0 - tanh( G + K * sqrt( 1.0 + h2h ) - L / ( 1.0 + h2h ) ) );
475
476 delta_Z0_odd = f_o * g_o;
477
478 return delta_Z0_odd;
479}
480
481
483{
484 double er_eff, h2, u_t_e, u_t_o, g, h2h;
485 double Q_1, Q_2, Q_3, Q_4, Q_5, Q_6, Q_7, Q_8, Q_9, Q_10;
486 double delta_Z0_e_0, delta_Z0_o_0, Z0_single, er_eff_single;
487
488 h2 = GetParameter( TCP::H_T );
489 u_t_e = w_t_e / GetParameter( TCP::H ); /* normalized even-mode line width */
490 u_t_o = w_t_o / GetParameter( TCP::H ); /* normalized odd-mode line width */
491 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */
492 h2h = h2 / GetParameter( TCP::H ); /* normalized cover height */
493
494 Z0_single = m_aux_microstrip.Z0_0;
495 er_eff_single = m_aux_microstrip.er_eff_0;
496
497 /* even-mode */
498 er_eff = er_eff_e_0;
499 Q_1 = 0.8695 * pow( u_t_e, 0.194 );
500 Q_2 = 1.0 + 0.7519 * g + 0.189 * pow( g, 2.31 );
501 Q_3 = 0.1975 + pow( ( 16.6 + pow( ( 8.4 / g ), 6.0 ) ), -0.387 )
502 + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 3.4, 10.0 ) ) ) / 241.0;
503 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 ) ) );
504 /* static even-mode impedance */
505 Z0_e_0 = Z0_single * sqrt( er_eff_single / er_eff ) / ( 1.0 - sqrt( er_eff_single ) * Q_4 * Z0_single / TC::ZF0 );
506 /* correction for cover */
507 delta_Z0_e_0 = delta_Z0_even_cover( g, u_t_e, h2h ) / sqrt( er_eff );
508
509 Z0_e_0 = Z0_e_0 - delta_Z0_e_0;
510
511 /* odd-mode */
512 er_eff = er_eff_o_0;
513 Q_5 = 1.794 + 1.14 * log( 1.0 + 0.638 / ( g + 0.517 * pow( g, 2.43 ) ) );
514 Q_6 = 0.2305 + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 5.8, 10.0 ) ) ) / 281.3
515 + log( 1.0 + 0.598 * pow( g, 1.154 ) ) / 5.1;
516 Q_7 = ( 10.0 + 190.0 * g * g ) / ( 1.0 + 82.3 * g * g * g );
517 Q_8 = exp( -6.5 - 0.95 * log( g ) - pow( g / 0.15, 5.0 ) );
518 Q_9 = log( Q_7 ) * ( Q_8 + 1.0 / 16.5 );
519 Q_10 = ( Q_2 * Q_4 - Q_5 * exp( log( u_t_o ) * Q_6 * pow( u_t_o, -Q_9 ) ) ) / Q_2;
520
521 /* static odd-mode impedance */
522 Z0_o_0 = Z0_single * sqrt( er_eff_single / er_eff ) / ( 1.0 - sqrt( er_eff_single ) * Q_10 * Z0_single / TC::ZF0 );
523 /* correction for cover */
524 delta_Z0_o_0 = delta_Z0_odd_cover( g, u_t_o, h2h ) / sqrt( er_eff );
525
526 Z0_o_0 = Z0_o_0 - delta_Z0_o_0;
527}
528
529
531{
532 double P_1, P_2, P_3, P_4, P_5, P_6, P_7;
533 double P_8, P_9, P_10, P_11, P_12, P_13, P_14, P_15;
534 double F_e, F_o;
535 double er_eff, u, g, f_n;
536
537 u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalize line width */
538 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalize line spacing */
539
540 /* normalized frequency [GHz * mm] */
541 f_n = GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::H ) / 1e06;
542
543 er_eff = er_eff_e_0;
544 P_1 = 0.27488 + ( 0.6315 + 0.525 / pow( 1.0 + 0.0157 * f_n, 20.0 ) ) * u - 0.065683 * exp( -8.7513 * u );
545 P_2 = 0.33622 * ( 1.0 - exp( -0.03442 * GetParameter( TCP::EPSILONR ) ) );
546 P_3 = 0.0363 * exp( -4.6 * u ) * ( 1.0 - exp( -pow( f_n / 38.7, 4.97 ) ) );
547 P_4 = 1.0 + 2.751 * ( 1.0 - exp( -pow( GetParameter( TCP::EPSILONR ) / 15.916, 8.0 ) ) );
548 P_5 = 0.334 * exp( -3.3 * pow( GetParameter( TCP::EPSILONR ) / 15.0, 3.0 ) ) + 0.746;
549 P_6 = P_5 * exp( -pow( f_n / 18.0, 0.368 ) );
550 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 ) );
551
552 F_e = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 * P_7 ) * f_n, 1.5763 );
553 /* even-mode effective dielectric constant */
554 er_eff_e = GetParameter( TCP::EPSILONR ) - ( GetParameter( TCP::EPSILONR ) - er_eff ) / ( 1.0 + F_e );
556
557 er_eff = er_eff_o_0;
558 P_8 = 0.7168 * ( 1.0 + 1.076 / ( 1.0 + 0.0576 * ( GetParameter( TCP::EPSILONR ) - 1.0 ) ) );
559 P_9 = P_8
560 - 0.7913 * ( 1.0 - exp( -pow( f_n / 20.0, 1.424 ) ) )
561 * atan( 2.481 * pow( GetParameter( TCP::EPSILONR ) / 8.0, 0.946 ) );
562 P_10 = 0.242 * pow( GetParameter( TCP::EPSILONR ) - 1.0, 0.55 );
563 P_11 = 0.6366 * ( exp( -0.3401 * f_n ) - 1.0 ) * atan( 1.263 * pow( u / 3.0, 1.629 ) );
564 P_12 = P_9 + ( 1.0 - P_9 ) / ( 1.0 + 1.183 * pow( u, 1.376 ) );
565 P_13 = 1.695 * P_10 / ( 0.414 + 1.605 * P_10 );
566 P_14 = 0.8928 + 0.1072 * ( 1.0 - exp( -0.42 * pow( f_n / 20.0, 3.215 ) ) );
567 P_15 = fabs( 1.0 - 0.8928 * ( 1.0 + P_11 ) * P_12 * exp( -P_13 * pow( g, 1.092 ) ) / P_14 );
568
569 F_o = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 ) * f_n * P_15, 1.5763 );
570 /* odd-mode effective dielectric constant */
571 er_eff_o = GetParameter( TCP::EPSILONR ) - ( GetParameter( TCP::EPSILONR ) - er_eff ) / ( 1.0 + F_o );
573}
574
575
577{
578 double e_r_eff_e_0, e_r_eff_o_0, Z0_h_e, Z0_h_o, delta;
579 double K, R_s, Q_c_e, Q_c_o, alpha_c_e, alpha_c_o;
580
581 e_r_eff_e_0 = er_eff_e_0;
582 e_r_eff_o_0 = er_eff_o_0;
583 Z0_h_e = Z0_e_0 * sqrt( e_r_eff_e_0 ); /* homogeneous stripline impedance */
584 Z0_h_o = Z0_o_0 * sqrt( e_r_eff_o_0 ); /* homogeneous stripline impedance */
586
587 if( GetParameter( TCP::FREQUENCY ) > 0.0 )
588 {
589 /* current distribution factor (same for the two modes) */
590 K = exp( -1.2 * pow( ( Z0_h_e + Z0_h_o ) / ( 2.0 * TC::ZF0 ), 0.7 ) );
591 /* skin resistance */
592 R_s = 1.0 / ( GetParameter( TCP::SIGMA ) * delta );
593 /* correction for surface roughness */
594 R_s *= 1.0 + ( ( 2.0 / M_PI ) * atan( 1.40 * pow( ( GetParameter( TCP::ROUGH ) / delta ), 2.0 ) ) );
595
596 /* even-mode strip inductive quality factor */
597 Q_c_e = ( M_PI * Z0_h_e * GetParameter( TCP::PHYS_WIDTH ) * GetParameter( TCP::FREQUENCY ) )
598 / ( R_s * TC::C0 * K );
599 /* even-mode losses per unit length */
600 alpha_c_e = ( 20.0 * M_PI / log( 10.0 ) ) * GetParameter( TCP::FREQUENCY ) * sqrt( e_r_eff_e_0 )
601 / ( TC::C0 * Q_c_e );
602
603 /* odd-mode strip inductive quality factor */
604 Q_c_o = ( M_PI * Z0_h_o * GetParameter( TCP::PHYS_WIDTH ) * GetParameter( TCP::FREQUENCY ) )
605 / ( R_s * TC::C0 * K );
606 /* odd-mode losses per unit length */
607 alpha_c_o = ( 20.0 * M_PI / log( 10.0 ) ) * GetParameter( TCP::FREQUENCY ) * sqrt( e_r_eff_o_0 )
608 / ( TC::C0 * Q_c_o );
609 }
610 else
611 {
612 alpha_c_e = alpha_c_o = 0.0;
613 }
614
615 atten_cond_e = alpha_c_e * GetParameter( TCP::PHYS_LEN );
616 atten_cond_o = alpha_c_o * GetParameter( TCP::PHYS_LEN );
617}
618
619
621{
622 double e_r, e_r_eff_e_0, e_r_eff_o_0;
623 double alpha_d_e, alpha_d_o;
624
626 e_r_eff_e_0 = er_eff_e_0;
627 e_r_eff_o_0 = er_eff_o_0;
628
629 alpha_d_e = ( 20.0 * M_PI / log( 10.0 ) ) * ( GetParameter( TCP::FREQUENCY ) / TC::C0 )
630 * ( e_r / sqrt( e_r_eff_e_0 ) ) * ( ( e_r_eff_e_0 - 1.0 ) / ( e_r - 1.0 ) ) * GetParameter( TCP::TAND );
631 alpha_d_o = ( 20.0 * M_PI / log( 10.0 ) ) * ( GetParameter( TCP::FREQUENCY ) / TC::C0 )
632 * ( e_r / sqrt( e_r_eff_o_0 ) ) * ( ( e_r_eff_o_0 - 1.0 ) / ( e_r - 1.0 ) ) * GetParameter( TCP::TAND );
633
636}
637
638
645
646
648{
649 double e_r_eff_e, e_r_eff_o;
650 double v_e, v_o, lambda_g_e, lambda_g_o;
651
652 e_r_eff_e = er_eff_e;
653 e_r_eff_o = er_eff_o;
654
655 /* even-mode velocity */
656 v_e = TC::C0 / sqrt( e_r_eff_e );
657 /* odd-mode velocity */
658 v_o = TC::C0 / sqrt( e_r_eff_o );
659 /* even-mode wavelength */
660 lambda_g_e = v_e / GetParameter( TCP::FREQUENCY );
661 /* odd-mode wavelength */
662 lambda_g_o = v_o / GetParameter( TCP::FREQUENCY );
663 /* electrical angles */
664 ang_l_e = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g_e; /* in radians */
665 ang_l_o = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g_o; /* in radians */
666}
667
668
670{
671 // Differential impedance of a coupled pair driven in odd mode is exactly twice the
672 // odd-mode characteristic impedance (Pozar, "Microwave Engineering" 4th ed., §7.6).
673 // Odd mode is not the same as single-ended impedance, so avoid approximations found
674 // on websites that use static single ended impedance as the starting point.
675 // Read the dispersed Z0_O left by Z0_dispersion() rather than the static Z0_o_0 so
676 // Zdiff tracks frequency above a few GHz where Kirschning-Jansen raises the odd-mode
677 // impedance by several percent.
678
679 Zdiff = 2.0 * GetParameter( TCP::Z0_O );
680}
681
682
683/*
684 * Z0_dispersion() - calculate frequency dependency of characteristic impedances.
685 *
686 * Kirschning & Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent
687 * Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT 32(1):83-90,
688 * Jan. 1984 (errata: MTT 33(3):288, Mar. 1985). The Q_0..Q_29 closed-form chain below
689 * implements the dispersive even- and odd-mode impedance correction tables from that
690 * paper.
691 */
693{
694 double Q_0;
695 double Q_11, Q_12, Q_13, Q_14, Q_15, Q_16, Q_17, Q_18, Q_19, Q_20, Q_21;
696 double Q_22, Q_23, Q_24, Q_25, Q_26, Q_27, Q_28, Q_29;
697 double r_e, q_e, p_e, d_e, C_e;
698 double e_r_eff_o_f, e_r_eff_o_0;
699 double e_r_eff_single_f, e_r_eff_single_0, Z0_single_f;
700 double f_n, g, u, e_r;
701 double R_1, R_2, R_7, R_10, R_11, R_12, R_15, R_16, tmpf;
702
704
705 u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalize line width */
706 g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalize line spacing */
707
708 /* normalized frequency [GHz * mm] */
709 f_n = GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::H ) / 1e06;
710
711 e_r_eff_single_f = m_aux_microstrip.GetParameter( TCP::EPSILON_EFF );
712 e_r_eff_single_0 = m_aux_microstrip.er_eff_0;
713 Z0_single_f = m_aux_microstrip.GetParameter( TCP::Z0 );
714
715 e_r_eff_o_f = er_eff_o;
716 e_r_eff_o_0 = er_eff_o_0;
717
718 Q_11 = 0.893 * ( 1.0 - 0.3 / ( 1.0 + 0.7 * ( e_r - 1.0 ) ) );
719 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 )
720 * pow( g, 0.902 );
721 Q_13 = 1.0 + 0.038 * pow( e_r / 8.0, 5.1 );
722 Q_14 = 1.0 + 1.203 * pow( e_r / 15.0, 4.0 ) / ( 1.0 + pow( e_r / 15.0, 4.0 ) );
723 Q_15 = 1.887 * exp( -1.5 * pow( g, 0.84 ) ) * pow( g, Q_14 )
724 / ( 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 ) ) );
725 Q_16 = ( 1.0 + 9.0 / ( 1.0 + 0.403 * pow( e_r - 1.0, 2 ) ) ) * Q_15;
726 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 ) ) );
727 Q_18 = 0.61 * ( 1.0 - exp( -2.13 * pow( u / 8.0, 1.593 ) ) ) / ( 1.0 + 6.544 * pow( g, 4.17 ) );
728 Q_19 = 0.21 * g * g * g * g
729 / ( ( 1.0 + 0.18 * pow( g, 4.9 ) ) * ( 1.0 + 0.1 * u * u ) * ( 1.0 + pow( f_n / 24.0, 3.0 ) ) );
730 Q_20 = ( 0.09 + 1.0 / ( 1.0 + 0.1 * pow( e_r - 1, 2.7 ) ) ) * Q_19;
731 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 ) ) );
732
733 r_e = pow( f_n / 28.843, 12 );
734 q_e = 0.016 + pow( 0.0514 * e_r * Q_21, 4.524 );
735 p_e = 4.766 * exp( -3.228 * pow( u, 0.641 ) );
736 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 ) )
737 * ( pow( e_r - 1.0, 6.0 ) / ( 1.0 + 10 * pow( e_r - 1.0, 6.0 ) ) );
738 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
739 - Q_17 + Q_18 + Q_20;
740
741
742 R_1 = 0.03891 * pow( e_r, 1.4 );
743 R_2 = 0.267 * pow( u, 7.0 );
744 R_7 = 1.206 - 0.3144 * exp( -R_1 ) * ( 1.0 - exp( -R_2 ) );
745 R_10 = 0.00044 * pow( e_r, 2.136 ) + 0.0184;
746 tmpf = pow( f_n / 19.47, 6.0 );
747 R_11 = tmpf / ( 1.0 + 0.0962 * tmpf );
748 R_12 = 1.0 / ( 1.0 + 0.00245 * u * u );
749 R_15 = 0.707 * R_10 * pow( f_n / 12.3, 1.097 );
750 R_16 = 1.0 + 0.0503 * e_r * e_r * R_11 * ( 1.0 - exp( -pow( u / 15.0, 6.0 ) ) );
751 Q_0 = R_7 * ( 1.0 - 1.1241 * ( R_12 / R_16 ) * exp( -0.026 * pow( f_n, 1.15656 ) - R_15 ) );
752
753 /* even-mode frequency-dependent characteristic impedances */
754 SetParameter( TCP::Z0_E, Z0_e_0 * pow( 0.9408 * pow( e_r_eff_single_f, C_e ) - 0.9603, Q_0 )
755 / pow( ( 0.9408 - d_e ) * pow( e_r_eff_single_0, C_e ) - 0.9603, Q_0 ) );
756
757 Q_29 = 15.16 / ( 1.0 + 0.196 * pow( e_r - 1.0, 2.0 ) );
758 tmpf = pow( e_r - 1.0, 3.0 );
759 Q_28 = 0.149 * tmpf / ( 94.5 + 0.038 * tmpf );
760 tmpf = pow( e_r - 1.0, 1.5 );
761 Q_27 = 0.4 * pow( g, 0.84 ) * ( 1.0 + 2.5 * tmpf / ( 5.0 + tmpf ) );
762 tmpf = pow( ( e_r - 1.0 ) / 13.0, 12.0 );
763 Q_26 = 30.0 - 22.2 * ( tmpf / ( 1.0 + 3.0 * tmpf ) ) - Q_29;
764 tmpf = ( e_r - 1.0 ) * ( e_r - 1.0 );
765 Q_25 = ( 0.3 * f_n * f_n / ( 10.0 + f_n * f_n ) ) * ( 1.0 + 2.333 * tmpf / ( 5.0 + tmpf ) );
766 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 ) );
767 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 ) );
768 Q_22 = 0.925 * pow( f_n / Q_26, 1.536 ) / ( 1.0 + 0.3 * pow( f_n / 30.0, 1.536 ) );
769
770 /* odd-mode frequency-dependent characteristic impedances */
771 SetParameter( TCP::Z0_O, Z0_single_f
772 + ( Z0_o_0 * pow( e_r_eff_o_f / e_r_eff_o_0, Q_22 ) - Z0_single_f * Q_23 )
773 / ( 1.0 + Q_24 + pow( 0.46 * g, 2.2 ) * Q_25 ) );
774}
775
776
777void COUPLED_MICROSTRIP::syn_err_fun( double* f1, double* f2, double s_h, double w_h, double e_r, double w_h_se,
778 double w_h_so )
779{
780 double g, he;
781
782 g = cosh( 0.5 * M_PI * s_h );
783 he = cosh( M_PI * w_h + 0.5 * M_PI * s_h );
784
785 *f1 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g + 1.0 ) / ( g + 1.0 ) );
786 *f2 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g - 1.0 ) / ( g - 1.0 ) );
787
788 if( e_r <= 6.0 )
789 *f2 += ( 4.0 / ( M_PI * ( 1.0 + e_r / 2.0 ) ) ) * acosh( 1.0 + 2.0 * w_h / s_h );
790 else
791 *f2 += ( 1.0 / M_PI ) * acosh( 1.0 + 2.0 * w_h / s_h );
792
793 *f1 -= w_h_se;
794 *f2 -= w_h_so;
795}
796
797
799{
800 double Z0, e_r;
801 double w_h_se, w_h_so, w_h, a, ce, co, s_h;
802 double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err;
803 double eps = 1e-04;
804
805 f1 = f2 = 0;
807
808 Z0 = GetParameter( TCP::Z0_E ) / 2.0;
809 /* Wheeler formula for single microstrip synthesis */
810 a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0;
811 w_h_se = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a;
812
813 Z0 = GetParameter( TCP::Z0_O ) / 2.0;
814 /* Wheeler formula for single microstrip synthesis */
815 a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0;
816 w_h_so = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a;
817
818 ce = cosh( 0.5 * M_PI * w_h_se );
819 co = cosh( 0.5 * M_PI * w_h_so );
820 /* first guess at m_parameters[PHYS_S )/h */
821 s_h = ( 2.0 / M_PI ) * acosh( ( ce + co - 2.0 ) / ( co - ce ) );
822 /* first guess at w/h */
823 w_h = acosh( ( ce * co - 1.0 ) / ( co - ce ) ) / M_PI - s_h / 2.0;
824
827
828 syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so );
829
830 /* rather crude Newton-Rhapson; we need this because the estimate of */
831 /* w_h is often quite far from the true value (see Akhtarzad S. et al.) */
832 do
833 {
834 /* compute Jacobian */
835 syn_err_fun( &ft1, &ft2, s_h + eps, w_h, e_r, w_h_se, w_h_so );
836 j11 = ( ft1 - f1 ) / eps;
837 j21 = ( ft2 - f2 ) / eps;
838 syn_err_fun( &ft1, &ft2, s_h, w_h + eps, e_r, w_h_se, w_h_so );
839 j12 = ( ft1 - f1 ) / eps;
840 j22 = ( ft2 - f2 ) / eps;
841
842 /* compute next step */
843 d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 );
844 d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 );
845
846 //g_print("j11 = %e\tj12 = %e\tj21 = %e\tj22 = %e\n", j11, j12, j21, j22);
847 //g_print("det = %e\n", j11*j22 - j21*j22);
848 //g_print("d_s_h = %e\td_w_h = %e\n", d_s_h, d_w_h);
849
850 s_h += d_s_h;
851 w_h += d_w_h;
852
853 /* check the error */
854 syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so );
855
856 err = sqrt( f1 * f1 + f2 * f2 );
857 /* converged ? */
858 } while( err > 1e-04 );
859
860
863}
864
865
866void COUPLED_MICROSTRIP::syn_fun( double* f1, double* f2, double s_h, double w_h, double Z0_e, double Z0_o )
867{
870
871 /* compute coupled microstrip parameters */
872 Analyse();
873
874 *f1 = GetParameter( TCP::Z0_E ) - Z0_e;
875 *f2 = GetParameter( TCP::Z0_O ) - Z0_o;
876}
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:37
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.