You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
9.2 KiB

  1. /*
  2. * coplanar.cpp - coplanar class implementation
  3. *
  4. * Copyright (C) 2008 Michael Margraf <michael.margraf@alumni.tu-berlin.de>
  5. * Copyright (C) 2005, 2006 Stefan Jahn <stefan@lkcc.org>
  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. #include <cmath>
  25. #include <cstdio>
  26. #include <cstdlib>
  27. #include <cstring>
  28. #include "coplanar.h"
  29. #include "units.h"
  30. COPLANAR::COPLANAR() : TRANSLINE()
  31. {
  32. m_Name = "CoPlanar";
  33. backMetal = false;
  34. Init();
  35. }
  36. GROUNDEDCOPLANAR::GROUNDEDCOPLANAR() : COPLANAR()
  37. {
  38. m_Name = "GrCoPlanar";
  39. backMetal = true;
  40. }
  41. // -------------------------------------------------------------------
  42. void COPLANAR::calcAnalyze()
  43. {
  44. m_parameters[SKIN_DEPTH_PRM] = skin_depth();
  45. // other local variables (quasi-static constants)
  46. double k1, kk1, kpk1, k2, k3, q1, q2, q3 = 0, qz, er0 = 0;
  47. double zl_factor;
  48. // compute the necessary quasi-static approx. (K1, K3, er(0) and Z(0))
  49. k1 = m_parameters[PHYS_WIDTH_PRM]
  50. / ( m_parameters[PHYS_WIDTH_PRM] + m_parameters[PHYS_S_PRM] + m_parameters[PHYS_S_PRM] );
  51. kk1 = ellipk( k1 );
  52. kpk1 = ellipk( sqrt( 1 - k1 * k1 ) );
  53. q1 = kk1 / kpk1;
  54. // backside is metal
  55. if( backMetal )
  56. {
  57. k3 = tanh( ( M_PI / 4 ) * ( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] ) )
  58. / tanh( ( M_PI / 4 )
  59. * ( m_parameters[PHYS_WIDTH_PRM] + m_parameters[PHYS_S_PRM]
  60. + m_parameters[PHYS_S_PRM] )
  61. / m_parameters[H_PRM] );
  62. q3 = ellipk( k3 ) / ellipk( sqrt( 1 - k3 * k3 ) );
  63. qz = 1 / ( q1 + q3 );
  64. er0 = 1 + q3 * qz * ( m_parameters[EPSILONR_PRM] - 1 );
  65. zl_factor = ZF0 / 2 * qz;
  66. }
  67. // backside is air
  68. else
  69. {
  70. k2 = sinh( ( M_PI / 4 ) * ( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] ) )
  71. / sinh( ( M_PI / 4 )
  72. * ( m_parameters[PHYS_WIDTH_PRM] + m_parameters[PHYS_S_PRM]
  73. + m_parameters[PHYS_S_PRM] )
  74. / m_parameters[H_PRM] );
  75. q2 = ellipk( k2 ) / ellipk( sqrt( 1 - k2 * k2 ) );
  76. er0 = 1 + ( m_parameters[EPSILONR_PRM] - 1 ) / 2 * q2 / q1;
  77. zl_factor = ZF0 / 4 / q1;
  78. }
  79. // adds effect of strip thickness
  80. if( m_parameters[T_PRM] > 0 )
  81. {
  82. double d, se, We, ke, qe;
  83. d = ( m_parameters[T_PRM] * 1.25 / M_PI )
  84. * ( 1 + log( 4 * M_PI * m_parameters[PHYS_WIDTH_PRM] / m_parameters[T_PRM] ) );
  85. se = m_parameters[PHYS_S_PRM] - d;
  86. We = m_parameters[PHYS_WIDTH_PRM] + d;
  87. // modifies k1 accordingly (k1 = ke)
  88. ke = We / ( We + se + se ); // ke = k1 + (1 - k1 * k1) * d / 2 / s;
  89. qe = ellipk( ke ) / ellipk( sqrt( 1 - ke * ke ) );
  90. // backside is metal
  91. if( backMetal )
  92. {
  93. qz = 1 / ( qe + q3 );
  94. er0 = 1 + q3 * qz * ( m_parameters[EPSILONR_PRM] - 1 );
  95. zl_factor = ZF0 / 2 * qz;
  96. }
  97. // backside is air
  98. else
  99. {
  100. zl_factor = ZF0 / 4 / qe;
  101. }
  102. // modifies er0 as well
  103. er0 = er0
  104. - ( 0.7 * ( er0 - 1 ) * m_parameters[T_PRM] / m_parameters[PHYS_S_PRM] )
  105. / ( q1 + ( 0.7 * m_parameters[T_PRM] / m_parameters[PHYS_S_PRM] ) );
  106. }
  107. // pre-compute square roots
  108. double sr_er = sqrt( m_parameters[EPSILONR_PRM] );
  109. double sr_er0 = sqrt( er0 );
  110. // cut-off frequency of the TE0 mode
  111. double fte = ( C0 / 4 ) / ( m_parameters[H_PRM] * sqrt( m_parameters[EPSILONR_PRM] - 1 ) );
  112. // dispersion factor G
  113. double p = log( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] );
  114. double u = 0.54 - ( 0.64 - 0.015 * p ) * p;
  115. double v = 0.43 - ( 0.86 - 0.54 * p ) * p;
  116. double G = exp( u * log( m_parameters[PHYS_WIDTH_PRM] / m_parameters[PHYS_S_PRM] ) + v );
  117. // loss constant factors (computed only once for efficiency's sake)
  118. double ac = 0;
  119. if( m_parameters[T_PRM] > 0 )
  120. {
  121. // equations by GHIONE
  122. double n = ( 1 - k1 ) * 8 * M_PI / ( m_parameters[T_PRM] * ( 1 + k1 ) );
  123. double a = m_parameters[PHYS_WIDTH_PRM] / 2;
  124. double b = a + m_parameters[PHYS_S_PRM];
  125. ac = ( M_PI + log( n * a ) ) / a + ( M_PI + log( n * b ) ) / b;
  126. }
  127. double ac_factor = ac / ( 4 * ZF0 * kk1 * kpk1 * ( 1 - k1 * k1 ) );
  128. double ad_factor = ( m_parameters[EPSILONR_PRM] / ( m_parameters[EPSILONR_PRM] - 1 ) )
  129. * m_parameters[TAND_PRM] * M_PI / C0;
  130. // ....................................................
  131. double sr_er_f = sr_er0;
  132. // add the dispersive effects to er0
  133. sr_er_f += ( sr_er - sr_er0 ) / ( 1 + G * pow( m_parameters[FREQUENCY_PRM] / fte, -1.8 ) );
  134. // for now, the loss are limited to strip losses (no radiation
  135. // losses yet) losses in neper/length
  136. m_parameters[LOSS_CONDUCTOR_PRM] =
  137. 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] * ac_factor * sr_er0
  138. * sqrt( M_PI * MU0 * m_parameters[FREQUENCY_PRM] / m_parameters[SIGMA_PRM] );
  139. m_parameters[LOSS_DIELECTRIC_PRM] = 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] * ad_factor
  140. * m_parameters[FREQUENCY_PRM] * ( sr_er_f * sr_er_f - 1 )
  141. / sr_er_f;
  142. m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] * sr_er_f
  143. * m_parameters[FREQUENCY_PRM] / C0; /* in radians */
  144. m_parameters[EPSILON_EFF_PRM] = sr_er_f * sr_er_f;
  145. m_parameters[Z0_PRM] = zl_factor / sr_er_f;
  146. }
  147. // -------------------------------------------------------------------
  148. void COPLANAR::show_results()
  149. {
  150. setResult( 0, m_parameters[EPSILON_EFF_PRM], "" );
  151. setResult( 1, m_parameters[LOSS_CONDUCTOR_PRM], "dB" );
  152. setResult( 2, m_parameters[LOSS_DIELECTRIC_PRM], "dB" );
  153. setResult( 3, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" );
  154. }
  155. #define MAX_ERROR 0.000001
  156. // -------------------------------------------------------------------
  157. /* @function calcSynthesize
  158. *
  159. * @TODO Add a warning in case the synthetizin algorithm did not converge.
  160. * Add it for all transmission lines that uses @ref minimizeZ0Error1D .
  161. */
  162. void COPLANAR::calcSynthesize()
  163. {
  164. if( isSelected( PHYS_WIDTH_PRM ) )
  165. minimizeZ0Error1D( &( m_parameters[PHYS_WIDTH_PRM] ) );
  166. else
  167. minimizeZ0Error1D( &( m_parameters[PHYS_S_PRM] ) );
  168. }
  169. // -------------------------------------------------------------------
  170. void COPLANAR::showSynthesize()
  171. {
  172. if( isSelected( PHYS_WIDTH_PRM ) )
  173. setProperty( PHYS_WIDTH_PRM, m_parameters[PHYS_WIDTH_PRM] );
  174. if( isSelected( PHYS_S_PRM ) )
  175. setProperty( PHYS_S_PRM, m_parameters[PHYS_S_PRM] );
  176. setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] );
  177. if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0 )
  178. {
  179. if( isSelected( PHYS_S_PRM ) )
  180. setErrorLevel( PHYS_S_PRM, TRANSLINE_ERROR );
  181. else
  182. setErrorLevel( PHYS_S_PRM, TRANSLINE_WARNING );
  183. }
  184. if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0 )
  185. {
  186. if( isSelected( PHYS_WIDTH_PRM ) )
  187. setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR );
  188. else
  189. setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING );
  190. }
  191. if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 )
  192. setErrorLevel( PHYS_LEN_PRM, TRANSLINE_ERROR );
  193. if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 )
  194. setErrorLevel( Z0_PRM, TRANSLINE_WARNING );
  195. if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 )
  196. setErrorLevel( ANG_L_PRM, TRANSLINE_WARNING );
  197. }
  198. void COPLANAR::showAnalyze()
  199. {
  200. setProperty( Z0_PRM, m_parameters[Z0_PRM] );
  201. setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] );
  202. if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0 )
  203. setErrorLevel( PHYS_S_PRM, TRANSLINE_WARNING );
  204. if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0 )
  205. setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING );
  206. if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 )
  207. setErrorLevel( PHYS_LEN_PRM, TRANSLINE_WARNING );
  208. if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 )
  209. setErrorLevel( Z0_PRM, TRANSLINE_ERROR );
  210. if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 )
  211. setErrorLevel( ANG_L_PRM, TRANSLINE_ERROR );
  212. }