1 /*
2  * stripline.cpp - stripline class definition
3  *
4  * Copyright (C) 2011 Michael Margraf <michael.margraf@alumni.tu-berlin.de>
5  * Modifications 2018 for Kicad: Jean-Pierre Charras
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or (at
10  * your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this package; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 
25 #include <cmath>
26 #include <cstdio>
27 #include <cstdlib>
28 #include <cstring>
29 
30 #include "stripline.h"
31 #include "units.h"
32 
STRIPLINE()33 STRIPLINE::STRIPLINE() : TRANSLINE()
34 {
35     m_Name = "StripLine";
36     Init();
37 }
38 
39 
40 // -------------------------------------------------------------------
41 // calculate characteristic impedance and conductor loss
lineImpedance(double height,double & ac)42 double STRIPLINE::lineImpedance( double height, double& ac )
43 {
44     double ZL;
45     double hmt = height - m_parameters[T_PRM];
46 
47     ac = sqrt( m_parameters[FREQUENCY_PRM] / m_parameters[SIGMA_PRM] / 17.2 );
48 
49     if( m_parameters[PHYS_WIDTH_PRM] / hmt >= 0.35 )
50     {
51         ZL = m_parameters[PHYS_WIDTH_PRM]
52              + ( 2.0 * height * log( ( 2.0 * height - m_parameters[T_PRM] ) / hmt )
53                        - m_parameters[T_PRM] * log( height * height / hmt / hmt - 1.0 ) )
54                        / M_PI;
55         ZL = ZF0 * hmt / sqrt( m_parameters[EPSILONR_PRM] ) / 4.0 / ZL;
56 
57         ac *= 2.02e-6 * m_parameters[EPSILONR_PRM] * ZL / hmt;
58         ac *= 1.0 + 2.0 * m_parameters[PHYS_WIDTH_PRM] / hmt
59               + ( height + m_parameters[T_PRM] ) / hmt / M_PI
60                         * log( 2.0 * height / m_parameters[T_PRM] - 1.0 );
61     }
62     else
63     {
64         double tdw = m_parameters[T_PRM] / m_parameters[PHYS_WIDTH_PRM];
65         if( m_parameters[T_PRM] / m_parameters[PHYS_WIDTH_PRM] > 1.0 )
66             tdw = m_parameters[PHYS_WIDTH_PRM] / m_parameters[T_PRM];
67         double de = 1.0 + tdw / M_PI * ( 1.0 + log( 4.0 * M_PI / tdw ) ) + 0.236 * pow( tdw, 1.65 );
68         if( m_parameters[T_PRM] / m_parameters[PHYS_WIDTH_PRM] > 1.0 )
69             de *= m_parameters[T_PRM] / 2.0;
70         else
71             de *= m_parameters[PHYS_WIDTH_PRM] / 2.0;
72         ZL = ZF0 / 2.0 / M_PI / sqrt( m_parameters[EPSILONR_PRM] )
73              * log( 4.0 * height / M_PI / de );
74 
75         ac *= 0.01141 / ZL / de;
76         ac *= de / height + 0.5 + tdw / 2.0 / M_PI + 0.5 / M_PI * log( 4.0 * M_PI / tdw )
77               + 0.1947 * pow( tdw, 0.65 ) - 0.0767 * pow( tdw, 1.65 );
78     }
79 
80     return ZL;
81 }
82 
83 
84 // -------------------------------------------------------------------
calcAnalyze()85 void STRIPLINE::calcAnalyze()
86 {
87     m_parameters[SKIN_DEPTH_PRM] = skin_depth();
88 
89     m_parameters[EPSILON_EFF_PRM] = m_parameters[EPSILONR_PRM]; // no dispersion
90 
91     double ac1, ac2;
92     double t             = m_parameters[T_PRM];
93     double a             = m_parameters[STRIPLINE_A_PRM];
94     double h             = m_parameters[H_PRM];
95     m_parameters[Z0_PRM] = 2.0
96                            / ( 1.0 / lineImpedance( 2.0 * a + t, ac1 )
97                                    + 1.0 / lineImpedance( 2.0 * ( h - a ) - t, ac2 ) );
98     m_parameters[LOSS_CONDUCTOR_PRM]  = m_parameters[PHYS_LEN_PRM] * 0.5 * ( ac1 + ac2 );
99     m_parameters[LOSS_DIELECTRIC_PRM] = 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM]
100                                         * ( M_PI / C0 ) * m_parameters[FREQUENCY_PRM]
101                                         * sqrt( m_parameters[EPSILONR_PRM] )
102                                         * m_parameters[TAND_PRM];
103 
104     m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM]
105                               * sqrt( m_parameters[EPSILONR_PRM] ) * m_parameters[FREQUENCY_PRM]
106                               / C0; // in radians
107 }
108 
109 
showAnalyze()110 void STRIPLINE::showAnalyze()
111 {
112     setProperty( Z0_PRM, m_parameters[Z0_PRM] );
113     setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] );
114 
115     if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 )
116         setErrorLevel( Z0_PRM, TRANSLINE_ERROR );
117 
118     if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 )
119         setErrorLevel( ANG_L_PRM, TRANSLINE_ERROR );
120 
121     if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 )
122         setErrorLevel( PHYS_LEN_PRM, TRANSLINE_WARNING );
123 
124     if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] < 0 )
125         setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING );
126 
127     if( m_parameters[STRIPLINE_A_PRM] + m_parameters[T_PRM] >= m_parameters[H_PRM] )
128     {
129         setErrorLevel( STRIPLINE_A_PRM, TRANSLINE_WARNING );
130         setErrorLevel( T_PRM, TRANSLINE_WARNING );
131         setErrorLevel( H_PRM, TRANSLINE_WARNING );
132         setErrorLevel( Z0_PRM, TRANSLINE_ERROR );
133     }
134 }
135 
showSynthesize()136 void STRIPLINE::showSynthesize()
137 {
138     setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] );
139     setProperty( PHYS_WIDTH_PRM, m_parameters[PHYS_WIDTH_PRM] );
140 
141     if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 )
142         setErrorLevel( PHYS_LEN_PRM, TRANSLINE_ERROR );
143 
144     if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] < 0 )
145         setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR );
146 
147     if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 )
148         setErrorLevel( Z0_PRM, TRANSLINE_WARNING );
149 
150     if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 )
151         setErrorLevel( ANG_L_PRM, TRANSLINE_WARNING );
152 
153     if( m_parameters[STRIPLINE_A_PRM] + m_parameters[T_PRM] >= m_parameters[H_PRM] )
154     {
155         setErrorLevel( STRIPLINE_A_PRM, TRANSLINE_WARNING );
156         setErrorLevel( T_PRM, TRANSLINE_WARNING );
157         setErrorLevel( H_PRM, TRANSLINE_WARNING );
158         setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR );
159     }
160 }
161 // -------------------------------------------------------------------
show_results()162 void STRIPLINE::show_results()
163 {
164 
165     setResult( 0, m_parameters[EPSILON_EFF_PRM], "" );
166     setResult( 1, m_parameters[LOSS_CONDUCTOR_PRM], "dB" );
167     setResult( 2, m_parameters[LOSS_DIELECTRIC_PRM], "dB" );
168 
169     setResult( 3, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" );
170 }
171 
172 
173 #define MAX_ERROR 0.000001
174 
175 // -------------------------------------------------------------------
calcSynthesize()176 void STRIPLINE::calcSynthesize()
177 {
178     minimizeZ0Error1D( &( m_parameters[PHYS_WIDTH_PRM] ) );
179 }
180