KiCad PCB EDA Suite
coplanar.cpp
Go to the documentation of this file.
1 /*
2  * coplanar.cpp - coplanar class implementation
3  *
4  * Copyright (C) 2008 Michael Margraf <[email protected]>
5  * Copyright (C) 2005, 2006 Stefan Jahn <[email protected]>
6  * Modified for Kicad: 2011 jean-pierre.charras
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or (at
11  * your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * 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  */
24 
25 
26 #include <cmath>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <cstring>
30 
31 #include "coplanar.h"
32 #include "units.h"
33 
35 {
36  m_Name = "CoPlanar";
37  backMetal = false;
38  Init();
39 }
40 
41 
43 {
44  m_Name = "GrCoPlanar";
45  backMetal = true;
46 }
47 
48 
49 // -------------------------------------------------------------------
51 {
53 
54  // other local variables (quasi-static constants)
55  double k1, kk1, kpk1, k2, k3, q1, q2, q3 = 0, qz, er0 = 0;
56  double zl_factor;
57 
58  // compute the necessary quasi-static approx. (K1, K3, er(0) and Z(0))
61  kk1 = ellipk( k1 );
62  kpk1 = ellipk( sqrt( 1 - k1 * k1 ) );
63  q1 = kk1 / kpk1;
64 
65 
66  // backside is metal
67  if( backMetal )
68  {
69  k3 = tanh( ( M_PI / 4 ) * ( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] ) )
70  / tanh( ( M_PI / 4 )
73  / m_parameters[H_PRM] );
74  q3 = ellipk( k3 ) / ellipk( sqrt( 1 - k3 * k3 ) );
75  qz = 1 / ( q1 + q3 );
76  er0 = 1 + q3 * qz * ( m_parameters[EPSILONR_PRM] - 1 );
77  zl_factor = ZF0 / 2 * qz;
78  }
79  // backside is air
80  else
81  {
82  k2 = sinh( ( M_PI / 4 ) * ( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] ) )
83  / sinh( ( M_PI / 4 )
86  / m_parameters[H_PRM] );
87  q2 = ellipk( k2 ) / ellipk( sqrt( 1 - k2 * k2 ) );
88  er0 = 1 + ( m_parameters[EPSILONR_PRM] - 1 ) / 2 * q2 / q1;
89  zl_factor = ZF0 / 4 / q1;
90  }
91 
92 
93  // adds effect of strip thickness
94  if( m_parameters[T_PRM] > 0 )
95  {
96  double d, se, We, ke, qe;
97  d = ( m_parameters[T_PRM] * 1.25 / M_PI )
98  * ( 1 + log( 4 * M_PI * m_parameters[PHYS_WIDTH_PRM] / m_parameters[T_PRM] ) );
99  se = m_parameters[PHYS_S_PRM] - d;
100  We = m_parameters[PHYS_WIDTH_PRM] + d;
101 
102  // modifies k1 accordingly (k1 = ke)
103  ke = We / ( We + se + se ); // ke = k1 + (1 - k1 * k1) * d / 2 / s;
104  qe = ellipk( ke ) / ellipk( sqrt( 1 - ke * ke ) );
105 
106  // backside is metal
107  if( backMetal )
108  {
109  qz = 1 / ( qe + q3 );
110  er0 = 1 + q3 * qz * ( m_parameters[EPSILONR_PRM] - 1 );
111  zl_factor = ZF0 / 2 * qz;
112  }
113  // backside is air
114  else
115  {
116  zl_factor = ZF0 / 4 / qe;
117  }
118 
119  // modifies er0 as well
120  er0 = er0
121  - ( 0.7 * ( er0 - 1 ) * m_parameters[T_PRM] / m_parameters[PHYS_S_PRM] )
122  / ( q1 + ( 0.7 * m_parameters[T_PRM] / m_parameters[PHYS_S_PRM] ) );
123  }
124 
125  // pre-compute square roots
126  double sr_er = sqrt( m_parameters[EPSILONR_PRM] );
127  double sr_er0 = sqrt( er0 );
128 
129  // cut-off frequency of the TE0 mode
130  double fte = ( C0 / 4 ) / ( m_parameters[H_PRM] * sqrt( m_parameters[EPSILONR_PRM] - 1 ) );
131 
132  // dispersion factor G
133  double p = log( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] );
134  double u = 0.54 - ( 0.64 - 0.015 * p ) * p;
135  double v = 0.43 - ( 0.86 - 0.54 * p ) * p;
136  double G = exp( u * log( m_parameters[PHYS_WIDTH_PRM] / m_parameters[PHYS_S_PRM] ) + v );
137 
138  // loss constant factors (computed only once for efficiency's sake)
139  double ac = 0;
140 
141  if( m_parameters[T_PRM] > 0 )
142  {
143  // equations by GHIONE
144  double n = ( 1 - k1 ) * 8 * M_PI / ( m_parameters[T_PRM] * ( 1 + k1 ) );
145  double a = m_parameters[PHYS_WIDTH_PRM] / 2;
146  double b = a + m_parameters[PHYS_S_PRM];
147  ac = ( M_PI + log( n * a ) ) / a + ( M_PI + log( n * b ) ) / b;
148  }
149 
150  double ac_factor = ac / ( 4 * ZF0 * kk1 * kpk1 * ( 1 - k1 * k1 ) );
151  double ad_factor = ( m_parameters[EPSILONR_PRM] / ( m_parameters[EPSILONR_PRM] - 1 ) )
152  * m_parameters[TAND_PRM] * M_PI / C0;
153 
154 
155  // ....................................................
156  double sr_er_f = sr_er0;
157 
158  // add the dispersive effects to er0
159  sr_er_f += ( sr_er - sr_er0 ) / ( 1 + G * pow( m_parameters[FREQUENCY_PRM] / fte, -1.8 ) );
160 
161  // for now, the loss are limited to strip losses (no radiation
162  // losses yet) losses in neper/length
164  20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] * ac_factor * sr_er0
165  * sqrt( M_PI * MU0 * m_parameters[FREQUENCY_PRM] / m_parameters[SIGMA_PRM] );
166  m_parameters[LOSS_DIELECTRIC_PRM] = 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] * ad_factor
167  * m_parameters[FREQUENCY_PRM] * ( sr_er_f * sr_er_f - 1 )
168  / sr_er_f;
169 
170  m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] * sr_er_f
171  * m_parameters[FREQUENCY_PRM] / C0; /* in radians */
172 
173  m_parameters[EPSILON_EFF_PRM] = sr_er_f * sr_er_f;
174  m_parameters[Z0_PRM] = zl_factor / sr_er_f;
175 }
176 
177 
178 // -------------------------------------------------------------------
180 {
181 
183  setResult( 1, m_parameters[LOSS_CONDUCTOR_PRM], wxT( "dB" ) );
184  setResult( 2, m_parameters[LOSS_DIELECTRIC_PRM], wxT( "dB" ) );
185 
186  setResult( 3, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, wxT( "┬Ám" ) );
187 }
188 
189 
190 #define MAX_ERROR 0.000001
191 
192 // -------------------------------------------------------------------
193 /* @function calcSynthesize
194  *
195  * @TODO Add a warning in case the synthetizin algorithm did not converge.
196  * Add it for all transmission lines that uses @ref minimizeZ0Error1D .
197  */
199 {
200  if( isSelected( PHYS_WIDTH_PRM ) )
202  else
204 }
205 
206 // -------------------------------------------------------------------
208 {
209  if( isSelected( PHYS_WIDTH_PRM ) )
211 
212  if( isSelected( PHYS_S_PRM ) )
214 
216 
217  if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0 )
218  {
219  if( isSelected( PHYS_S_PRM ) )
221  else
223  }
224 
225  if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0 )
226  {
227  if( isSelected( PHYS_WIDTH_PRM ) )
229  else
231  }
232 
233  if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 )
235 
236  if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 )
238 
239  if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 )
241 }
242 
243 
245 {
248 
249  if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0 )
251 
252  if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0 )
254 
255  if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 )
257 
258  if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 )
260 
261  if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 )
263 }
bool isSelected(enum PRMS_ID aPrmId)
Definition: transline.cpp:127
void setResult(int, const wxString &)
Definition: transline.cpp:135
bool minimizeZ0Error1D(double *)
@function minimizeZ0Error1D
Definition: transline.cpp:357
void Init()
Definition: transline.cpp:98
bool backMetal
Definition: coplanar.h:39
#define MU0
Definition: units.h:60
#define G(x, y, z)
Definition: md5_hash.cpp:16
void show_results() override
Shows results.
Definition: coplanar.cpp:179
void setProperty(enum PRMS_ID aPrmId, double aValue)
Definition: transline.cpp:117
COPLANAR()
Definition: coplanar.cpp:34
void calcSynthesize() override
Computation for synthesis.
Definition: coplanar.cpp:198
double ellipk(double)
Definition: transline.cpp:332
#define ZF0
Definition: units.h:62
double m_parameters[EXTRA_PRMS_COUNT]
Definition: transline.h:131
void showSynthesize() override
Shows analysis results and checks for errors / warnings.
Definition: coplanar.cpp:207
const char * m_Name
Definition: transline.h:84
#define UNIT_MICRON
Definition: units_scales.h:33
#define C0
Definition: units.h:61
#define TRANSLINE_ERROR
Definition: transline.h:31
void calcAnalyze() override
Computation for analysis.
Definition: coplanar.cpp:50
void showAnalyze() override
Shows synthesis results and checks for errors / warnings.
Definition: coplanar.cpp:244
#define TRANSLINE_WARNING
Definition: transline.h:30
double skin_depth()
@function skin_depth calculate skin depth
Definition: transline.cpp:245
void setErrorLevel(PRMS_ID, char)
@function setErrorLevel
Definition: transline.cpp:443