KiCad PCB EDA Suite
Loading...
Searching...
No Matches
coupled_stripline.cpp
Go to the documentation of this file.
1/*
2 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (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 package; see the file COPYING. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20/*
21 * This implements the calculations described in:
22 *
23 * [1] S. B. Cohn, "Characteristic Impedance of the Shielded-Strip Transmission Line," in Transactions of the IRE
24 * Professional Group on Microwave Theory and Techniques, vol. 2, no. 2, pp. 52-57, July 1954
25 * [2] S. B. Cohn, "Shielded Coupled-Strip Transmission Line," in IRE Transactions on Microwave Theory and Techniques,
26 * vol. 3, no. 5, pp. 29-38, October 1955
27 */
28
32
33
34namespace TC = TRANSLINE_CALCULATIONS;
36
37
39{
40 // Calculate skin depth
41 SetParameter( TCP::SKIN_DEPTH, SkinDepth() );
42
43 // Get analysis parameters
44 double w = GetParameter( TCP::PHYS_WIDTH );
45 double t = GetParameter( TCP::T );
46 double s = GetParameter( TCP::PHYS_S );
47 double h = GetParameter( TCP::H );
48 const double er = GetParameter( TCP::EPSILONR );
49
51
52 // We've got the impedances now for an infinitely thin line
53 if( t == 0.0 )
54 {
55 SetParameter( TCP::Z0_E, Z0_e_w_h_0_s_h );
56 SetParameter( TCP::Z0_O, Z0_o_w_h_0_s_h );
57 }
58 else
59 {
61 calcFringeCapacitances( h, t, er );
63 calcZ0OddMode( t, s );
64 }
65
66 calcLosses();
68}
69
70
72{
73 if( aOpts == SYNTHESIZE_OPTS::FIX_WIDTH )
74 return MinimiseZ0Error1D( TCP::PHYS_S, TCP::Z0_O );
75
76 if( aOpts == SYNTHESIZE_OPTS::FIX_SPACING )
77 return MinimiseZ0Error1D( TCP::PHYS_WIDTH, TCP::Z0_O );
78
79 // This synthesis approach is modified from wcalc, which is released under GPL version 2
80 // Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006 Dan McMahill
81 // All rights reserved
82
83 double ze0 = 0;
84 double zo0 = 0;
85
86 const double h = GetParameter( TCP::H );
87 const double er = GetParameter( TCP::EPSILONR );
88
89 const double z0e_target = GetParameter( TCP::Z0_E );
90 const double z0o_target = GetParameter( TCP::Z0_O );
91 // Calculate Z0 and coupling, k
92 const double z0 = sqrt( z0e_target * z0o_target );
93 const double k = ( z0e_target - z0o_target ) / ( z0e_target + z0o_target );
94
95 int maxiters = 50;
96
97 // Initial guess at a solution. Note that this is an initial guess for coupled microstrip, not coupled stripline...
98 static constexpr double ai[] = { 1, -0.301, 3.209, -27.282, 56.609, -37.746 };
99 static constexpr double bi[] = { 0.020, -0.623, 17.192, -68.946, 104.740, -16.148 };
100 static constexpr double ci[] = { 0.002, -0.347, 7.171, -36.910, 76.132, -51.616 };
101
102 const double AW = exp( z0 * sqrt( er + 1.0 ) / 42.4 ) - 1.0;
103 const double F1 = 8.0 * sqrt( AW * ( 7.0 + 4.0 / er ) / 11.0 + ( 1.0 + 1.0 / er ) / 0.81 ) / AW;
104
105 double F2 = 0.0, F3 = 0.0;
106 ;
107
108 for( int i = 0; i <= 5; i++ )
109 F2 = F2 + ai[i] * pow( k, i );
110
111 for( int i = 0; i <= 5; i++ )
112 F3 = F3 + ( bi[i] - ci[i] * ( 9.6 - er ) ) * pow( ( 0.6 - k ), static_cast<double>( i ) );
113
114 double w = h * fabs( F1 * F2 );
115 double s = h * fabs( F1 * F3 );
116
117 int iters = 0;
118 bool done = false;
119 double delta = 0.0;
120
121 delta = TC::UNIT_MIL * 1e-5;
122
123 const double cval = 1e-12 * z0e_target * z0o_target;
124
125 while( !done && iters < maxiters )
126 {
127 iters++;
128
129 // Compute impedances with initial solution guess
130 SetParameter( TCP::PHYS_WIDTH, w );
131 SetParameter( TCP::PHYS_S, s );
132 Analyse();
133
134 // Check for convergence
135 ze0 = GetParameter( TCP::Z0_E );
136 zo0 = GetParameter( TCP::Z0_O );
137 const double err = pow( ( ze0 - z0e_target ), 2.0 ) + pow( ( zo0 - z0o_target ), 2.0 );
138
139 if( err < cval )
140 {
141 done = true;
142 }
143 else
144 {
145 // Approximate the first Jacobian
146 SetParameter( TCP::PHYS_WIDTH, w + delta );
147 SetParameter( TCP::PHYS_S, s );
148 Analyse();
149
150 const double ze1 = GetParameter( TCP::Z0_E );
151 const double zo1 = GetParameter( TCP::Z0_O );
152
153 SetParameter( TCP::PHYS_WIDTH, w );
154 SetParameter( TCP::PHYS_S, s + delta );
155 Analyse();
156
157 const double ze2 = GetParameter( TCP::Z0_E );
158 const double zo2 = GetParameter( TCP::Z0_O );
159
160 const double dedw = ( ze1 - ze0 ) / delta;
161 const double dodw = ( zo1 - zo0 ) / delta;
162 const double deds = ( ze2 - ze0 ) / delta;
163 const double dods = ( zo2 - zo0 ) / delta;
164
165 // Find the determinate
166 const double d = dedw * dods - deds * dodw;
167
168 // Estimate the new solution, but don't change by more than 10% at a time to avoid convergence problems
169 double dw = -1.0 * ( ( ze0 - z0e_target ) * dods - ( zo0 - z0o_target ) * deds ) / d;
170
171 if( fabs( dw ) > 0.1 * w )
172 {
173 if( dw > 0.0 )
174 dw = 0.1 * w;
175 else
176 dw = -0.1 * w;
177 }
178
179 w = fabs( w + dw );
180
181 double ds = ( ( ze0 - z0e_target ) * dodw - ( zo0 - z0o_target ) * dedw ) / d;
182
183 if( fabs( ds ) > 0.1 * s )
184 {
185 if( ds > 0.0 )
186 ds = 0.1 * s;
187 else
188 ds = -0.1 * s;
189 }
190
191 s = fabs( s + ds );
192 }
193 }
194
195 if( !done )
196 return false;
197
198 // Recompute with the final parameters
199 SetParameter( TCP::PHYS_WIDTH, w );
200 SetParameter( TCP::PHYS_S, s );
201 Analyse();
202
203 // Reset the impedances
204 SetParameter( TCP::Z0_E, z0e_target );
205 SetParameter( TCP::Z0_O, z0o_target );
206
207 return true;
208}
209
210
212{
213 SetAnalysisResult( TCP::EPSILON_EFF_EVEN, e_eff_e );
214 SetAnalysisResult( TCP::EPSILON_EFF_ODD, e_eff_o );
215 SetAnalysisResult( TCP::UNIT_PROP_DELAY_EVEN, unit_prop_delay_e );
216 SetAnalysisResult( TCP::UNIT_PROP_DELAY_ODD, unit_prop_delay_o );
217 SetAnalysisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) );
218
219 const double Z0_E = GetParameter( TCP::Z0_E );
220 const double Z0_O = GetParameter( TCP::Z0_O );
221 const double Z_DIFF = GetParameter( TCP::Z_DIFF );
222 const double W = GetParameter( TCP::PHYS_WIDTH );
223 const double L = GetParameter( TCP::PHYS_LEN );
224 const double S = GetParameter( TCP::PHYS_S );
225
226 const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0;
227 const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0;
228 const bool Z_DIFF_invalid = !std::isfinite( Z_DIFF ) || Z_DIFF <= 0;
229 const bool ANG_L_invalid = !std::isfinite( ang_l ) || ang_l < 0;
230 const bool W_invalid = !std::isfinite( W ) || W <= 0;
231 const bool L_invalid = !std::isfinite( L ) || L < 0;
232 const bool S_invalid = !std::isfinite( S ) || S <= 0;
233
234 SetAnalysisResult( TCP::Z0_E, Z0_E, Z0_E_invalid ? TRANSLINE_STATUS::TS_ERROR : TRANSLINE_STATUS::OK );
235 SetAnalysisResult( TCP::Z0_O, Z0_O, Z0_O_invalid ? TRANSLINE_STATUS::TS_ERROR : TRANSLINE_STATUS::OK );
236 SetAnalysisResult( TCP::Z_DIFF, Z_DIFF, Z_DIFF_invalid ? TRANSLINE_STATUS::TS_ERROR : TRANSLINE_STATUS::OK );
237 SetAnalysisResult( TCP::ANG_L, ang_l, ANG_L_invalid ? TRANSLINE_STATUS::TS_ERROR : TRANSLINE_STATUS::OK );
238 SetAnalysisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
239 SetAnalysisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
240 SetAnalysisResult( TCP::PHYS_S, S, S_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
241}
242
243
245{
246 SetSynthesisResult( TCP::EPSILON_EFF_EVEN, e_eff_e );
247 SetSynthesisResult( TCP::EPSILON_EFF_ODD, e_eff_o );
248 SetSynthesisResult( TCP::UNIT_PROP_DELAY_EVEN, unit_prop_delay_e );
249 SetSynthesisResult( TCP::UNIT_PROP_DELAY_ODD, unit_prop_delay_o );
250 SetSynthesisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) );
251
252 const double Z0_E = GetParameter( TCP::Z0_E );
253 const double Z0_O = GetParameter( TCP::Z0_O );
254 const double Z_DIFF = GetParameter( TCP::Z_DIFF );
255 const double W = GetParameter( TCP::PHYS_WIDTH );
256 const double L = GetParameter( TCP::PHYS_LEN );
257 const double S = GetParameter( TCP::PHYS_S );
258
259 const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0;
260 const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0;
261 const bool Z_DIFF_invalid = !std::isfinite( Z_DIFF ) || Z_DIFF <= 0;
262 const bool ANG_L_invalid = !std::isfinite( ang_l ) || ang_l < 0;
263 const bool W_invalid = !std::isfinite( W ) || W <= 0;
264 const bool L_invalid = !std::isfinite( L ) || L < 0;
265 const bool S_invalid = !std::isfinite( S ) || S <= 0;
266
267 SetSynthesisResult( TCP::Z0_E, Z0_E, Z0_E_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
268 SetSynthesisResult( TCP::Z0_O, Z0_O, Z0_O_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
269 SetSynthesisResult( TCP::Z_DIFF, Z_DIFF, Z_DIFF_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
270 SetSynthesisResult( TCP::ANG_L, ang_l, ANG_L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
271 SetSynthesisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::TS_ERROR : TRANSLINE_STATUS::OK );
272 SetSynthesisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::TS_ERROR : TRANSLINE_STATUS::OK );
273 SetSynthesisResult( TCP::PHYS_S, S, S_invalid ? TRANSLINE_STATUS::TS_ERROR : TRANSLINE_STATUS::OK );
274}
275
276
277void COUPLED_STRIPLINE::calcFringeCapacitances( const double h, const double t, const double er )
278{
279 // Reference [1], Eq. 2
280 C_f_t_h = ( TC::E0 * er / M_PI )
281 * ( ( 2.0 / ( 1.0 - t / h ) ) * log( ( 1.0 / ( 1.0 - t / h ) ) + 1.0 )
282 - ( 1.0 / ( 1.0 - t / h ) - 1.0 ) * log( ( 1.0 / pow( 1.0 - t / h, 2.0 ) ) - 1.0 ) );
283
284 // Reference [2], Eq. 13
285 C_f_0 = ( TC::E0 * er / M_PI ) * 2.0 * log( 2.0 );
286}
287
288
289void COUPLED_STRIPLINE::calcZeroThicknessCoupledImpedances( const double h, const double w, const double s,
290 const double er )
291{
292 // Reference [2], Eqs. 2 - 7
293 const double k_e = tanh( M_PI * w / ( 2.0 * h ) ) * tanh( M_PI * ( w + s ) / ( 2.0 * h ) );
294 const double k_o = tanh( M_PI * w / ( 2.0 * h ) ) * coth( M_PI * ( w + s ) / ( 2.0 * h ) );
295 const double k_e_p = std::sqrt( 1 - std::pow( k_e, 2 ) );
296 const double k_o_p = std::sqrt( 1 - std::pow( k_o, 2 ) );
297 Z0_e_w_h_0_s_h = ( TC::ZF0 / ( 4.0 * std::sqrt( er ) ) )
298 * ( EllipticIntegral( k_e_p ).first / EllipticIntegral( k_e ).first );
299 Z0_o_w_h_0_s_h = ( TC::ZF0 / ( 4.0 * std::sqrt( er ) ) )
300 * ( EllipticIntegral( k_o_p ).first / EllipticIntegral( k_o ).first );
301}
302
303
305{
306 const double er = GetParameter( TCP::EPSILONR );
307 const double h = GetParameter( TCP::H );
308 const double w = GetParameter( TCP::PHYS_WIDTH );
309
310 // Finite-thickness single strip impedance
312
313 // Zero-thickness single strip impedance
314 // Reference [1], Eqs. 5 - 6 (corrected for sqrt(e_r))
315 const double k = sech( M_PI * w / ( 2.0 * h ) );
316 const double k_p = tanh( M_PI * w / ( 2.0 * h ) );
317 Z0_w_h_0 =
318 ( TC::ZF0 / ( 4.0 * std::sqrt( er ) ) ) * ( EllipticIntegral( k ).first / EllipticIntegral( k_p ).first );
319}
320
321
323{
324 // Reference [2], Eq. 18
325 const double Z_e =
326 1.0 / ( ( 1.0 / Z0_w_h_t_h ) - ( C_f_t_h / C_f_0 ) * ( ( 1.0 / Z0_w_h_0 ) - ( 1.0 / Z0_e_w_h_0_s_h ) ) );
327 SetParameter( TCP::Z0_E, Z_e );
328}
329
330
331void COUPLED_STRIPLINE::calcZ0OddMode( const double t, const double s )
332{
333 // Reference [2], Eq. 20
334 const double Z_o_1 =
335 1.0 / ( ( 1.0 / Z0_w_h_t_h ) + ( C_f_t_h / C_f_0 ) * ( ( 1.0 / Z0_o_w_h_0_s_h ) - ( 1.0 / Z0_w_h_0 ) ) );
336
337 // Reference [2], Eq. 22
338 const double Z_o_2 =
339 1.0
340 / ( ( 1.0 / Z0_o_w_h_0_s_h ) + ( ( 1.0 / Z0_w_h_t_h ) - ( 1.0 / Z0_w_h_0 ) )
341 - ( 2.0 / TC::ZF0 ) * ( C_f_t_h / TC::E0 - C_f_0 / TC::E0 ) + ( 2.0 * t ) / ( TC::ZF0 * s ) );
342
343 const double Z_o = s / t >= 5.0 ? Z_o_1 : Z_o_2;
344
345 SetParameter( TCP::Z0_O, Z_o );
346 SetParameter( TCP::Z_DIFF, 2.0 * Z_o );
347}
348
349
351{
352}
353
354
356{
357 // We assume here that the dielectric is homogenous surrounding the strips - in this case, the odd or even modes
358 // don't change the effective dielectric constant of the transmission mode. This would not be the case if the
359 // dielectric were inhomogenous, as there is more electric field permeating the dielectric between the traces in
360 // the odd mode compared to the even mode.
361 const double e_r = GetParameter( TCP::EPSILONR );
362 e_eff_e = e_r;
363 e_eff_o = e_r;
364
365 // Both modes have the same propagation delay
366 const double unitPropDelay = UnitPropagationDelay( e_r );
367 unit_prop_delay_e = unitPropDelay;
368 unit_prop_delay_o = unitPropDelay;
369
370 // Electrical length (in radians)
371 const double v = TC::C0 / sqrt( e_r );
372 const double lambda_g = v / GetParameter( TCP::FREQUENCY );
373 ang_l = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g;
374}
375
376
378{
379 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, GetParameter( TCP::EPSILONR ) );
380 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, GetParameter( TCP::T ) );
381 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::STRIPLINE_A, GetParameter( TCP::H ) / 2.0 );
382 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::H, GetParameter( TCP::H ) );
383 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::PHYS_LEN, GetParameter( TCP::PHYS_LEN ) );
384 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, GetParameter( TCP::FREQUENCY ) );
385 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, 0.0 );
386 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::PHYS_WIDTH, GetParameter( TCP::PHYS_WIDTH ) );
387 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, 0 );
388 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, GetParameter( TCP::SIGMA ) );
389 m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::MURC, GetParameter( TCP::MURC ) );
391
392 return m_striplineCalc.GetParameter( TCP::Z0 );
393}
void Analyse() override
Analyse track geometry parameters to output Z0 and Ang_L.
double C_f_t_h
Fringing capacitance of single strip of finite width.
void calcLosses()
Calculates conductor and dielectric losses.
void SetSynthesisResults() override
Sets the output values and status following synthesis.
STRIPLINE m_striplineCalc
Calculator used to determine single stripline values.
double unit_prop_delay_o
Odd mode unit propagation delay (ps/cm)
bool Synthesize(SYNTHESIZE_OPTS aOpts) override
Synthesis track geometry parameters to match given Z0.
void calcFringeCapacitances(double h, double t, double er)
Calculate the coupling fringe capacitances.
double Z0_o_w_h_0_s_h
Odd mode impedance of coupled zero thickness strips.
double Z0_w_h_t_h
Impedance of single strip of finite thickness.
void calcZ0EvenMode()
Calculates even mode Z0.
void calcDielectrics()
Calculate dialectric and propagation parameters.
double Z0_w_h_0
Impedance of single strip of zero thickness.
void calcSingleStripImpedances()
Calculates impedances of finite- and zero-thickness single strips.
double e_eff_e
Even mode effective dielectric constant.
void calcZ0OddMode(double t, double s)
Calculates odd mode Z0.
void SetAnalysisResults() override
Sets the output values and status following analysis.
double C_f_0
Fringing capacitance from one edge to ground of zero thickness strip.
double e_eff_o
Odd mode effective dielectric constant.
double Z0_e_w_h_0_s_h
Even mode impedance of coupled zero thickness strips.
double calcZ0SymmetricStripline()
Calculates the impedance of a finite-width single strip.
double ang_l
Angular length (rad)
void calcZeroThicknessCoupledImpedances(double h, double w, double s, double er)
Calculates zero-thickness coupled strip impedances.
double unit_prop_delay_e
Even mode unit propagation delay (ps/cm)
void Analyse() override
Analyse track geometry parameters to output Z0 and Ang_L.
static double coth(const double x)
Calculates cosh of the given argument.
double GetParameter(const TRANSLINE_PARAMETERS aParam) const
Gets the given calculation property.
static double sech(const double x)
Calculates sech of the given argument.
static std::pair< double, double > EllipticIntegral(double arg)
Computes the complete elliptic integral of first kind K() and the second kind E() using the arithmeti...
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.
bool MinimiseZ0Error1D(TRANSLINE_PARAMETERS aOptimise, TRANSLINE_PARAMETERS aMeasure)
minimizeZ0Error1D
double SkinDepth() const
Calculate skin depth.
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.
int delta
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.