From aac9731852cdda8fc20ffcfd600c4a0372308d8b Mon Sep 17 00:00:00 2001 From: JamesJCode <13408010-JamesJCode@users.noreply.gitlab.com> Date: Sun, 20 Apr 2025 23:52:34 +0100 Subject: [PATCH] Refactor PCB calcs to common library, and add coupled stripline Fixes https://gitlab.com/kicad/code/kicad/-/issues/16863 --- common/CMakeLists.txt | 9 + common/bitmap_info.cpp | 2 + .../coupled_microstrip.cpp | 823 +++++++++++++++ .../coupled_microstrip.h | 202 ++++ .../coupled_stripline.cpp | 393 +++++++ .../coupled_stripline.h | 104 ++ common/transline_calculations/microstrip.cpp | 396 +++++++ common/transline_calculations/microstrip.h | 118 +++ common/transline_calculations/stripline.cpp | 172 +++ common/transline_calculations/stripline.h | 64 ++ .../transline_calculation_base.cpp | 225 ++++ .../transline_calculation_base.h | 227 ++++ common/transline_calculations/units.h | 74 ++ common/transline_calculations/units_scales.h | 72 ++ include/bitmaps/bitmaps_list.h | 1 + pcb_calculator/CMakeLists.txt | 1 + .../calculator_panels/panel_transline.cpp | 16 +- .../panel_transline_base.cpp | 20 +- .../panel_transline_base.fbp | 4 +- pcb_calculator/transline/c_microstrip.cpp | 989 ++---------------- pcb_calculator/transline/c_microstrip.h | 74 +- pcb_calculator/transline/c_stripline.cpp | 118 +++ pcb_calculator/transline/c_stripline.h | 44 + pcb_calculator/transline/microstrip.cpp | 530 ++-------- pcb_calculator/transline/microstrip.h | 66 +- pcb_calculator/transline/stripline.cpp | 204 ++-- pcb_calculator/transline/stripline.h | 26 +- pcb_calculator/transline/transline.cpp | 15 +- pcb_calculator/transline/transline.h | 7 +- pcb_calculator/transline_dlg_funct.cpp | 2 +- pcb_calculator/transline_ident.cpp | 36 +- pcb_calculator/transline_ident.h | 8 +- resources/bitmaps_png/CMakeLists.txt | 1 + .../bitmaps_png/png/coupled_stripline.png | Bin 0 -> 10179 bytes .../png/coupled_stripline_dark.png | Bin 0 -> 10179 bytes .../sources/dark/coupled_stripline.svg | 834 +++++++++++++++ .../sources/light/coupled_stripline.svg | 834 +++++++++++++++ 37 files changed, 5035 insertions(+), 1676 deletions(-) create mode 100644 common/transline_calculations/coupled_microstrip.cpp create mode 100644 common/transline_calculations/coupled_microstrip.h create mode 100644 common/transline_calculations/coupled_stripline.cpp create mode 100644 common/transline_calculations/coupled_stripline.h create mode 100644 common/transline_calculations/microstrip.cpp create mode 100644 common/transline_calculations/microstrip.h create mode 100644 common/transline_calculations/stripline.cpp create mode 100644 common/transline_calculations/stripline.h create mode 100644 common/transline_calculations/transline_calculation_base.cpp create mode 100644 common/transline_calculations/transline_calculation_base.h create mode 100644 common/transline_calculations/units.h create mode 100644 common/transline_calculations/units_scales.h create mode 100644 pcb_calculator/transline/c_stripline.cpp create mode 100644 pcb_calculator/transline/c_stripline.h create mode 100644 resources/bitmaps_png/png/coupled_stripline.png create mode 100644 resources/bitmaps_png/png/coupled_stripline_dark.png create mode 100644 resources/bitmaps_png/sources/dark/coupled_stripline.svg create mode 100644 resources/bitmaps_png/sources/light/coupled_stripline.svg diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 2583cd95e9..ea79bb2d2d 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -557,6 +557,14 @@ set( COMMON_IO_SRCS io/easyedapro/easyedapro_import_utils.cpp ) +set ( COMMON_TRANSLINE_CALCULATION_SRCS + transline_calculations/transline_calculation_base.cpp + transline_calculations/microstrip.cpp + transline_calculations/coupled_microstrip.cpp + transline_calculations/stripline.cpp + transline_calculations/coupled_stripline.cpp + ) + set( COMMON_IMPORT_GFX_SRCS import_gfx/graphics_import_mgr.cpp import_gfx/graphics_importer.cpp @@ -591,6 +599,7 @@ set( COMMON_SRCS ${FONT_SRCS} ${COMMON_IMPORT_GFX_SRCS} ${COMMON_GIT_SRCS} + ${COMMON_TRANSLINE_CALCULATION_SRCS} base_screen.cpp bin_mod.cpp bitmap_base.cpp diff --git a/common/bitmap_info.cpp b/common/bitmap_info.cpp index c428c047b2..83477b8277 100644 --- a/common/bitmap_info.cpp +++ b/common/bitmap_info.cpp @@ -4893,6 +4893,7 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::color_code_tolerance].emplace_back( BITMAPS::color_code_tolerance, wxT( "color_code_tolerance.png" ), -1, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::color_code_value].emplace_back( BITMAPS::color_code_value, wxT( "color_code_value.png" ), -1, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::color_code_value_and_name].emplace_back( BITMAPS::color_code_value_and_name, wxT( "color_code_value_and_name.png" ), -1, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::coupled_stripline].emplace_back( BITMAPS::coupled_stripline, wxT( "coupled_stripline.png" ), -1, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::creepage_clearance].emplace_back( BITMAPS::creepage_clearance, wxT( "creepage_clearance.png" ), -1, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::cpw].emplace_back( BITMAPS::cpw, wxT( "cpw.png" ), -1, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::cpw_back].emplace_back( BITMAPS::cpw_back, wxT( "cpw_back.png" ), -1, wxT( "light" ) ); @@ -4928,6 +4929,7 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::color_code_tolerance].emplace_back( BITMAPS::color_code_tolerance, wxT( "color_code_tolerance_dark.png" ), -1, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::color_code_value].emplace_back( BITMAPS::color_code_value, wxT( "color_code_value_dark.png" ), -1, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::color_code_value_and_name].emplace_back( BITMAPS::color_code_value_and_name, wxT( "color_code_value_and_name_dark.png" ), -1, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::coupled_stripline].emplace_back( BITMAPS::coupled_stripline, wxT( "coupled_stripline_dark.png" ), -1, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::creepage_clearance].emplace_back( BITMAPS::creepage_clearance, wxT( "creepage_clearance_dark.png" ), -1, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::cpw].emplace_back( BITMAPS::cpw, wxT( "cpw_dark.png" ), -1, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::cpw_back].emplace_back( BITMAPS::cpw_back, wxT( "cpw_back_dark.png" ), -1, wxT( "dark" ) ); diff --git a/common/transline_calculations/coupled_microstrip.cpp b/common/transline_calculations/coupled_microstrip.cpp new file mode 100644 index 0000000000..60e689a767 --- /dev/null +++ b/common/transline_calculations/coupled_microstrip.cpp @@ -0,0 +1,823 @@ +/* + * Copyright (C) 2001 Gopal Narayanan + * Copyright (C) 2002 Claudio Girardi + * Copyright (C) 2005, 2006 Stefan Jahn + * Modified for Kicad: 2018 Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + + +namespace TC = TRANSLINE_CALCULATIONS; +using TCP = TRANSLINE_PARAMETERS; + + +void COUPLED_MICROSTRIP::Analyse() +{ + // Compute thickness corrections + delta_u_thickness(); + + // Get effective dielectric constants + er_eff_static(); + + // Impedances for even- and odd-mode + Z0_even_odd(); + + // Calculate freq dependence of er_eff_e, er_eff_o + er_eff_freq(); + + // Calculate frequency dependence of Z0e, Z0o */ + Z0_dispersion(); + + // Calculate losses + attenuation(); + + // Calculate electrical lengths + line_angle(); + + // Calculate diff impedance + diff_impedance(); +} + + +bool COUPLED_MICROSTRIP::Synthesize( const SYNTHESIZE_OPTS aOpts ) +{ + if( aOpts == SYNTHESIZE_OPTS::FIX_WIDTH ) + return MinimiseZ0Error1D( TCP::PHYS_S, TCP::Z0_O ); + + if( aOpts == SYNTHESIZE_OPTS::FIX_SPACING ) + return MinimiseZ0Error1D( TCP::PHYS_WIDTH, TCP::Z0_O ); + + double Z0_e, Z0_o, ang_l_dest; + double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err; + double eps = 1e-04; + double w_h, s_h, le, lo; + + /* required value of Z0_e and Z0_o */ + Z0_e = GetParameter( TCP::Z0_E ); + Z0_o = GetParameter( TCP::Z0_O ); + + ang_l_e = GetParameter( TCP::ANG_L ); + ang_l_o = GetParameter( TCP::ANG_L ); + ang_l_dest = GetParameter( TCP::ANG_L ); + + /* calculate width and use for initial value in Newton's method */ + synth_width(); + w_h = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); + s_h = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); + f1 = f2 = 0; + + int iters = 0; + + /* rather crude Newton-Rhapson */ + do + { + ++iters; + + /* compute Jacobian */ + syn_fun( &ft1, &ft2, s_h + eps, w_h, Z0_e, Z0_o ); + j11 = ( ft1 - f1 ) / eps; + j21 = ( ft2 - f2 ) / eps; + syn_fun( &ft1, &ft2, s_h, w_h + eps, Z0_e, Z0_o ); + j12 = ( ft1 - f1 ) / eps; + j22 = ( ft2 - f2 ) / eps; + + /* compute next step; increments of s_h and w_h */ + d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 ); + d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 ); + + s_h += d_s_h; + w_h += d_w_h; + + /* compute the error with the new values of s_h and w_h */ + syn_fun( &f1, &f2, s_h, w_h, Z0_e, Z0_o ); + err = sqrt( f1 * f1 + f2 * f2 ); + + /* converged ? */ + } while( err > 1e-04 && iters < 250 ); + + if( err > 1e-04 ) + return false; + + /* denormalize computed width and spacing */ + SetParameter( TCP::PHYS_S, s_h * GetParameter( TCP::H ) ); + SetParameter( TCP::PHYS_WIDTH, w_h * GetParameter( TCP::H ) ); + + /* calculate physical length */ + le = TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff_e ) * ang_l_dest / 2.0 / M_PI; + lo = TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff_o ) * ang_l_dest / 2.0 / M_PI; + SetParameter( TCP::PHYS_LEN, sqrt( le * lo ) ); + + Analyse(); + + SetParameter( TCP::ANG_L, ang_l_dest ); + SetParameter( TCP::Z0_E, Z0_e ); + SetParameter( TCP::Z0_O, Z0_o ); + + return true; +} + + +void COUPLED_MICROSTRIP::SetAnalysisResults() +{ + SetAnalysisResult( TCP::EPSILON_EFF_EVEN, er_eff_e ); + SetAnalysisResult( TCP::EPSILON_EFF_ODD, er_eff_o ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY_EVEN, prop_delay_e ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY_ODD, prop_delay_o ); + SetAnalysisResult( TCP::ATTEN_COND_EVEN, atten_cond_e ); + SetAnalysisResult( TCP::ATTEN_COND_ODD, atten_cond_o ); + SetAnalysisResult( TCP::ATTEN_DILECTRIC_EVEN, atten_dielectric_e ); + SetAnalysisResult( TCP::ATTEN_DILECTRIC_ODD, atten_dielectric_o ); + SetAnalysisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + SetAnalysisResult( TCP::Z_DIFF, Zdiff ); + + const double Z0_E = GetParameter( TCP::Z0_E ); + const double Z0_O = GetParameter( TCP::Z0_O ); + const double ANG_L = sqrt( ang_l_e * ang_l_o ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double S = GetParameter( TCP::PHYS_S ); + + const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0; + const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0; + const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool S_invalid = !std::isfinite( S ) || S <= 0; + + SetAnalysisResult( TCP::Z0_E, Z0_E, Z0_E_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::Z0_O, Z0_O, Z0_O_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::ANG_L, ANG_L, ANG_L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_S, S, S_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); +} + + +void COUPLED_MICROSTRIP::SetSynthesisResults() +{ + SetAnalysisResult( TCP::EPSILON_EFF_EVEN, er_eff_e ); + SetAnalysisResult( TCP::EPSILON_EFF_ODD, er_eff_o ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY_EVEN, prop_delay_e ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY_ODD, prop_delay_o ); + SetAnalysisResult( TCP::ATTEN_COND_EVEN, atten_cond_e ); + SetAnalysisResult( TCP::ATTEN_COND_ODD, atten_cond_o ); + SetAnalysisResult( TCP::ATTEN_DILECTRIC_EVEN, atten_dielectric_e ); + SetAnalysisResult( TCP::ATTEN_DILECTRIC_ODD, atten_dielectric_o ); + SetAnalysisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + SetAnalysisResult( TCP::Z_DIFF, Zdiff ); + + const double Z0_E = GetParameter( TCP::Z0_E ); + const double Z0_O = GetParameter( TCP::Z0_O ); + const double ANG_L = sqrt( ang_l_e * ang_l_o ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double S = GetParameter( TCP::PHYS_S ); + + const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0; + const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0; + const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool S_invalid = !std::isfinite( S ) || S <= 0; + + SetAnalysisResult( TCP::Z0_E, Z0_E, Z0_E_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::Z0_O, Z0_O, Z0_O_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::ANG_L, ANG_L, ANG_L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_S, S, S_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); +} + + +double COUPLED_MICROSTRIP::delta_u_thickness_single( double u, double t_h ) +{ + double delta_u; + + if( t_h > 0.0 ) + { + delta_u = ( 1.25 * t_h / M_PI ) + * ( 1.0 + + log( ( 2.0 + ( 4.0 * M_PI * u - 2.0 ) / ( 1.0 + exp( -100.0 * ( u - 1.0 / ( 2.0 * M_PI ) ) ) ) ) + / t_h ) ); + } + else + { + delta_u = 0.0; + } + return delta_u; +} + + +/* + * delta_u_thickness() - compute the thickness effect on normalized + * width for coupled microstrips + * + * References: Rolf Jansen, "High-Speed Computation of Single and + * Coupled Microstrip Parameters Including Dispersion, High-Order + * Modes, Loss and Finite Strip Thickness", IEEE Trans. MTT, vol. 26, + * no. 2, pp. 75-82, Feb. 1978 + */ +void COUPLED_MICROSTRIP::delta_u_thickness() +{ + double e_r, u, g, t_h; + double delta_u, delta_t, delta_u_e, delta_u_o; + + e_r = GetParameter( TCP::EPSILONR ); + u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalized line width */ + g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */ + t_h = GetParameter( TCP::T ) / GetParameter( TCP::H ); /* normalized strip thickness */ + + if( t_h > 0.0 ) + { + /* single microstrip correction for finite strip thickness */ + delta_u = delta_u_thickness_single( u, t_h ); + delta_t = t_h / ( g * e_r ); + /* thickness correction for the even- and odd-mode */ + delta_u_e = delta_u * ( 1.0 - 0.5 * exp( -0.69 * delta_u / delta_t ) ); + delta_u_o = delta_u_e + delta_t; + } + else + { + delta_u_e = delta_u_o = 0.0; + } + + w_t_e = GetParameter( TCP::PHYS_WIDTH ) + delta_u_e * GetParameter( TCP::H ); + w_t_o = GetParameter( TCP::PHYS_WIDTH ) + delta_u_o * GetParameter( TCP::H ); +} + + +void COUPLED_MICROSTRIP::compute_single_line() +{ + /* prepare parameters for single microstrip computations */ + m_aux_microstrip.SetParameter( TCP::EPSILONR, GetParameter( TCP::EPSILONR ) ); + m_aux_microstrip.SetParameter( TCP::PHYS_WIDTH, GetParameter( TCP::PHYS_WIDTH ) ); + m_aux_microstrip.SetParameter( TCP::H, GetParameter( TCP::H ) ); + m_aux_microstrip.SetParameter( TCP::T, 0.0 ); + + //m_aux_microstrip.m_parameters[H_T ) = m_parameters[H_T ); + m_aux_microstrip.SetParameter( TCP::H_T, 1e12 ); /* arbitrarily high */ + m_aux_microstrip.SetParameter( TCP::FREQUENCY, GetParameter( TCP::FREQUENCY ) ); + m_aux_microstrip.SetParameter( TCP::MURC, GetParameter( TCP::MURC ) ); + m_aux_microstrip.microstrip_Z0(); + m_aux_microstrip.dispersion(); +} + + +double COUPLED_MICROSTRIP::filling_factor_even( double u, double g, double e_r ) +{ + double v, v3, v4, a_e, b_e, q_inf; + + v = u * ( 20.0 + g * g ) / ( 10.0 + g * g ) + g * exp( -g ); + v3 = v * v * v; + v4 = v3 * v; + a_e = 1.0 + log( ( v4 + v * v / 2704.0 ) / ( v4 + 0.432 ) ) / 49.0 + log( 1.0 + v3 / 5929.741 ) / 18.7; + b_e = 0.564 * pow( ( ( e_r - 0.9 ) / ( e_r + 3.0 ) ), 0.053 ); + + /* filling factor, with width corrected for thickness */ + q_inf = pow( ( 1.0 + 10.0 / v ), -a_e * b_e ); + + return q_inf; +} + + +double COUPLED_MICROSTRIP::filling_factor_odd( double u, double g, double e_r ) +{ + double b_odd = 0.747 * e_r / ( 0.15 + e_r ); + double c_odd = b_odd - ( b_odd - 0.207 ) * exp( -0.414 * u ); + double d_odd = 0.593 + 0.694 * exp( -0.562 * u ); + + /* filling factor, with width corrected for thickness */ + double q_inf = exp( -c_odd * pow( g, d_odd ) ); + + return q_inf; +} + + +double COUPLED_MICROSTRIP::delta_q_cover_even( double h2h ) +{ + double q_c; + + if( h2h <= 39 ) + q_c = tanh( 1.626 + 0.107 * h2h - 1.733 / sqrt( h2h ) ); + else + q_c = 1.0; + + return q_c; +} + + +double COUPLED_MICROSTRIP::delta_q_cover_odd( double h2h ) +{ + double q_c; + + if( h2h <= 7 ) + q_c = tanh( 9.575 / ( 7.0 - h2h ) - 2.965 + 1.68 * h2h - 0.311 * h2h * h2h ); + else + q_c = 1.0; + + return q_c; +} + + +void COUPLED_MICROSTRIP::er_eff_static() +{ + double u_t_e, u_t_o, g, h2, h2h; + double a_o, t_h, q, q_c, q_t, q_inf; + double er_eff_single; + double er; + + er = GetParameter( TCP::EPSILONR ); + + /* compute zero-thickness single line parameters */ + compute_single_line(); + er_eff_single = m_aux_microstrip.er_eff_0; + + h2 = GetParameter( TCP::H_T ); + u_t_e = w_t_e / GetParameter( TCP::H ); /* normalized even_mode line width */ + u_t_o = w_t_o / GetParameter( TCP::H ); /* normalized odd_mode line width */ + g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */ + h2h = h2 / GetParameter( TCP::H ); /* normalized cover height */ + t_h = GetParameter( TCP::T ) / GetParameter( TCP::H ); /* normalized strip thickness */ + + /* filling factor, computed with thickness corrected width */ + q_inf = filling_factor_even( u_t_e, g, er ); + /* cover effect */ + q_c = delta_q_cover_even( h2h ); + /* thickness effect */ + q_t = m_aux_microstrip.delta_q_thickness( u_t_e, t_h ); + /* resultant filling factor */ + q = ( q_inf - q_t ) * q_c; + /* static even-mode effective dielectric constant */ + er_eff_e_0 = 0.5 * ( er + 1.0 ) + 0.5 * ( er - 1.0 ) * q; + + /* filling factor, with width corrected for thickness */ + q_inf = filling_factor_odd( u_t_o, g, er ); + /* cover effect */ + q_c = delta_q_cover_odd( h2h ); + /* thickness effect */ + q_t = m_aux_microstrip.delta_q_thickness( u_t_o, t_h ); + /* resultant filling factor */ + q = ( q_inf - q_t ) * q_c; + + a_o = 0.7287 * ( er_eff_single - 0.5 * ( er + 1.0 ) ) * ( 1.0 - exp( -0.179 * u_t_o ) ); + + /* static odd-mode effective dielectric constant */ + er_eff_o_0 = ( 0.5 * ( er + 1.0 ) + a_o - er_eff_single ) * q + er_eff_single; +} + + +double COUPLED_MICROSTRIP::delta_Z0_even_cover( double g, double u, double h2h ) +{ + double f_e, g_e, delta_Z0_even; + double x, y, A, B, C, D, E, F; + + A = -4.351 / pow( 1.0 + h2h, 1.842 ); + B = 6.639 / pow( 1.0 + h2h, 1.861 ); + C = -2.291 / pow( 1.0 + h2h, 1.90 ); + f_e = 1.0 - atanh( A + ( B + C * u ) * u ); + + x = pow( 10.0, 0.103 * g - 0.159 ); + y = pow( 10.0, 0.0492 * g - 0.073 ); + D = 0.747 / sin( 0.5 * M_PI * x ); + E = 0.725 * sin( 0.5 * M_PI * y ); + F = pow( 10.0, 0.11 - 0.0947 * g ); + g_e = 270.0 * ( 1.0 - tanh( D + E * sqrt( 1.0 + h2h ) - F / ( 1.0 + h2h ) ) ); + + delta_Z0_even = f_e * g_e; + + return delta_Z0_even; +} + + +double COUPLED_MICROSTRIP::delta_Z0_odd_cover( double g, double u, double h2h ) +{ + double f_o, g_o, delta_Z0_odd; + double G, J, K, L; + + J = tanh( pow( 1.0 + h2h, 1.585 ) / 6.0 ); + f_o = pow( u, J ); + + G = 2.178 - 0.796 * g; + + if( g > 0.858 ) + K = log10( 20.492 * pow( g, 0.174 ) ); + else + K = 1.30; + + if( g > 0.873 ) + L = 2.51 * pow( g, -0.462 ); + else + L = 2.674; + + g_o = 270.0 * ( 1.0 - tanh( G + K * sqrt( 1.0 + h2h ) - L / ( 1.0 + h2h ) ) ); + + delta_Z0_odd = f_o * g_o; + + return delta_Z0_odd; +} + + +void COUPLED_MICROSTRIP::Z0_even_odd() +{ + double er_eff, h2, u_t_e, u_t_o, g, h2h; + double Q_1, Q_2, Q_3, Q_4, Q_5, Q_6, Q_7, Q_8, Q_9, Q_10; + double delta_Z0_e_0, delta_Z0_o_0, Z0_single, er_eff_single; + + h2 = GetParameter( TCP::H_T ); + u_t_e = w_t_e / GetParameter( TCP::H ); /* normalized even-mode line width */ + u_t_o = w_t_o / GetParameter( TCP::H ); /* normalized odd-mode line width */ + g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalized line spacing */ + h2h = h2 / GetParameter( TCP::H ); /* normalized cover height */ + + Z0_single = m_aux_microstrip.Z0_0; + er_eff_single = m_aux_microstrip.er_eff_0; + + /* even-mode */ + er_eff = er_eff_e_0; + Q_1 = 0.8695 * pow( u_t_e, 0.194 ); + Q_2 = 1.0 + 0.7519 * g + 0.189 * pow( g, 2.31 ); + Q_3 = 0.1975 + pow( ( 16.6 + pow( ( 8.4 / g ), 6.0 ) ), -0.387 ) + + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 3.4, 10.0 ) ) ) / 241.0; + 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 ) ) ); + /* static even-mode impedance */ + Z0_e_0 = Z0_single * sqrt( er_eff_single / er_eff ) / ( 1.0 - sqrt( er_eff_single ) * Q_4 * Z0_single / TC::ZF0 ); + /* correction for cover */ + delta_Z0_e_0 = delta_Z0_even_cover( g, u_t_e, h2h ) / sqrt( er_eff ); + + Z0_e_0 = Z0_e_0 - delta_Z0_e_0; + + /* odd-mode */ + er_eff = er_eff_o_0; + Q_5 = 1.794 + 1.14 * log( 1.0 + 0.638 / ( g + 0.517 * pow( g, 2.43 ) ) ); + Q_6 = 0.2305 + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 5.8, 10.0 ) ) ) / 281.3 + + log( 1.0 + 0.598 * pow( g, 1.154 ) ) / 5.1; + Q_7 = ( 10.0 + 190.0 * g * g ) / ( 1.0 + 82.3 * g * g * g ); + Q_8 = exp( -6.5 - 0.95 * log( g ) - pow( g / 0.15, 5.0 ) ); + Q_9 = log( Q_7 ) * ( Q_8 + 1.0 / 16.5 ); + Q_10 = ( Q_2 * Q_4 - Q_5 * exp( log( u_t_o ) * Q_6 * pow( u_t_o, -Q_9 ) ) ) / Q_2; + + /* static odd-mode impedance */ + Z0_o_0 = Z0_single * sqrt( er_eff_single / er_eff ) / ( 1.0 - sqrt( er_eff_single ) * Q_10 * Z0_single / TC::ZF0 ); + /* correction for cover */ + delta_Z0_o_0 = delta_Z0_odd_cover( g, u_t_o, h2h ) / sqrt( er_eff ); + + Z0_o_0 = Z0_o_0 - delta_Z0_o_0; +} + + +void COUPLED_MICROSTRIP::er_eff_freq() +{ + double P_1, P_2, P_3, P_4, P_5, P_6, P_7; + double P_8, P_9, P_10, P_11, P_12, P_13, P_14, P_15; + double F_e, F_o; + double er_eff, u, g, f_n; + + u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalize line width */ + g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalize line spacing */ + + /* normalized frequency [GHz * mm] */ + f_n = GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::H ) / 1e06; + + er_eff = er_eff_e_0; + P_1 = 0.27488 + ( 0.6315 + 0.525 / pow( 1.0 + 0.0157 * f_n, 20.0 ) ) * u - 0.065683 * exp( -8.7513 * u ); + P_2 = 0.33622 * ( 1.0 - exp( -0.03442 * GetParameter( TCP::EPSILONR ) ) ); + P_3 = 0.0363 * exp( -4.6 * u ) * ( 1.0 - exp( -pow( f_n / 38.7, 4.97 ) ) ); + P_4 = 1.0 + 2.751 * ( 1.0 - exp( -pow( GetParameter( TCP::EPSILONR ) / 15.916, 8.0 ) ) ); + P_5 = 0.334 * exp( -3.3 * pow( GetParameter( TCP::EPSILONR ) / 15.0, 3.0 ) ) + 0.746; + P_6 = P_5 * exp( -pow( f_n / 18.0, 0.368 ) ); + 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 ) ); + + F_e = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 * P_7 ) * f_n, 1.5763 ); + /* even-mode effective dielectric constant */ + er_eff_e = GetParameter( TCP::EPSILONR ) - ( GetParameter( TCP::EPSILONR ) - er_eff ) / ( 1.0 + F_e ); + prop_delay_e = UnitPropagationDelay( er_eff_e ); + + er_eff = er_eff_o_0; + P_8 = 0.7168 * ( 1.0 + 1.076 / ( 1.0 + 0.0576 * ( GetParameter( TCP::EPSILONR ) - 1.0 ) ) ); + P_9 = P_8 + - 0.7913 * ( 1.0 - exp( -pow( f_n / 20.0, 1.424 ) ) ) + * atan( 2.481 * pow( GetParameter( TCP::EPSILONR ) / 8.0, 0.946 ) ); + P_10 = 0.242 * pow( GetParameter( TCP::EPSILONR ) - 1.0, 0.55 ); + P_11 = 0.6366 * ( exp( -0.3401 * f_n ) - 1.0 ) * atan( 1.263 * pow( u / 3.0, 1.629 ) ); + P_12 = P_9 + ( 1.0 - P_9 ) / ( 1.0 + 1.183 * pow( u, 1.376 ) ); + P_13 = 1.695 * P_10 / ( 0.414 + 1.605 * P_10 ); + P_14 = 0.8928 + 0.1072 * ( 1.0 - exp( -0.42 * pow( f_n / 20.0, 3.215 ) ) ); + P_15 = fabs( 1.0 - 0.8928 * ( 1.0 + P_11 ) * P_12 * exp( -P_13 * pow( g, 1.092 ) ) / P_14 ); + + F_o = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 ) * f_n * P_15, 1.5763 ); + /* odd-mode effective dielectric constant */ + er_eff_o = GetParameter( TCP::EPSILONR ) - ( GetParameter( TCP::EPSILONR ) - er_eff ) / ( 1.0 + F_o ); + prop_delay_o = UnitPropagationDelay( er_eff_o ); +} + + +void COUPLED_MICROSTRIP::conductor_losses() +{ + double e_r_eff_e_0, e_r_eff_o_0, Z0_h_e, Z0_h_o, delta; + double K, R_s, Q_c_e, Q_c_o, alpha_c_e, alpha_c_o; + + e_r_eff_e_0 = er_eff_e_0; + e_r_eff_o_0 = er_eff_o_0; + Z0_h_e = Z0_e_0 * sqrt( e_r_eff_e_0 ); /* homogeneous stripline impedance */ + Z0_h_o = Z0_o_0 * sqrt( e_r_eff_o_0 ); /* homogeneous stripline impedance */ + delta = GetParameter( TCP::SKIN_DEPTH ); + + if( GetParameter( TCP::FREQUENCY ) > 0.0 ) + { + /* current distribution factor (same for the two modes) */ + K = exp( -1.2 * pow( ( Z0_h_e + Z0_h_o ) / ( 2.0 * TC::ZF0 ), 0.7 ) ); + /* skin resistance */ + R_s = 1.0 / ( GetParameter( TCP::SIGMA ) * delta ); + /* correction for surface roughness */ + R_s *= 1.0 + ( ( 2.0 / M_PI ) * atan( 1.40 * pow( ( GetParameter( TCP::ROUGH ) / delta ), 2.0 ) ) ); + + /* even-mode strip inductive quality factor */ + Q_c_e = ( M_PI * Z0_h_e * GetParameter( TCP::PHYS_WIDTH ) * GetParameter( TCP::FREQUENCY ) ) + / ( R_s * TC::C0 * K ); + /* even-mode losses per unit length */ + alpha_c_e = ( 20.0 * M_PI / log( 10.0 ) ) * GetParameter( TCP::FREQUENCY ) * sqrt( e_r_eff_e_0 ) + / ( TC::C0 * Q_c_e ); + + /* odd-mode strip inductive quality factor */ + Q_c_o = ( M_PI * Z0_h_o * GetParameter( TCP::PHYS_WIDTH ) * GetParameter( TCP::FREQUENCY ) ) + / ( R_s * TC::C0 * K ); + /* odd-mode losses per unit length */ + alpha_c_o = ( 20.0 * M_PI / log( 10.0 ) ) * GetParameter( TCP::FREQUENCY ) * sqrt( e_r_eff_o_0 ) + / ( TC::C0 * Q_c_o ); + } + else + { + alpha_c_e = alpha_c_o = 0.0; + } + + atten_cond_e = alpha_c_e * GetParameter( TCP::PHYS_LEN ); + atten_cond_o = alpha_c_o * GetParameter( TCP::PHYS_LEN ); +} + + +void COUPLED_MICROSTRIP::dielectric_losses() +{ + double e_r, e_r_eff_e_0, e_r_eff_o_0; + double alpha_d_e, alpha_d_o; + + e_r = GetParameter( TCP::EPSILONR ); + e_r_eff_e_0 = er_eff_e_0; + e_r_eff_o_0 = er_eff_o_0; + + alpha_d_e = ( 20.0 * M_PI / log( 10.0 ) ) * ( GetParameter( TCP::FREQUENCY ) / TC::C0 ) + * ( e_r / sqrt( e_r_eff_e_0 ) ) * ( ( e_r_eff_e_0 - 1.0 ) / ( e_r - 1.0 ) ) * GetParameter( TCP::TAND ); + alpha_d_o = ( 20.0 * M_PI / log( 10.0 ) ) * ( GetParameter( TCP::FREQUENCY ) / TC::C0 ) + * ( e_r / sqrt( e_r_eff_o_0 ) ) * ( ( e_r_eff_o_0 - 1.0 ) / ( e_r - 1.0 ) ) * GetParameter( TCP::TAND ); + + atten_dielectric_e = alpha_d_e * GetParameter( TCP::PHYS_LEN ); + atten_dielectric_o = alpha_d_o * GetParameter( TCP::PHYS_LEN ); +} + + +void COUPLED_MICROSTRIP::attenuation() +{ + SetParameter( TCP::SKIN_DEPTH, SkinDepth() ); + conductor_losses(); + dielectric_losses(); +} + + +void COUPLED_MICROSTRIP::line_angle() +{ + double e_r_eff_e, e_r_eff_o; + double v_e, v_o, lambda_g_e, lambda_g_o; + + e_r_eff_e = er_eff_e; + e_r_eff_o = er_eff_o; + + /* even-mode velocity */ + v_e = TC::C0 / sqrt( e_r_eff_e ); + /* odd-mode velocity */ + v_o = TC::C0 / sqrt( e_r_eff_o ); + /* even-mode wavelength */ + lambda_g_e = v_e / GetParameter( TCP::FREQUENCY ); + /* odd-mode wavelength */ + lambda_g_o = v_o / GetParameter( TCP::FREQUENCY ); + /* electrical angles */ + ang_l_e = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g_e; /* in radians */ + ang_l_o = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g_o; /* in radians */ +} + + +void COUPLED_MICROSTRIP::diff_impedance() +{ + // Note that differential impedance is exactly twice the odd mode impedance. + // Odd mode is not the same as single-ended impedance, so avoid approximations found + // on websites that use static single ended impedance as the starting point + + Zdiff = 2 * Z0_o_0; +} + + +/* + * Z0_dispersion() - calculate frequency dependency of characteristic + * impedances + */ +void COUPLED_MICROSTRIP::Z0_dispersion() +{ + double Q_0; + double Q_11, Q_12, Q_13, Q_14, Q_15, Q_16, Q_17, Q_18, Q_19, Q_20, Q_21; + double Q_22, Q_23, Q_24, Q_25, Q_26, Q_27, Q_28, Q_29; + double r_e, q_e, p_e, d_e, C_e; + double e_r_eff_o_f, e_r_eff_o_0; + double e_r_eff_single_f, e_r_eff_single_0, Z0_single_f; + double f_n, g, u, e_r; + double R_1, R_2, R_7, R_10, R_11, R_12, R_15, R_16, tmpf; + + e_r = GetParameter( TCP::EPSILONR ); + + u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); /* normalize line width */ + g = GetParameter( TCP::PHYS_S ) / GetParameter( TCP::H ); /* normalize line spacing */ + + /* normalized frequency [GHz * mm] */ + f_n = GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::H ) / 1e06; + + e_r_eff_single_f = m_aux_microstrip.GetParameter( TCP::EPSILON_EFF ); + e_r_eff_single_0 = m_aux_microstrip.er_eff_0; + Z0_single_f = m_aux_microstrip.GetParameter( TCP::Z0 ); + + e_r_eff_o_f = er_eff_o; + e_r_eff_o_0 = er_eff_o_0; + + Q_11 = 0.893 * ( 1.0 - 0.3 / ( 1.0 + 0.7 * ( e_r - 1.0 ) ) ); + 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 ) + * pow( g, 0.902 ); + Q_13 = 1.0 + 0.038 * pow( e_r / 8.0, 5.1 ); + Q_14 = 1.0 + 1.203 * pow( e_r / 15.0, 4.0 ) / ( 1.0 + pow( e_r / 15.0, 4.0 ) ); + Q_15 = 1.887 * exp( -1.5 * pow( g, 0.84 ) ) * pow( g, Q_14 ) + / ( 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 ) ) ); + Q_16 = ( 1.0 + 9.0 / ( 1.0 + 0.403 * pow( e_r - 1.0, 2 ) ) ) * Q_15; + 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 ) ) ); + Q_18 = 0.61 * ( 1.0 - exp( -2.13 * pow( u / 8.0, 1.593 ) ) ) / ( 1.0 + 6.544 * pow( g, 4.17 ) ); + Q_19 = 0.21 * g * g * g * g + / ( ( 1.0 + 0.18 * pow( g, 4.9 ) ) * ( 1.0 + 0.1 * u * u ) * ( 1.0 + pow( f_n / 24.0, 3.0 ) ) ); + Q_20 = ( 0.09 + 1.0 / ( 1.0 + 0.1 * pow( e_r - 1, 2.7 ) ) ) * Q_19; + 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 ) ) ); + + r_e = pow( f_n / 28.843, 12 ); + q_e = 0.016 + pow( 0.0514 * e_r * Q_21, 4.524 ); + p_e = 4.766 * exp( -3.228 * pow( u, 0.641 ) ); + 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 ) ) + * ( pow( e_r - 1.0, 6.0 ) / ( 1.0 + 10 * pow( e_r - 1.0, 6.0 ) ) ); + 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 + - Q_17 + Q_18 + Q_20; + + + R_1 = 0.03891 * pow( e_r, 1.4 ); + R_2 = 0.267 * pow( u, 7.0 ); + R_7 = 1.206 - 0.3144 * exp( -R_1 ) * ( 1.0 - exp( -R_2 ) ); + R_10 = 0.00044 * pow( e_r, 2.136 ) + 0.0184; + tmpf = pow( f_n / 19.47, 6.0 ); + R_11 = tmpf / ( 1.0 + 0.0962 * tmpf ); + R_12 = 1.0 / ( 1.0 + 0.00245 * u * u ); + R_15 = 0.707 * R_10 * pow( f_n / 12.3, 1.097 ); + R_16 = 1.0 + 0.0503 * e_r * e_r * R_11 * ( 1.0 - exp( -pow( u / 15.0, 6.0 ) ) ); + Q_0 = R_7 * ( 1.0 - 1.1241 * ( R_12 / R_16 ) * exp( -0.026 * pow( f_n, 1.15656 ) - R_15 ) ); + + /* even-mode frequency-dependent characteristic impedances */ + SetParameter( TCP::Z0_E, Z0_e_0 * pow( 0.9408 * pow( e_r_eff_single_f, C_e ) - 0.9603, Q_0 ) + / pow( ( 0.9408 - d_e ) * pow( e_r_eff_single_0, C_e ) - 0.9603, Q_0 ) ); + + Q_29 = 15.16 / ( 1.0 + 0.196 * pow( e_r - 1.0, 2.0 ) ); + tmpf = pow( e_r - 1.0, 3.0 ); + Q_28 = 0.149 * tmpf / ( 94.5 + 0.038 * tmpf ); + tmpf = pow( e_r - 1.0, 1.5 ); + Q_27 = 0.4 * pow( g, 0.84 ) * ( 1.0 + 2.5 * tmpf / ( 5.0 + tmpf ) ); + tmpf = pow( ( e_r - 1.0 ) / 13.0, 12.0 ); + Q_26 = 30.0 - 22.2 * ( tmpf / ( 1.0 + 3.0 * tmpf ) ) - Q_29; + tmpf = ( e_r - 1.0 ) * ( e_r - 1.0 ); + Q_25 = ( 0.3 * f_n * f_n / ( 10.0 + f_n * f_n ) ) * ( 1.0 + 2.333 * tmpf / ( 5.0 + tmpf ) ); + 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 ) ); + 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 ) ); + Q_22 = 0.925 * pow( f_n / Q_26, 1.536 ) / ( 1.0 + 0.3 * pow( f_n / 30.0, 1.536 ) ); + + /* odd-mode frequency-dependent characteristic impedances */ + SetParameter( TCP::Z0_O, Z0_single_f + + ( Z0_o_0 * pow( e_r_eff_o_f / e_r_eff_o_0, Q_22 ) - Z0_single_f * Q_23 ) + / ( 1.0 + Q_24 + pow( 0.46 * g, 2.2 ) * Q_25 ) ); +} + + +void COUPLED_MICROSTRIP::syn_err_fun( double* f1, double* f2, double s_h, double w_h, double e_r, double w_h_se, + double w_h_so ) +{ + double g, he; + + g = cosh( 0.5 * M_PI * s_h ); + he = cosh( M_PI * w_h + 0.5 * M_PI * s_h ); + + *f1 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g + 1.0 ) / ( g + 1.0 ) ); + *f2 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g - 1.0 ) / ( g - 1.0 ) ); + + if( e_r <= 6.0 ) + *f2 += ( 4.0 / ( M_PI * ( 1.0 + e_r / 2.0 ) ) ) * acosh( 1.0 + 2.0 * w_h / s_h ); + else + *f2 += ( 1.0 / M_PI ) * acosh( 1.0 + 2.0 * w_h / s_h ); + + *f1 -= w_h_se; + *f2 -= w_h_so; +} + + +void COUPLED_MICROSTRIP::synth_width() +{ + double Z0, e_r; + double w_h_se, w_h_so, w_h, a, ce, co, s_h; + double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err; + double eps = 1e-04; + + f1 = f2 = 0; + e_r = GetParameter( TCP::EPSILONR ); + + Z0 = GetParameter( TCP::Z0_E ) / 2.0; + /* Wheeler formula for single microstrip synthesis */ + a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0; + w_h_se = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a; + + Z0 = GetParameter( TCP::Z0_O ) / 2.0; + /* Wheeler formula for single microstrip synthesis */ + a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0; + w_h_so = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a; + + ce = cosh( 0.5 * M_PI * w_h_se ); + co = cosh( 0.5 * M_PI * w_h_so ); + /* first guess at m_parameters[PHYS_S )/h */ + s_h = ( 2.0 / M_PI ) * acosh( ( ce + co - 2.0 ) / ( co - ce ) ); + /* first guess at w/h */ + w_h = acosh( ( ce * co - 1.0 ) / ( co - ce ) ) / M_PI - s_h / 2.0; + + SetParameter( TCP::PHYS_S, s_h * GetParameter( TCP::H ) ); + SetParameter( TCP::PHYS_WIDTH, w_h * GetParameter( TCP::H ) ); + + syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so ); + + /* rather crude Newton-Rhapson; we need this because the estimate of */ + /* w_h is often quite far from the true value (see Akhtarzad S. et al.) */ + do + { + /* compute Jacobian */ + syn_err_fun( &ft1, &ft2, s_h + eps, w_h, e_r, w_h_se, w_h_so ); + j11 = ( ft1 - f1 ) / eps; + j21 = ( ft2 - f2 ) / eps; + syn_err_fun( &ft1, &ft2, s_h, w_h + eps, e_r, w_h_se, w_h_so ); + j12 = ( ft1 - f1 ) / eps; + j22 = ( ft2 - f2 ) / eps; + + /* compute next step */ + d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 ); + d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 ); + + //g_print("j11 = %e\tj12 = %e\tj21 = %e\tj22 = %e\n", j11, j12, j21, j22); + //g_print("det = %e\n", j11*j22 - j21*j22); + //g_print("d_s_h = %e\td_w_h = %e\n", d_s_h, d_w_h); + + s_h += d_s_h; + w_h += d_w_h; + + /* check the error */ + syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so ); + + err = sqrt( f1 * f1 + f2 * f2 ); + /* converged ? */ + } while( err > 1e-04 ); + + + SetParameter( TCP::PHYS_S, s_h * GetParameter( TCP::H ) ); + SetParameter( TCP::PHYS_WIDTH, w_h * GetParameter( TCP::H ) ); +} + + +void COUPLED_MICROSTRIP::syn_fun( double* f1, double* f2, double s_h, double w_h, double Z0_e, double Z0_o ) +{ + SetParameter( TCP::PHYS_S, s_h * GetParameter( TCP::H ) ); + SetParameter( TCP::PHYS_WIDTH, w_h * GetParameter( TCP::H ) ); + + /* compute coupled microstrip parameters */ + Analyse(); + + *f1 = GetParameter( TCP::Z0_E ) - Z0_e; + *f2 = GetParameter( TCP::Z0_O ) - Z0_o; +} diff --git a/common/transline_calculations/coupled_microstrip.h b/common/transline_calculations/coupled_microstrip.h new file mode 100644 index 0000000000..c867b9522b --- /dev/null +++ b/common/transline_calculations/coupled_microstrip.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2001 Gopal Narayanan + * Copyright (C) 2002 Claudio Girardi + * Copyright (C) 2005, 2006 Stefan Jahn + * Modified for Kicad: 2018 Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef TRANSLINE_CALCULATIONS_COUPLED_MICROSTRIP_H +#define TRANSLINE_CALCULATIONS_COUPLED_MICROSTRIP_H + + +#include +#include + + +class COUPLED_MICROSTRIP : public TRANSLINE_CALCULATION_BASE +{ + using TCP = TRANSLINE_PARAMETERS; + +public: + COUPLED_MICROSTRIP() : + TRANSLINE_CALCULATION_BASE( { TCP::Z0_E, + TCP::Z0_O, + TCP::Z_DIFF, + TCP::ANG_L, + TCP::PHYS_WIDTH, + TCP::PHYS_LEN, + TCP::PHYS_S, + TCP::H, + TCP::T, + TCP::H_T, + TCP::FREQUENCY, + TCP::EPSILONR, + TCP::EPSILON_EFF_EVEN, + TCP::EPSILON_EFF_ODD, + TCP::UNIT_PROP_DELAY_EVEN, + TCP::UNIT_PROP_DELAY_ODD, + TCP::ATTEN_COND_EVEN, + TCP::ATTEN_COND_ODD, + TCP::ATTEN_DILECTRIC_EVEN, + TCP::ATTEN_DILECTRIC_ODD, + TCP::SKIN_DEPTH, + TCP::MURC, + TCP::SIGMA, + TCP::ROUGH, + TCP::TAND } ) + { + } + + /// Analyse track geometry parameters to output Z0 and Ang_L + void Analyse() override; + + /// Synthesis track geometry parameters to match given Z0 + bool Synthesize( SYNTHESIZE_OPTS aOpts ) override; + +private: + /// Sets the output values and status following analysis + void SetAnalysisResults() override; + + /// Sets the output values and status following synthesis + void SetSynthesisResults() override; + + /** + * Computes the thickness effect on normalized width for a single microstrip line + * + * References: H. A. Atwater, "Simplified Design Equations for Microstrip Line Parameters", Microwave Journal, + * pp. 109-115,November 1989. + */ + double delta_u_thickness_single( double, double ); + + /** + * Compute the thickness effect on normalized width for coupled microstrips + * + * References: Rolf Jansen, "High-Speed Computation of Single and Coupled Microstrip Parameters Including + * Dispersion, High-Order Modes, Loss and Finite Strip Thickness", IEEE Trans. MTT, vol. 26, no. 2, pp. 75-82, + * Feb. 1978 + */ + void delta_u_thickness(); + + /// Computes initial parameters for a single microstrip + void compute_single_line(); + + /// Compute the filling factor for the coupled microstrip even mode without cover and zero conductor thickness + double filling_factor_even( double, double, double ); + + /** + * Compute the filling factor for the coupled microstrip odd mode without cover and zero conductor thickness + */ + double filling_factor_odd( double, double, double ); + + /// Compute the cover effect on filling factor for the even mode + double delta_q_cover_even( double ); + + /// Compute the cover effect on filling factor for the odd mode + double delta_q_cover_odd( double ); + + /** + * Compute the static effective dielectric constants + * + * References: Manfred Kirschning and Rolf Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent + * Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT, vol. 32, no. 1, Jan. 1984 + */ + void er_eff_static(); + + /** + * Compute the even mode impedance correction for a homogeneous microstrip due to the cover + * + * References: S. March, "Microstrip Packaging: Watch the Last Step", Microwaves, vol. 20, no. 13, pp. 83.94, + * Dec. 1981. + */ + double delta_Z0_even_cover( double, double, double ); + + /** + * Compute the odd mode impedance correction for a homogeneous microstrip due to the cover + * + * References: S. March, "Microstrip Packaging: Watch the Last Step", Microwaves, vol. 20, no. 13, pp. 83.94, + * Dec. 1981. + */ + double delta_Z0_odd_cover( double, double, double ); + + /** + * Compute the static even- and odd-mode static impedances + * + * References: Manfred Kirschning and Rolf Jansen, "Accurate Wide-Range Design Equations for the Frequency-Dependent + * Characteristic of Parallel Coupled Microstrip Lines", IEEE Trans. MTT, vol. 32, no. 1, Jan. 1984 + */ + void Z0_even_odd(); + + /// Compute er_eff as a function of frequency + void er_eff_freq(); + + /// Compute conductor losses per unit length + void conductor_losses(); + + /// Compute dielectric losses per unit length + void dielectric_losses(); + + /// Compute attenuation + void attenuation(); + + /// Compute electrical length in radians + void line_angle(); + + /// Calculate the differential impedance of the coupled microstrips + void diff_impedance(); + + /// Calculate frequency dependency of characteristic impedances + void Z0_dispersion(); + + /// Error function to minimise when synthesising trace geometry + void syn_err_fun( double*, double*, double, double, double, double, double ); + + /** + * Calculate widths given Z0 and e_r + * + * From Akhtarzad S. et al., "The design of coupled microstrip lines", IEEE Trans. MTT-23, June 1975 and + * Hinton, J.H., "On design of coupled microstrip lines", IEEE Trans. MTT-28, March 1980 + */ + void synth_width(); + + void syn_fun( double*, double*, double, double, double, double ); + + /// Runs intermediate single-track calculations + MICROSTRIP m_aux_microstrip; + + double w_t_e{ 0.0 }; + double w_t_o{ 0.0 }; + double er_eff_e_0{ 0.0 }; + double er_eff_o_0{ 0.0 }; + double Z0_e_0{ 0.0 }; + double Z0_o_0{ 0.0 }; + double er_eff_e{ 0.0 }; + double er_eff_o{ 0.0 }; + double prop_delay_e{ 0.0 }; + double prop_delay_o{ 0.0 }; + double atten_cond_e{ 0.0 }; + double atten_cond_o{ 0.0 }; + double atten_dielectric_e{ 0.0 }; + double atten_dielectric_o{ 0.0 }; + double ang_l_e{ 0.0 }; + double ang_l_o{ 0.0 }; + double Zdiff{ 0.0 }; +}; + + +#endif //TRANSLINE_CALCULATIONS_COUPLED_MICROSTRIP_H diff --git a/common/transline_calculations/coupled_stripline.cpp b/common/transline_calculations/coupled_stripline.cpp new file mode 100644 index 0000000000..dbb40939c1 --- /dev/null +++ b/common/transline_calculations/coupled_stripline.cpp @@ -0,0 +1,393 @@ +/* + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* + * This implements the calculations described in: + * + * [1] S. B. Cohn, "Characteristic Impedance of the Shielded-Strip Transmission Line," in Transactions of the IRE + * Professional Group on Microwave Theory and Techniques, vol. 2, no. 2, pp. 52-57, July 1954 + * [2] S. B. Cohn, "Shielded Coupled-Strip Transmission Line," in IRE Transactions on Microwave Theory and Techniques, + * vol. 3, no. 5, pp. 29-38, October 1955 + */ + +#include +#include +#include + + +namespace TC = TRANSLINE_CALCULATIONS; +using TCP = TRANSLINE_PARAMETERS; + + +void COUPLED_STRIPLINE::Analyse() +{ + // Calculate skin depth + SetParameter( TCP::SKIN_DEPTH, SkinDepth() ); + + // Get analysis parameters + double w = GetParameter( TCP::PHYS_WIDTH ); + double t = GetParameter( TCP::T ); + double s = GetParameter( TCP::PHYS_S ); + double h = GetParameter( TCP::H ); + const double er = GetParameter( TCP::EPSILONR ); + + calcZeroThicknessCoupledImpedances( h, w, s, er ); + + // We've got the impedances now for an infinitely thin line + if( t == 0.0 ) + { + SetParameter( TCP::Z0_E, Z0_e_w_h_0_s_h ); + SetParameter( TCP::Z0_O, Z0_o_w_h_0_s_h ); + } + else + { + calcSingleStripImpedances(); + calcFringeCapacitances( h, t, er ); + calcZ0EvenMode(); + calcZ0OddMode( t, s ); + } + + calcLosses(); + calcDielectrics(); +} + + +bool COUPLED_STRIPLINE::Synthesize( const SYNTHESIZE_OPTS aOpts ) +{ + if( aOpts == SYNTHESIZE_OPTS::FIX_WIDTH ) + return MinimiseZ0Error1D( TCP::PHYS_S, TCP::Z0_O ); + + if( aOpts == SYNTHESIZE_OPTS::FIX_SPACING ) + return MinimiseZ0Error1D( TCP::PHYS_WIDTH, TCP::Z0_O ); + + // This synthesis approach is modified from wcalc, which is released under GPL version 2 + // Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006 Dan McMahill + // All rights reserved + + double ze0 = 0; + double zo0 = 0; + + const double h = GetParameter( TCP::H ); + const double er = GetParameter( TCP::EPSILONR ); + + const double z0e_target = GetParameter( TCP::Z0_E ); + const double z0o_target = GetParameter( TCP::Z0_O ); + // Calculate Z0 and coupling, k + const double z0 = sqrt( z0e_target * z0o_target ); + const double k = ( z0e_target - z0o_target ) / ( z0e_target + z0o_target ); + + int maxiters = 50; + + // Initial guess at a solution. Note that this is an initial guess for coupled microstrip, not coupled stripline... + static constexpr double ai[] = { 1, -0.301, 3.209, -27.282, 56.609, -37.746 }; + static constexpr double bi[] = { 0.020, -0.623, 17.192, -68.946, 104.740, -16.148 }; + static constexpr double ci[] = { 0.002, -0.347, 7.171, -36.910, 76.132, -51.616 }; + + const double AW = exp( z0 * sqrt( er + 1.0 ) / 42.4 ) - 1.0; + const double F1 = 8.0 * sqrt( AW * ( 7.0 + 4.0 / er ) / 11.0 + ( 1.0 + 1.0 / er ) / 0.81 ) / AW; + + double F2 = 0.0, F3 = 0.0; + ; + + for( int i = 0; i <= 5; i++ ) + F2 = F2 + ai[i] * pow( k, i ); + + for( int i = 0; i <= 5; i++ ) + F3 = F3 + ( bi[i] - ci[i] * ( 9.6 - er ) ) * pow( ( 0.6 - k ), static_cast( i ) ); + + double w = h * fabs( F1 * F2 ); + double s = h * fabs( F1 * F3 ); + + int iters = 0; + bool done = false; + double delta = 0.0; + + delta = TC::UNIT_MIL * 1e-5; + + const double cval = 1e-12 * z0e_target * z0o_target; + + while( !done && iters < maxiters ) + { + iters++; + + // Compute impedances with initial solution guess + SetParameter( TCP::PHYS_WIDTH, w ); + SetParameter( TCP::PHYS_S, s ); + Analyse(); + + // Check for convergence + ze0 = GetParameter( TCP::Z0_E ); + zo0 = GetParameter( TCP::Z0_O ); + const double err = pow( ( ze0 - z0e_target ), 2.0 ) + pow( ( zo0 - z0o_target ), 2.0 ); + + if( err < cval ) + { + done = true; + } + else + { + // Approximate the first Jacobian + SetParameter( TCP::PHYS_WIDTH, w + delta ); + SetParameter( TCP::PHYS_S, s ); + Analyse(); + + const double ze1 = GetParameter( TCP::Z0_E ); + const double zo1 = GetParameter( TCP::Z0_O ); + + SetParameter( TCP::PHYS_WIDTH, w ); + SetParameter( TCP::PHYS_S, s + delta ); + Analyse(); + + const double ze2 = GetParameter( TCP::Z0_E ); + const double zo2 = GetParameter( TCP::Z0_O ); + + const double dedw = ( ze1 - ze0 ) / delta; + const double dodw = ( zo1 - zo0 ) / delta; + const double deds = ( ze2 - ze0 ) / delta; + const double dods = ( zo2 - zo0 ) / delta; + + // Find the determinate + const double d = dedw * dods - deds * dodw; + + // Estimate the new solution, but don't change by more than 10% at a time to avoid convergence problems + double dw = -1.0 * ( ( ze0 - z0e_target ) * dods - ( zo0 - z0o_target ) * deds ) / d; + + if( fabs( dw ) > 0.1 * w ) + { + if( dw > 0.0 ) + dw = 0.1 * w; + else + dw = -0.1 * w; + } + + w = fabs( w + dw ); + + double ds = ( ( ze0 - z0e_target ) * dodw - ( zo0 - z0o_target ) * dedw ) / d; + + if( fabs( ds ) > 0.1 * s ) + { + if( ds > 0.0 ) + ds = 0.1 * s; + else + ds = -0.1 * s; + } + + s = fabs( s + ds ); + } + } + + if( !done ) + return false; + + // Recompute with the final parameters + SetParameter( TCP::PHYS_WIDTH, w ); + SetParameter( TCP::PHYS_S, s ); + Analyse(); + + // Reset the impedances + SetParameter( TCP::Z0_E, z0e_target ); + SetParameter( TCP::Z0_O, z0o_target ); + + return true; +} + + +void COUPLED_STRIPLINE::SetAnalysisResults() +{ + SetAnalysisResult( TCP::EPSILON_EFF_EVEN, e_eff_e ); + SetAnalysisResult( TCP::EPSILON_EFF_ODD, e_eff_o ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY_EVEN, unit_prop_delay_e ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY_ODD, unit_prop_delay_o ); + SetAnalysisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + + const double Z0_E = GetParameter( TCP::Z0_E ); + const double Z0_O = GetParameter( TCP::Z0_O ); + const double Z_DIFF = GetParameter( TCP::Z_DIFF ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double S = GetParameter( TCP::PHYS_S ); + + const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0; + const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0; + const bool Z_DIFF_invalid = !std::isfinite( Z_DIFF ) || Z_DIFF <= 0; + const bool ANG_L_invalid = !std::isfinite( ang_l ) || ang_l < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool S_invalid = !std::isfinite( S ) || S <= 0; + + SetAnalysisResult( TCP::Z0_E, Z0_E, Z0_E_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::Z0_O, Z0_O, Z0_O_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::Z_DIFF, Z_DIFF, Z_DIFF_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::ANG_L, ang_l, ANG_L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_S, S, S_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); +} + + +void COUPLED_STRIPLINE::SetSynthesisResults() +{ + SetSynthesisResult( TCP::EPSILON_EFF_EVEN, e_eff_e ); + SetSynthesisResult( TCP::EPSILON_EFF_ODD, e_eff_o ); + SetSynthesisResult( TCP::UNIT_PROP_DELAY_EVEN, unit_prop_delay_e ); + SetSynthesisResult( TCP::UNIT_PROP_DELAY_ODD, unit_prop_delay_o ); + SetSynthesisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + + const double Z0_E = GetParameter( TCP::Z0_E ); + const double Z0_O = GetParameter( TCP::Z0_O ); + const double Z_DIFF = GetParameter( TCP::Z_DIFF ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double S = GetParameter( TCP::PHYS_S ); + + const bool Z0_E_invalid = !std::isfinite( Z0_E ) || Z0_E <= 0; + const bool Z0_O_invalid = !std::isfinite( Z0_O ) || Z0_O <= 0; + const bool Z_DIFF_invalid = !std::isfinite( Z_DIFF ) || Z_DIFF <= 0; + const bool ANG_L_invalid = !std::isfinite( ang_l ) || ang_l < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool S_invalid = !std::isfinite( S ) || S <= 0; + + SetSynthesisResult( TCP::Z0_E, Z0_E, Z0_E_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::Z0_O, Z0_O, Z0_O_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::Z_DIFF, Z_DIFF, Z_DIFF_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::ANG_L, ang_l, ANG_L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::PHYS_S, S, S_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); +} + + +void COUPLED_STRIPLINE::calcFringeCapacitances( const double h, const double t, const double er ) +{ + // Reference [1], Eq. 2 + C_f_t_h = ( TC::E0 * er / M_PI ) + * ( ( 2.0 / ( 1.0 - t / h ) ) * log( ( 1.0 / ( 1.0 - t / h ) ) + 1.0 ) + - ( 1.0 / ( 1.0 - t / h ) - 1.0 ) * log( ( 1.0 / pow( 1.0 - t / h, 2.0 ) ) - 1.0 ) ); + + // Reference [2], Eq. 13 + C_f_0 = ( TC::E0 * er / M_PI ) * 2.0 * log( 2.0 ); +} + + +void COUPLED_STRIPLINE::calcZeroThicknessCoupledImpedances( const double h, const double w, const double s, + const double er ) +{ + // Reference [2], Eqs. 2 - 7 + const double k_e = tanh( M_PI * w / ( 2.0 * h ) ) * tanh( M_PI * ( w + s ) / ( 2.0 * h ) ); + const double k_o = tanh( M_PI * w / ( 2.0 * h ) ) * coth( M_PI * ( w + s ) / ( 2.0 * h ) ); + const double k_e_p = std::sqrt( 1 - std::pow( k_e, 2 ) ); + const double k_o_p = std::sqrt( 1 - std::pow( k_o, 2 ) ); + Z0_e_w_h_0_s_h = ( TC::ZF0 / ( 4.0 * std::sqrt( er ) ) ) + * ( EllipticIntegral( k_e_p ).first / EllipticIntegral( k_e ).first ); + Z0_o_w_h_0_s_h = ( TC::ZF0 / ( 4.0 * std::sqrt( er ) ) ) + * ( EllipticIntegral( k_o_p ).first / EllipticIntegral( k_o ).first ); +} + + +void COUPLED_STRIPLINE::calcSingleStripImpedances() +{ + const double er = GetParameter( TCP::EPSILONR ); + const double h = GetParameter( TCP::H ); + const double w = GetParameter( TCP::PHYS_WIDTH ); + + // Finite-thickness single strip impedance + Z0_w_h_t_h = calcZ0SymmetricStripline(); + + // Zero-thickness single strip impedance + // Reference [1], Eqs. 5 - 6 (corrected for sqrt(e_r)) + const double k = sech( M_PI * w / ( 2.0 * h ) ); + const double k_p = tanh( M_PI * w / ( 2.0 * h ) ); + Z0_w_h_0 = + ( TC::ZF0 / ( 4.0 * std::sqrt( er ) ) ) * ( EllipticIntegral( k ).first / EllipticIntegral( k_p ).first ); +} + + +void COUPLED_STRIPLINE::calcZ0EvenMode() +{ + // Reference [2], Eq. 18 + const double Z_e = + 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 ) ) ); + SetParameter( TCP::Z0_E, Z_e ); +} + + +void COUPLED_STRIPLINE::calcZ0OddMode( const double t, const double s ) +{ + // Reference [2], Eq. 20 + const double Z_o_1 = + 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 ) ) ); + + // Reference [2], Eq. 22 + const double Z_o_2 = + 1.0 + / ( ( 1.0 / Z0_o_w_h_0_s_h ) + ( ( 1.0 / Z0_w_h_t_h ) - ( 1.0 / Z0_w_h_0 ) ) + - ( 2.0 / TC::ZF0 ) * ( C_f_t_h / TC::E0 - C_f_0 / TC::E0 ) + ( 2.0 * t ) / ( TC::ZF0 * s ) ); + + const double Z_o = s / t >= 5.0 ? Z_o_1 : Z_o_2; + + SetParameter( TCP::Z0_O, Z_o ); + SetParameter( TCP::Z_DIFF, 2.0 * Z_o ); +} + + +void COUPLED_STRIPLINE::calcLosses() +{ +} + + +void COUPLED_STRIPLINE::calcDielectrics() +{ + // We assume here that the dielectric is homogenous surrounding the strips - in this case, the odd or even modes + // don't change the effective dielectric constant of the transmission mode. This would not be the case if the + // dielectric were inhomogenous, as there is more electric field permeating the dielectric between the traces in + // the odd mode compared to the even mode. + const double e_r = GetParameter( TCP::EPSILONR ); + e_eff_e = e_r; + e_eff_o = e_r; + + // Both modes have the same propagation delay + const double unitPropDelay = UnitPropagationDelay( e_r ); + unit_prop_delay_e = unitPropDelay; + unit_prop_delay_o = unitPropDelay; + + // Electrical length (in radians) + const double v = TC::C0 / sqrt( e_r ); + const double lambda_g = v / GetParameter( TCP::FREQUENCY ); + ang_l = 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g; +} + + +double COUPLED_STRIPLINE::calcZ0SymmetricStripline() +{ + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, GetParameter( TCP::EPSILONR ) ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::T, GetParameter( TCP::T ) ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::STRIPLINE_A, GetParameter( TCP::H ) / 2.0 ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::H, GetParameter( TCP::H ) ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::PHYS_LEN, GetParameter( TCP::PHYS_LEN ) ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, GetParameter( TCP::FREQUENCY ) ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::TAND, 0.0 ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::PHYS_WIDTH, GetParameter( TCP::PHYS_WIDTH ) ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, 0 ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, GetParameter( TCP::SIGMA ) ); + m_striplineCalc.SetParameter( TRANSLINE_PARAMETERS::MURC, GetParameter( TCP::MURC ) ); + m_striplineCalc.Analyse(); + + return m_striplineCalc.GetParameter( TCP::Z0 ); +} diff --git a/common/transline_calculations/coupled_stripline.h b/common/transline_calculations/coupled_stripline.h new file mode 100644 index 0000000000..33c18f953e --- /dev/null +++ b/common/transline_calculations/coupled_stripline.h @@ -0,0 +1,104 @@ +/* + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef TRANSLINE_CALCULATIONS_COUPLED_STRIPLINE_H +#define TRANSLINE_CALCULATIONS_COUPLED_STRIPLINE_H + + +#include +#include + +/* + * This implements the calculations described in: + * + * [1] S. B. Cohn, "Characteristic Impedance of the Shielded-Strip Transmission Line," in Transactions of the IRE + * Professional Group on Microwave Theory and Techniques, vol. 2, no. 2, pp. 52-57, July 1954 + * [2] S. B. Cohn, "Shielded Coupled-Strip Transmission Line," in IRE Transactions on Microwave Theory and Techniques, + * vol. 3, no. 5, pp. 29-38, October 1955 + */ + +class COUPLED_STRIPLINE : public TRANSLINE_CALCULATION_BASE +{ + using TCP = TRANSLINE_PARAMETERS; + +public: + COUPLED_STRIPLINE() : + TRANSLINE_CALCULATION_BASE( { TCP::SKIN_DEPTH, TCP::Z0_E, TCP::Z0_O, TCP::Z_DIFF, TCP::PHYS_WIDTH, + TCP::FREQUENCY, TCP::PHYS_LEN, TCP::H, TCP::PHYS_S, TCP::T, TCP::EPSILONR, + TCP::MURC, TCP::SIGMA, TCP::ANG_L } ) + { + } + + /// Analyse track geometry parameters to output Z0 and Ang_L + void Analyse() override; + + /// Synthesis track geometry parameters to match given Z0 + bool Synthesize( SYNTHESIZE_OPTS aOpts ) override; + +private: + /// Sets the output values and status following analysis + void SetAnalysisResults() override; + + /// Sets the output values and status following synthesis + void SetSynthesisResults() override; + + /// Calculates the impedance of a finite-width single strip + double calcZ0SymmetricStripline(); + + /// Calculate the coupling fringe capacitances + void calcFringeCapacitances( double h, double t, double er ); + + /// Calculates impedances of finite- and zero-thickness single strips + void calcSingleStripImpedances(); + + /// Calculates zero-thickness coupled strip impedances + void calcZeroThicknessCoupledImpedances( double h, double w, double s, double er ); + + /// Calculates even mode Z0 + void calcZ0EvenMode(); + + /// Calculates odd mode Z0 + void calcZ0OddMode( double t, double s ); + + /// Calculates conductor and dielectric losses + void calcLosses(); + + /// Calculate dialectric and propagation parameters + void calcDielectrics(); + + double C_f_0{ 0.0 }; ///< Fringing capacitance from one edge to ground of zero thickness strip + double C_f_t_h{ 0.0 }; ///< Fringing capacitance of single strip of finite width + + double Z0_w_h_0{ 0.0 }; ///< Impedance of single strip of zero thickness + double Z0_w_h_t_h{ 0.0 }; ///< Impedance of single strip of finite thickness + double Z0_e_w_h_0_s_h{ 0.0 }; ///< Even mode impedance of coupled zero thickness strips + double Z0_o_w_h_0_s_h{ 0.0 }; ///< Odd mode impedance of coupled zero thickness strips + + double e_eff_e{ 0.0 }; ///< Even mode effective dielectric constant + double e_eff_o{ 0.0 }; ///< Odd mode effective dielectric constant + double ang_l{ 0.0 }; ///< Angular length (rad) + double unit_prop_delay_e{ 0.0 }; ///< Even mode unit propagation delay (ps/cm) + double unit_prop_delay_o{ 0.0 }; ///< Odd mode unit propagation delay (ps/cm) + + /// Calculator used to determine single stripline values + STRIPLINE m_striplineCalc; +}; + + +#endif //TRANSLINE_CALCULATIONS_COUPLED_STRIPLINE_H diff --git a/common/transline_calculations/microstrip.cpp b/common/transline_calculations/microstrip.cpp new file mode 100644 index 0000000000..cc31b3a24e --- /dev/null +++ b/common/transline_calculations/microstrip.cpp @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2001 Gopal Narayanan + * Copyright (C) 2002 Claudio Girardi + * Copyright (C) 2005, 2006 Stefan Jahn + * Modified for Kicad: 2018 Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + + +namespace TC = TRANSLINE_CALCULATIONS; +using TCP = TRANSLINE_PARAMETERS; + + +void MICROSTRIP::Analyse() +{ + // Effective permeability + mur_eff_ms(); + + // Static impedance + microstrip_Z0(); + + // Calculate freq dependence of er and Z0 + dispersion(); + + // Calculate electrical lengths + line_angle(); + + // Calculate losses + attenuation(); +} + + +bool MICROSTRIP::Synthesize( const SYNTHESIZE_OPTS aOpts ) +{ + const double z0_dest = GetParameter( TCP::Z0 ); + const double angl_dest = GetParameter( TCP::ANG_L ); + + // Calculate width and use for initial value in Newton's method + SetParameter( TCP::PHYS_WIDTH, SynthesizeWidth() ); + + // Optimise Z0, varying width + if( !MinimiseZ0Error1D( TCP::PHYS_WIDTH, TCP::Z0 ) ) + return false; + + // Re-calculate with required output parameters + SetParameter( TCP::Z0, z0_dest ); + SetParameter( TCP::ANG_L, angl_dest ); + double const er_eff = GetParameter( TCP::EPSILON_EFF ); + SetParameter( TCP::PHYS_LEN, TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff * mur_eff ) + * GetParameter( TCP::ANG_L ) / 2.0 / M_PI ); /* in m */ + Analyse(); + + // Set the output parameters + SetParameter( TCP::Z0, z0_dest ); + SetParameter( TCP::ANG_L, angl_dest ); + SetParameter( TCP::PHYS_LEN, TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( er_eff * mur_eff ) + * GetParameter( TCP::ANG_L ) / 2.0 / M_PI ); /* in m */ + + return true; +} + + +void MICROSTRIP::SetAnalysisResults() +{ + SetAnalysisResult( TCP::EPSILON_EFF, GetParameter( TCP::EPSILON_EFF ) ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY, GetParameter( TCP::UNIT_PROP_DELAY ) ); + SetAnalysisResult( TCP::ATTEN_COND, GetParameter( TCP::ATTEN_COND ) ); + SetAnalysisResult( TCP::ATTEN_DILECTRIC, GetParameter( TCP::ATTEN_DILECTRIC ) ); + SetAnalysisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + + const double Z0 = GetParameter( TCP::Z0 ); + const double ANG_L = GetParameter( TCP::ANG_L ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + + const bool Z0_invalid = !std::isfinite( Z0 ) || Z0 < 0; + const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + + SetAnalysisResult( TCP::Z0, Z0, Z0_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::ANG_L, ANG_L, ANG_L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); +} + + +void MICROSTRIP::SetSynthesisResults() +{ + SetSynthesisResult( TCP::EPSILON_EFF, GetParameter( TCP::EPSILON_EFF ) ); + SetSynthesisResult( TCP::UNIT_PROP_DELAY, GetParameter( TCP::UNIT_PROP_DELAY ) ); + SetSynthesisResult( TCP::ATTEN_COND, GetParameter( TCP::ATTEN_COND ) ); + SetSynthesisResult( TCP::ATTEN_DILECTRIC, GetParameter( TCP::ATTEN_DILECTRIC ) ); + SetSynthesisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + + const double Z0 = GetParameter( TCP::Z0 ); + const double ANG_L = GetParameter( TCP::ANG_L ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + + const bool Z0_invalid = !std::isfinite( Z0 ) || Z0 < 0; + const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + + SetSynthesisResult( TCP::Z0, Z0, Z0_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::ANG_L, ANG_L, ANG_L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); +} + + +double MICROSTRIP::SynthesizeWidth() const +{ + const double e_r = GetParameter( TCP::EPSILONR ); + const double a = ( ( GetParameter( TCP::Z0 ) / TC::ZF0 / 2 / M_PI ) * sqrt( ( e_r + 1 ) / 2. ) ) + + ( ( e_r - 1 ) / ( e_r + 1 ) * ( 0.23 + ( 0.11 / e_r ) ) ); + const double b = TC::ZF0 / 2 * M_PI / ( GetParameter( TCP::Z0 ) * sqrt( e_r ) ); + + double w_h; + + if( a > 1.52 ) + { + w_h = 8 * exp( a ) / ( exp( 2. * a ) - 2 ); + } + else + { + w_h = ( 2. / M_PI ) + * ( b - 1. - log( ( 2 * b ) - 1. ) + + ( ( e_r - 1 ) / ( 2 * e_r ) ) * ( log( b - 1. ) + 0.39 - 0.61 / e_r ) ); + } + + double width; + + if( GetParameter( TCP::H ) > 0.0 ) + width = w_h * GetParameter( TCP::H ); + else + width = 0; + + return width; +} + + +double MICROSTRIP::Z0_dispersion( double u, double e_r, double e_r_eff_0, double e_r_eff_f, double f_n ) +{ + const double R_1 = 0.03891 * pow( e_r, 1.4 ); + const double R_2 = 0.267 * pow( u, 7.0 ); + const double R_3 = 4.766 * exp( -3.228 * pow( u, 0.641 ) ); + const double R_4 = 0.016 + pow( 0.0514 * e_r, 4.524 ); + const double R_5 = pow( f_n / 28.843, 12.0 ); + const double R_6 = 22.2 * pow( u, 1.92 ); + const double R_7 = 1.206 - 0.3144 * exp( -R_1 ) * ( 1.0 - exp( -R_2 ) ); + const double R_8 = 1.0 + 1.275 * ( 1.0 - exp( -0.004625 * R_3 * pow( e_r, 1.674 ) * pow( f_n / 18.365, 2.745 ) ) ); + double tmpf = pow( e_r - 1.0, 6.0 ); + const double R_9 = 5.086 * R_4 * ( R_5 / ( 0.3838 + 0.386 * R_4 ) ) * ( exp( -R_6 ) / ( 1.0 + 1.2992 * R_5 ) ) + * ( tmpf / ( 1.0 + 10.0 * tmpf ) ); + const double R_10 = 0.00044 * pow( e_r, 2.136 ) + 0.0184; + tmpf = pow( f_n / 19.47, 6.0 ); + const double R_11 = tmpf / ( 1.0 + 0.0962 * tmpf ); + const double R_12 = 1.0 / ( 1.0 + 0.00245 * u * u ); + const double R_13 = 0.9408 * pow( e_r_eff_f, R_8 ) - 0.9603; + const double R_14 = ( 0.9408 - R_9 ) * pow( e_r_eff_0, R_8 ) - 0.9603; + const double R_15 = 0.707 * R_10 * pow( f_n / 12.3, 1.097 ); + const double R_16 = 1.0 + 0.0503 * e_r * e_r * R_11 * ( 1.0 - exp( -pow( u / 15.0, 6.0 ) ) ); + const double R_17 = R_7 * ( 1.0 - 1.1241 * ( R_12 / R_16 ) * exp( -0.026 * pow( f_n, 1.15656 ) - R_15 ) ); + + return pow( R_13 / R_14, R_17 ); +} + + +double MICROSTRIP::Z0_homogeneous( double u ) +{ + const double freq = 6.0 + ( 2.0 * M_PI - 6.0 ) * exp( -pow( 30.666 / u, 0.7528 ) ); + return ( TC::ZF0 / ( 2.0 * M_PI ) ) * log( freq / u + sqrt( 1.0 + 4.0 / ( u * u ) ) ); +} + + +double MICROSTRIP::delta_Z0_cover( double u, double h2h ) +{ + const double h2hp1 = 1.0 + h2h; + const double P = 270.0 * ( 1.0 - tanh( 1.192 + 0.706 * sqrt( h2hp1 ) - 1.389 / h2hp1 ) ); + const double Q = 1.0109 - atanh( ( 0.012 * u + 0.177 * u * u - 0.027 * u * u * u ) / ( h2hp1 * h2hp1 ) ); + return P * Q; +} + + +double MICROSTRIP::filling_factor( double u, double e_r ) +{ + const double u2 = u * u; + const double u3 = u2 * u; + const double u4 = u3 * u; + const double a = 1.0 + log( ( u4 + u2 / 2704 ) / ( u4 + 0.432 ) ) / 49.0 + log( 1.0 + u3 / 5929.741 ) / 18.7; + const double b = 0.564 * pow( ( e_r - 0.9 ) / ( e_r + 3.0 ), 0.053 ); + return pow( 1.0 + 10.0 / u, -a * b ); +} + + +double MICROSTRIP::delta_q_cover( double h2h ) +{ + return tanh( 1.043 + 0.121 * h2h - 1.164 / h2h ); +} + + +double MICROSTRIP::delta_q_thickness( double u, double t_h ) +{ + return ( 2.0 * log( 2.0 ) / M_PI ) * ( t_h / sqrt( u ) ); +} + + +double MICROSTRIP::e_r_effective( double e_r, double q ) +{ + return 0.5 * ( e_r + 1.0 ) + 0.5 * q * ( e_r - 1.0 ); +} + + +double MICROSTRIP::delta_u_thickness( double u, double t_h, double e_r ) +{ + double delta_u; + + if( t_h > 0.0 ) + { + /* correction for thickness for a homogeneous microstrip */ + delta_u = ( t_h / M_PI ) * log( 1.0 + ( 4.0 * M_E ) * pow( tanh( sqrt( 6.517 * u ) ), 2.0 ) / t_h ); + /* correction for strip on a substrate with relative permettivity e_r */ + delta_u = 0.5 * delta_u * ( 1.0 + 1.0 / cosh( sqrt( e_r - 1.0 ) ) ); + } + else + { + delta_u = 0.0; + } + return delta_u; +} + + +double MICROSTRIP::e_r_dispersion( double u, double e_r, double f_n ) +{ + const double P_1 = + 0.27488 + u * ( 0.6315 + 0.525 / pow( 1.0 + 0.0157 * f_n, 20.0 ) ) - 0.065683 * exp( -8.7513 * u ); + const double P_2 = 0.33622 * ( 1.0 - exp( -0.03442 * e_r ) ); + const double P_3 = 0.0363 * exp( -4.6 * u ) * ( 1.0 - exp( -pow( f_n / 38.7, 4.97 ) ) ); + const double P_4 = 1.0 + 2.751 * ( 1.0 - exp( -pow( e_r / 15.916, 8.0 ) ) ); + + return P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 ) * f_n, 1.5763 ); +} + + +double MICROSTRIP::conductor_losses() const +{ + double alpha_c; + const double e_r_eff_0 = er_eff_0; + const double delta = GetParameter( TCP::SKIN_DEPTH ); + + if( GetParameter( TCP::FREQUENCY ) > 0.0 ) + { + /* current distribution factor */ + const double K = exp( -1.2 * pow( Z0_h_1 / TC::ZF0, 0.7 ) ); + /* skin resistance */ + double R_s = 1.0 / ( GetParameter( TCP::SIGMA ) * delta ); + + /* correction for surface roughness */ + R_s *= 1.0 + ( ( 2.0 / M_PI ) * atan( 1.40 * pow( ( GetParameter( TCP::ROUGH ) / delta ), 2.0 ) ) ); + /* strip inductive quality factor */ + const double Q_c = ( M_PI * Z0_h_1 * GetParameter( TCP::PHYS_WIDTH ) * GetParameter( TCP::FREQUENCY ) ) + / ( R_s * TC::C0 * K ); + alpha_c = ( 20.0 * M_PI / log( 10.0 ) ) * GetParameter( TCP::FREQUENCY ) * sqrt( e_r_eff_0 ) / ( TC::C0 * Q_c ); + } + else + { + alpha_c = 0.0; + } + + return alpha_c; +} + + +double MICROSTRIP::dielectric_losses() const +{ + const double e_r = GetParameter( TCP::EPSILONR ); + const double e_r_eff_0 = er_eff_0; + + return ( 20.0 * M_PI / log( 10.0 ) ) * ( GetParameter( TCP::FREQUENCY ) / TC::C0 ) * ( e_r / sqrt( e_r_eff_0 ) ) + * ( ( e_r_eff_0 - 1.0 ) / ( e_r - 1.0 ) ) * GetParameter( TCP::TAND ); +} + + +void MICROSTRIP::microstrip_Z0() +{ + const double e_r = GetParameter( TCP::EPSILONR ); + const double h2 = GetParameter( TCP::H_T ); + const double h2h = h2 / GetParameter( TCP::H ); + double u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); + const double t_h = GetParameter( TCP::T ) / GetParameter( TCP::H ); + + /* compute normalized width correction for e_r = 1.0 */ + const double delta_u_1 = delta_u_thickness( u, t_h, 1.0 ); + /* compute homogeneous stripline impedance */ + Z0_h_1 = Z0_homogeneous( u + delta_u_1 ); + /* compute normalized width correction */ + const double delta_u_r = delta_u_thickness( u, t_h, e_r ); + u += delta_u_r; + /* compute homogeneous stripline impedance */ + const double Z0_h_r = Z0_homogeneous( u ); + + /* filling factor, with width corrected for thickness */ + const double q_inf = filling_factor( u, e_r ); + /* cover effect */ + const double q_c = delta_q_cover( h2h ); + /* thickness effect */ + const double q_t = delta_q_thickness( u, t_h ); + /* resultant filling factor */ + const double q = ( q_inf - q_t ) * q_c; + + /* e_r corrected for thickness and non-homogeneous material */ + const double e_r_eff_t = e_r_effective( e_r, q ); + + /* effective dielectric constant */ + const double e_r_eff = e_r_eff_t * pow( Z0_h_1 / Z0_h_r, 2.0 ); + + /* characteristic impedance, corrected for thickness, cover */ + /* and non-homogeneous material */ + SetParameter( TCP::Z0, Z0_h_r / sqrt( e_r_eff_t ) ); + + w_eff = u * GetParameter( TCP::H ); + er_eff_0 = e_r_eff; + Z0_0 = GetParameter( TCP::Z0 ); +} + + +void MICROSTRIP::dispersion() +{ + const double e_r = GetParameter( TCP::EPSILONR ); + const double e_r_eff_0 = er_eff_0; + const double u = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::H ); + + /* normalized frequency [GHz * mm] */ + const double f_n = GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::H ) / 1e06; + + const double P = e_r_dispersion( u, e_r, f_n ); + /* effective dielectric constant corrected for dispersion */ + const double e_r_eff_f = e_r - ( e_r - e_r_eff_0 ) / ( 1.0 + P ); + + const double D = Z0_dispersion( u, e_r, e_r_eff_0, e_r_eff_f, f_n ); + const double Z0_f = Z0_0 * D; + + SetParameter( TCP::UNIT_PROP_DELAY, UnitPropagationDelay( e_r_eff_f ) ); + SetParameter( TCP::EPSILON_EFF, e_r_eff_f ); + SetParameter( TCP::Z0, Z0_f ); +} + + +void MICROSTRIP::attenuation() +{ + SetParameter( TCP::SKIN_DEPTH, SkinDepth() ); + SetParameter( TCP::ATTEN_COND, conductor_losses() * GetParameter( TCP::PHYS_LEN ) ); + SetParameter( TCP::ATTEN_DILECTRIC, dielectric_losses() * GetParameter( TCP::PHYS_LEN ) ); +} + + +void MICROSTRIP::mur_eff_ms() +{ + const double mur = GetParameter( TCP::MUR ); + const double h = GetParameter( TCP::H ); + const double w = GetParameter( TCP::PHYS_WIDTH ); + mur_eff = ( 2.0 * mur ) / ( ( 1.0 + mur ) + ( ( 1.0 - mur ) * pow( ( 1.0 + ( 10.0 * h / w ) ), -0.5 ) ) ); +} + + +void MICROSTRIP::line_angle() +{ + double e_r_eff = GetParameter( TCP::EPSILON_EFF ); + + // Velocity + double v = TC::C0 / sqrt( e_r_eff * mur_eff ); + // Wavelength + double lambda_g = v / GetParameter( TCP::FREQUENCY ); + // Electrical angles (rad) + SetParameter( TCP::ANG_L, 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) / lambda_g ); +} diff --git a/common/transline_calculations/microstrip.h b/common/transline_calculations/microstrip.h new file mode 100644 index 0000000000..cb1a1194b6 --- /dev/null +++ b/common/transline_calculations/microstrip.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2001 Gopal Narayanan + * Copyright (C) 2002 Claudio Girardi + * Copyright (C) 2005, 2006 Stefan Jahn + * Modified for Kicad: 2018 Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef TRANSLINE_CALCULATIONS_MICROSTRIP_H +#define TRANSLINE_CALCULATIONS_MICROSTRIP_H + + +#include + + +class MICROSTRIP : public TRANSLINE_CALCULATION_BASE +{ + using TCP = TRANSLINE_PARAMETERS; + +public: + MICROSTRIP() : + TRANSLINE_CALCULATION_BASE( { TCP::EPSILONR, TCP::H_T, TCP::H, TCP::PHYS_WIDTH, TCP::T, TCP::Z0, + TCP::FREQUENCY, TCP::EPSILON_EFF, TCP::SKIN_DEPTH, TCP::SIGMA, TCP::ROUGH, + TCP::TAND, TCP::PHYS_LEN, TCP::MUR, TCP::MURC, TCP::ANG_L, + TCP::UNIT_PROP_DELAY, TCP::ATTEN_COND, TCP::ATTEN_DILECTRIC } ) + { + } + + friend class COUPLED_MICROSTRIP; + + /// Analyse track geometry parameters to output Z0 and Ang_L + void Analyse() override; + + /// Synthesis track geometry parameters to match given Z0 + bool Synthesize( SYNTHESIZE_OPTS aOpts ) override; + +private: + /// Sets the output values and status following analysis + void SetAnalysisResults() override; + + /// Sets the output values and status following synthesis + void SetSynthesisResults() override; + + /// Calculates the width with the current set of parameters + double SynthesizeWidth() const; + + /// Calculates the dispersion correction factor for the characteristic impedance static + static double Z0_dispersion( double, double, double, double, double ); + + /// Calculates the impedance for a stripline in a homogeneous medium, without cover effects + static double Z0_homogeneous( double ); + + /// Calculates the cover effect on impedance for a stripline in a homogeneous medium + static double delta_Z0_cover( double, double ); + + /// Calculates the filling factor for a microstrip without cover and zero conductor thickness + static double filling_factor( double, double ); + + /// Calculates the cover effect on filling factor + static double delta_q_cover( double ); + + /// Calculates the thickness effect on filling factor + static double delta_q_thickness( double, double ); + + /// Calculates effective dielectric constant from material e_r and filling factor + static double e_r_effective( double, double ); + + /// Calculates the thickness effect on normalized width + static double delta_u_thickness( double, double, double ); + + /// Calculates the dispersion correction factor for the effective permeability + static double e_r_dispersion( double, double, double ); + + /// Calculate the microstrip conductor losses per unit + double conductor_losses() const; + + /// Calculates the microstrip dielectric losses per unit + double dielectric_losses() const; + + /// Calculates the microstrip static impedance + void microstrip_Z0(); + + /// Calculates frequency dependent parameters of the microstrip + void dispersion(); + + /// Calculates the attenuation of the microstrip + void attenuation(); + + /// Calculates the effective magnetic permeability + void mur_eff_ms(); + + /// Calculates microstrip length in radians + void line_angle(); + + double Z0_0{ 0.0 }; ///< static characteristic impedance + double er_eff_0{ 0.0 }; ///< Static effective dielectric constant + double mur_eff{ 0.0 }; ///< Effective mag. permeability + double w_eff{ 0.0 }; ///< Effective width of line + double Z0_h_1{ 0.0 }; ///< homogeneous stripline impedance +}; + + +#endif //TRANSLINE_CALCULATIONS_MICROSTRIP_H diff --git a/common/transline_calculations/stripline.cpp b/common/transline_calculations/stripline.cpp new file mode 100644 index 0000000000..bc5193bea6 --- /dev/null +++ b/common/transline_calculations/stripline.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2001 Gopal Narayanan + * Copyright (C) 2002 Claudio Girardi + * Copyright (C) 2005, 2006 Stefan Jahn + * Modified for Kicad: 2018 Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + + +namespace TC = TRANSLINE_CALCULATIONS; +using TCP = TRANSLINE_PARAMETERS; + + +void STRIPLINE::Analyse() +{ + SetParameter( TCP::SKIN_DEPTH, SkinDepth() ); + SetParameter( TCP::EPSILON_EFF, GetParameter( TCP::EPSILONR ) ); // no dispersion + + double ac1, ac2; + double t = GetParameter( TCP::T ); + double a = GetParameter( TCP::STRIPLINE_A ); + double h = GetParameter( TCP::H ); + SetParameter( TCP::Z0, + 2.0 / ( 1.0 / lineImpedance( 2.0 * a + t, ac1 ) + 1.0 / lineImpedance( 2.0 * ( h - a ) - t, ac2 ) ) ); + SetParameter( TCP::LOSS_CONDUCTOR, GetParameter( TCP::PHYS_LEN ) * ( ac1 + ac2 ) ); + SetParameter( TCP::LOSS_DIELECTRIC, TC::LOG2DB * GetParameter( TCP::PHYS_LEN ) * ( M_PI / TC::C0 ) + * GetParameter( TCP::FREQUENCY ) * sqrt( GetParameter( TCP::EPSILONR ) ) + * GetParameter( TCP::TAND ) ); + + SetParameter( TCP::ANG_L, 2.0 * M_PI * GetParameter( TCP::PHYS_LEN ) * sqrt( GetParameter( TCP::EPSILONR ) ) + * GetParameter( TCP::FREQUENCY ) / TC::C0 ); // in radians + + unit_prop_delay = UnitPropagationDelay( GetParameter( TCP::EPSILON_EFF ) ); +} + + +bool STRIPLINE::Synthesize( const SYNTHESIZE_OPTS aOpts ) +{ + return MinimiseZ0Error1D( TCP::PHYS_WIDTH, TCP::Z0 ); +} + + +void STRIPLINE::SetAnalysisResults() +{ + SetAnalysisResult( TCP::EPSILON_EFF, GetParameter( TCP::EPSILON_EFF ) ); + SetAnalysisResult( TCP::UNIT_PROP_DELAY, unit_prop_delay ); + SetAnalysisResult( TCP::LOSS_CONDUCTOR, GetParameter( TCP::LOSS_CONDUCTOR ) ); + SetAnalysisResult( TCP::LOSS_DIELECTRIC, GetParameter( TCP::LOSS_DIELECTRIC ) ); + SetAnalysisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + + const double Z0 = GetParameter( TCP::Z0 ); + const double ANG_L = GetParameter( TCP::ANG_L ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + + const bool Z0_invalid = !std::isfinite( Z0 ) || Z0 < 0; + const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + + bool invalid = false; + + if( GetParameter( TCP::STRIPLINE_A ) + GetParameter( TCP::T ) >= GetParameter( TCP::H ) ) + invalid = true; + + SetAnalysisResult( TCP::Z0, Z0, Z0_invalid || invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::ANG_L, ANG_L, ANG_L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::PHYS_WIDTH, W, W_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::STRIPLINE_A, GetParameter( TCP::STRIPLINE_A ), + invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::T, GetParameter( TCP::T ), invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::H, GetParameter( TCP::H ), invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetAnalysisResult( TCP::Z0, GetParameter( TCP::Z0 ), invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); +} + + +void STRIPLINE::SetSynthesisResults() +{ + SetSynthesisResult( TCP::EPSILON_EFF, GetParameter( TCP::EPSILON_EFF ) ); + SetSynthesisResult( TCP::UNIT_PROP_DELAY, unit_prop_delay ); + SetSynthesisResult( TCP::LOSS_CONDUCTOR, GetParameter( TCP::LOSS_CONDUCTOR ) ); + SetSynthesisResult( TCP::LOSS_DIELECTRIC, GetParameter( TCP::LOSS_DIELECTRIC ) ); + SetSynthesisResult( TCP::SKIN_DEPTH, GetParameter( TCP::SKIN_DEPTH ) ); + + const double Z0 = GetParameter( TCP::Z0 ); + const double ANG_L = GetParameter( TCP::ANG_L ); + const double L = GetParameter( TCP::PHYS_LEN ); + const double W = GetParameter( TCP::PHYS_WIDTH ); + + const bool Z0_invalid = !std::isfinite( Z0 ) || Z0 < 0; + const bool ANG_L_invalid = !std::isfinite( ANG_L ) || ANG_L < 0; + const bool L_invalid = !std::isfinite( L ) || L < 0; + const bool W_invalid = !std::isfinite( W ) || W <= 0; + + bool invalid = false; + + if( GetParameter( TCP::STRIPLINE_A ) + GetParameter( TCP::T ) >= GetParameter( TCP::H ) ) + invalid = true; + + SetSynthesisResult( TCP::Z0, Z0, Z0_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::ANG_L, ANG_L, ANG_L_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::PHYS_LEN, L, L_invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::PHYS_WIDTH, W, W_invalid || invalid ? TRANSLINE_STATUS::ERROR : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::STRIPLINE_A, GetParameter( TCP::STRIPLINE_A ), + invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::T, GetParameter( TCP::T ), invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); + SetSynthesisResult( TCP::H, GetParameter( TCP::H ), invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK ); +} + + +double STRIPLINE::lineImpedance( double aHeight, double& aAc ) const +{ + double ZL; + const double hmt = aHeight - GetParameter( TCP::T ); + + aAc = sqrt( GetParameter( TCP::FREQUENCY ) / GetParameter( TCP::SIGMA ) / 17.2 ); + + if( GetParameter( TCP::PHYS_WIDTH ) / hmt >= 0.35 ) + { + ZL = GetParameter( TCP::PHYS_WIDTH ) + + ( 2.0 * aHeight * log( ( 2.0 * aHeight - GetParameter( TCP::T ) ) / hmt ) + - GetParameter( TCP::T ) * log( aHeight * aHeight / hmt / hmt - 1.0 ) ) + / M_PI; + ZL = TC::ZF0 * hmt / sqrt( GetParameter( TCP::EPSILONR ) ) / 4.0 / ZL; + + aAc *= 2.02e-6 * GetParameter( TCP::EPSILONR ) * ZL / hmt; + aAc *= 1.0 + 2.0 * GetParameter( TCP::PHYS_WIDTH ) / hmt + + ( aHeight + GetParameter( TCP::T ) ) / hmt / M_PI + * log( 2.0 * aHeight / GetParameter( TCP::T ) - 1.0 ); + } + else + { + double tdw = GetParameter( TCP::T ) / GetParameter( TCP::PHYS_WIDTH ); + + if( GetParameter( TCP::T ) / GetParameter( TCP::PHYS_WIDTH ) > 1.0 ) + tdw = GetParameter( TCP::PHYS_WIDTH ) / GetParameter( TCP::T ); + + double de = 1.0 + tdw / M_PI * ( 1.0 + log( 4.0 * M_PI / tdw ) ) + 0.236 * pow( tdw, 1.65 ); + + if( GetParameter( TCP::T ) / GetParameter( TCP::PHYS_WIDTH ) > 1.0 ) + de *= GetParameter( TCP::T ) / 2.0; + else + de *= GetParameter( TCP::PHYS_WIDTH ) / 2.0; + + ZL = TC::ZF0 / 2.0 / M_PI / sqrt( GetParameter( TCP::EPSILONR ) ) * log( 4.0 * aHeight / M_PI / de ); + + aAc *= 0.01141 / ZL / de; + aAc *= de / aHeight + 0.5 + tdw / 2.0 / M_PI + 0.5 / M_PI * log( 4.0 * M_PI / tdw ) + 0.1947 * pow( tdw, 0.65 ) + - 0.0767 * pow( tdw, 1.65 ); + } + + return ZL; +} diff --git a/common/transline_calculations/stripline.h b/common/transline_calculations/stripline.h new file mode 100644 index 0000000000..b51014dbb0 --- /dev/null +++ b/common/transline_calculations/stripline.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2001 Gopal Narayanan + * Copyright (C) 2002 Claudio Girardi + * Copyright (C) 2005, 2006 Stefan Jahn + * Modified for Kicad: 2018 Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef TRANSLINE_CALCULATIONS_STRIPLINE_H +#define TRANSLINE_CALCULATIONS_STRIPLINE_H + + +#include + + +class STRIPLINE : public TRANSLINE_CALCULATION_BASE +{ + using TCP = TRANSLINE_PARAMETERS; + +public: + STRIPLINE() : + TRANSLINE_CALCULATION_BASE( { TCP::SKIN_DEPTH, TCP::EPSILON_EFF, TCP::EPSILONR, TCP::T, TCP::STRIPLINE_A, + TCP::H, TCP::Z0, TCP::LOSS_CONDUCTOR, TCP::PHYS_LEN, TCP::LOSS_DIELECTRIC, + TCP::FREQUENCY, TCP::TAND, TCP::PHYS_WIDTH, TCP::UNIT_PROP_DELAY, TCP::ANG_L, + TCP::SIGMA, TCP::MURC } ) + { + } + + /// Analyse track geometry parameters to output Z0 and Ang_L + void Analyse() override; + + /// Synthesis track geometry parameters to match given Z0 + bool Synthesize( SYNTHESIZE_OPTS aOpts ) override; + +private: + /// Sets the output values and status following analysis + void SetAnalysisResults() override; + + /// Sets the output values and status following synthesis + void SetSynthesisResults() override; + + /// Calculate characteristic impedance and conductor loss (in db/meter) + double lineImpedance( double aHeight, double& aAc ) const; + + double unit_prop_delay; +}; + + +#endif //TRANSLINE_CALCULATIONS_STRIPLINE_H diff --git a/common/transline_calculations/transline_calculation_base.cpp b/common/transline_calculations/transline_calculation_base.cpp new file mode 100644 index 0000000000..38f1538453 --- /dev/null +++ b/common/transline_calculations/transline_calculation_base.cpp @@ -0,0 +1,225 @@ +/* + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + + +using TCP = TRANSLINE_PARAMETERS; +namespace TC = TRANSLINE_CALCULATIONS; + + +void TRANSLINE_CALCULATION_BASE::InitProperties( const std::initializer_list& aParams ) +{ + for( const TRANSLINE_PARAMETERS& param : aParams ) + m_parameters[param] = 0.0; +} + + +std::unordered_map>& +TRANSLINE_CALCULATION_BASE::GetAnalysisResults() +{ + SetAnalysisResults(); + return m_analysisStatus; +} + + +std::unordered_map>& +TRANSLINE_CALCULATION_BASE::GetSynthesisResults() +{ + SetSynthesisResults(); + return m_synthesisStatus; +} + + +void TRANSLINE_CALCULATION_BASE::SetAnalysisResult( const TRANSLINE_PARAMETERS aParam, const double aValue, + const TRANSLINE_STATUS aStatus ) +{ + m_analysisStatus[aParam] = { aValue, aStatus }; +} + + +void TRANSLINE_CALCULATION_BASE::SetSynthesisResult( const TRANSLINE_PARAMETERS aParam, const double aValue, + const TRANSLINE_STATUS aStatus ) +{ + m_synthesisStatus[aParam] = { aValue, aStatus }; +} + + +bool TRANSLINE_CALCULATION_BASE::MinimiseZ0Error1D( const TRANSLINE_PARAMETERS aOptimise, + const TRANSLINE_PARAMETERS aMeasure ) +{ + double& var = GetParameterRef( aOptimise ); + double& Z0_param = GetParameterRef( aMeasure ); + double& ANG_L_param = GetParameterRef( TCP::ANG_L ); + + if( !std::isfinite( Z0_param ) ) + { + var = NAN; + return false; + } + + if( ( !std::isfinite( var ) ) || ( var == 0 ) ) + var = 0.001; + + /* required value of Z0 */ + double Z0_dest = Z0_param; + + /* required value of angl_l */ + double angl_l_dest = ANG_L_param; + + /* Newton's method */ + int iteration = 0; + + /* compute parameters */ + Analyse(); + double Z0_current = Z0_param; + + double error = fabs( Z0_dest - Z0_current ); + + while( error > m_maxError ) + { + iteration++; + double increment = var / 100.0; + var += increment; + + /* compute parameters */ + Analyse(); + double Z0_result = Z0_param; + + // f(w(n)) = Z0 - Z0(w(n)) + // f'(w(n)) = -f'(Z0(w(n))) + // f'(Z0(w(n))) = (Z0(w(n)) - Z0(w(n+delw))/delw + // w(n+1) = w(n) - f(w(n))/f'(w(n)) + double slope = ( Z0_result - Z0_current ) / increment; + slope = ( Z0_dest - Z0_current ) / slope - increment; + var += slope; + + if( var <= 0.0 ) + var = increment; + + /* find new error */ + /* compute parameters */ + Analyse(); + Z0_current = Z0_param; + error = fabs( Z0_dest - Z0_current ); + + if( iteration > 250 ) + break; + } + + /* Compute one last time, but with correct length */ + Z0_param = Z0_dest; + ANG_L_param = angl_l_dest; + SetParameter( TCP::PHYS_LEN, TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( GetParameter( TCP::EPSILON_EFF ) ) + * ANG_L_param / 2.0 / M_PI ); /* in m */ + Analyse(); + + /* Restore parameters */ + Z0_param = Z0_dest; + ANG_L_param = angl_l_dest; + SetParameter( TCP::PHYS_LEN, TC::C0 / GetParameter( TCP::FREQUENCY ) / sqrt( GetParameter( TCP::EPSILON_EFF ) ) + * ANG_L_param / 2.0 / M_PI ); /* in m */ + + return error <= m_maxError; +} + + +double TRANSLINE_CALCULATION_BASE::SkinDepth() const +{ + double depth = 1.0 + / sqrt( M_PI * GetParameter( TCP::FREQUENCY ) * GetParameter( TCP::MURC ) + * TRANSLINE_CALCULATIONS::MU0 * GetParameter( TCP::SIGMA ) ); + return depth; +} + + +double TRANSLINE_CALCULATION_BASE::UnitPropagationDelay( const double aEpsilonEff ) +{ + return std::sqrt( aEpsilonEff ) * ( 1.0e10 / 2.99e8 ); +} + + +std::pair TRANSLINE_CALCULATION_BASE::EllipticIntegral( const double arg ) +{ + static constexpr double NR_EPSI = 2.2204460492503131e-16; + int iMax = 16; + + double k = 0.0, e = 0.0; + + if( arg == 1.0 ) + { + k = INFINITY; // infinite + e = 0; + } + else if( std::isinf( arg ) && arg < 0 ) + { + k = 0; + e = INFINITY; // infinite + } + else + { + double a, b, c, fr, s, fk = 1, fe = 1, t, da = arg; + int i; + + if( arg < 0 ) + { + fk = 1 / sqrt( 1 - arg ); + fe = sqrt( 1 - arg ); + da = -arg / ( 1 - arg ); + } + + a = 1; + b = sqrt( 1 - da ); + c = sqrt( da ); + fr = 0.5; + s = fr * c * c; + + for( i = 0; i < iMax; i++ ) + { + t = ( a + b ) / 2; + c = ( a - b ) / 2; + b = sqrt( a * b ); + a = t; + fr *= 2; + s += fr * c * c; + + if( c / a < NR_EPSI ) + break; + } + + if( i >= iMax ) + { + k = 0; + e = 0; + } + else + { + k = M_PI_2 / a; + e = M_PI_2 * ( 1 - s ) / a; + if( arg < 0 ) + { + k *= fk; + e *= fe; + } + } + } + + return { k, e }; +} diff --git a/common/transline_calculations/transline_calculation_base.h b/common/transline_calculations/transline_calculation_base.h new file mode 100644 index 0000000000..97c38a5009 --- /dev/null +++ b/common/transline_calculations/transline_calculation_base.h @@ -0,0 +1,227 @@ +/* + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef TRANSLINE_CALCULATIONS_TRANSLINE_CALCULATION_BASE_H +#define TRANSLINE_CALCULATIONS_TRANSLINE_CALCULATION_BASE_H + + +#include + + +/// All possible parameters used (as inputs or outputs) by the transmission line calculations +enum class TRANSLINE_PARAMETERS : int +{ + // The following parameters are accessible from the UI + UNKNOWN_ID = -1, + EPSILONR, // Dielectric constant + TAND, // Dielectric Loss Tangent + RHO, // Conductivity of conductor + H, // Height of substrate + H_T, // Height of top surface + T, // Height of top conductor + PHYS_WIDTH, // Width of trace + PHYS_DIAM_IN, // Inner diameter of cable + PHYS_S, // width of gap between line and ground + PHYS_DIAM_OUT, // Outer diameter of cable + PHYS_LEN, // Length of cable + ROUGH, // Surface roughness + MUR, // Magnetic permeability of substrate + MURC, // magnetic permeability of conductor + FREQUENCY, // Frequency of operation + STRIPLINE_A, // Stripline : distance from track to top plane + TWISTEDPAIR_TWIST, // Twists per length + TWISTEDPAIR_EPSILONR_ENV, // Dielectric constant of environment + Z0, // Characteristic impedance + Z0_E, // Even-mode characteristic impedance + Z0_O, // Odd-mode characteristic impedance + ANG_L, // Electrical length in angle + DUMMY_PRM, + + // The following parameters are generated by calculations + SIGMA, // Conductivity of the metal + SKIN_DEPTH, // Skin depth + LOSS_DIELECTRIC, // Loss in dielectric (dB) + LOSS_CONDUCTOR, // Loss in conductors (dB) + CUTOFF_FREQUENCY, // Cutoff frequency for higher order modes + EPSILON_EFF, // Effective dielectric constant + EPSILON_EFF_EVEN, // Even mode effective dielectric constant + EPSILON_EFF_ODD, // Odd mode effective dielectric constant + UNIT_PROP_DELAY, // The unit propagation delay (ps/cm) + UNIT_PROP_DELAY_ODD, // The odd mode unit propagation delay (ps/cm) + UNIT_PROP_DELAY_EVEN, // The even mode unit propagation delay (ps/cm) + ATTEN_COND, // The attenuation of the conductor + ATTEN_COND_EVEN, // The even mode attenuation of the conductor + ATTEN_COND_ODD, // The odd mode attenuation of the conductor + ATTEN_DILECTRIC, // The attenuation of the dilectric + ATTEN_DILECTRIC_EVEN, // The even mode attenuation of the dilectric + ATTEN_DILECTRIC_ODD, // The odd mode attenuation of the dilectric + Z_DIFF, // The differential impedance + EXTRAS_COUNT +}; + + +/// Options for specifying synthesis inputs, targets, or strategies +enum class SYNTHESIZE_OPTS +{ + DEFAULT, // Use the default synthesis options for the calculation + FIX_WIDTH, // Fixes the width of a differential pair + FIX_SPACING // Fixes the spacing of a differential pair +}; + + +/// Parameter status values +enum class TRANSLINE_STATUS +{ + OK, + WARNING, + ERROR +}; + + +/** +* The base class for all transmission line calculations. This is used by the PCB calculator, and by delay profiles +*/ +class TRANSLINE_CALCULATION_BASE +{ +public: + /** + * Constructs the transmission line calculation object. + * + * @aParameters all parameters that are used (as inputs or outputs) by the calculation + */ + TRANSLINE_CALCULATION_BASE( std::initializer_list aParameters ) + { + InitProperties( aParameters ); + } + + virtual ~TRANSLINE_CALCULATION_BASE() {} + + /// Sets the given calculation property + void SetParameter( const TRANSLINE_PARAMETERS aParam, const double aValue ) { m_parameters.at( aParam ) = aValue; } + + /// Gets the given calculation property + double GetParameter( const TRANSLINE_PARAMETERS aParam ) const { return m_parameters.at( aParam ); } + + /// Adds a constant to the given parameter + double& GetParameterRef( const TRANSLINE_PARAMETERS aParam ) { return m_parameters[aParam]; } + + /// Gets the output parameters following analysis + std::unordered_map>& GetAnalysisResults(); + + /// Gets the output parameters following synthesis + std::unordered_map>& GetSynthesisResults(); + + /// Analyses the transmission line using the current parameter set + virtual void Analyse() = 0; + + /// Synthesis the transmission line using the current parameter set target + /// @returns true if the synthesis converged, otherwise false + virtual bool Synthesize( SYNTHESIZE_OPTS aOpts ) = 0; + +protected: + /// Initialises the properties used (as inputs or outputs) by the calculation + void InitProperties( const std::initializer_list& aParams ); + + /// Sets values in the output analysis results structure + virtual void SetAnalysisResults() = 0; + + /// Sets values in the output synthesis results structure + virtual void SetSynthesisResults() = 0; + + /// Sets an analysis result + void SetAnalysisResult( TRANSLINE_PARAMETERS aParam, const double aValue, + const TRANSLINE_STATUS aStatus = TRANSLINE_STATUS::OK ); + + /// Sets a synthesis result + void SetSynthesisResult( TRANSLINE_PARAMETERS aParam, const double aValue, + const TRANSLINE_STATUS aStatus = TRANSLINE_STATUS::OK ); + + /** + * minimizeZ0Error1D + * + * Tries to find a parameter that minimizes the error on Z0. + * This function only works with a single parameter. + * Calls @ref Analyse several times until the error is acceptable. + * + * This function does not change Z0 / Angl_L + * + * @param aOptimise Parameter to optimise + * @param aMeasure The parameter to measure / optimise against + * @returns true if error < MAX_ERROR, otherwise false + */ + bool MinimiseZ0Error1D( TRANSLINE_PARAMETERS aOptimise, TRANSLINE_PARAMETERS aMeasure ); + + /** + * minimizeZ0Error2D + * + * Tries to find the parameters that minimizes the error on Z_Diff. + * This function only works with two parameters. + * Calls @ref Analyse several times until the error is acceptable. + * While the error is unacceptable, changes slightly the parameter. + * + * This function does not change Z0 / Angl_L + * + * @param aParam1 First parameter to optimise + * @param aParam2 Secpmd parameter to optimise + * @returns true if error < MAX_ERROR, otherwise false + */ + bool MinimiseZ0Error2D( TRANSLINE_PARAMETERS aParam1, TRANSLINE_PARAMETERS aParam2 ); + + /** + * Calculate skin depth + * + * \f$ \frac{1}{\sqrt{ \pi \cdot f \cdot \mu \cdot \sigma }} \f$ + */ + double SkinDepth() const; + + /** + * Calculates the unit propagation delay (ps/cm) for the given effective permittivity + * + * @aEpsilonEff is the effective permittivity of the material + */ + static double UnitPropagationDelay( double aEpsilonEff ); + + /** + * Computes the complete elliptic integral of first kind K() and the second kind E() using the + * arithmetic-geometric mean algorithm (AGM) by Abramowitz and Stegun. + * + * @returns std::pair where K = first kind integral, E = second kind integral + */ + static std::pair EllipticIntegral( double arg ); + + /// Calculates cosh of the given argument + static double coth( const double x ) { return ( std::exp( 2.0 * x ) + 1.0 ) / ( std::exp( 2.0 * x ) - 1.0 ); } + + /// Calculates sech of the given argument + static double sech( const double x ) { return 2.0 / ( std::exp( x ) + std::exp( -x ) ); } + + /// All input and output properties used by the calculation + std::unordered_map m_parameters; + + /// Analysis results + std::unordered_map> m_analysisStatus; + + /// Synthesis results + std::unordered_map> m_synthesisStatus; + + /// The maximum error for Z0 optimisations + static constexpr double m_maxError{ 0.000001 }; +}; + +#endif //TRANSLINE_CALCULATIONS_TRANSLINE_CALCULATION_BASE_H diff --git a/common/transline_calculations/units.h b/common/transline_calculations/units.h new file mode 100644 index 0000000000..ad58528a63 --- /dev/null +++ b/common/transline_calculations/units.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 1992-2011 jean-pierre.charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef TRANSLINE_CALCULATIONS_UNITS_H +#define TRANSLINE_CALCULATIONS_UNITS_H + + +#include + + +#ifndef HAVE_CMATH_ASINH +inline double asinh( double x ) +{ + return log( x + sqrt( x * x + 1 ) ); +} +#endif + +#ifndef HAVE_CMATH_ACOSH +inline double acosh( double x ) +{ + // must be x>=1, if not return Nan (Not a Number) + if( x < 1.0 ) + return sqrt( -1.0 ); + + // return only the positive result (as sqrt does). + return log( x + sqrt( x * x - 1.0 ) ); +} +#endif + +#ifndef HAVE_CMATH_ATANH +inline double atanh( double x ) +{ + // must be x>-1, x<1, if not return Nan (Not a Number) + if( !( x > -1.0 && x < 1.0 ) ) + return sqrt( -1.0 ); + + return log( ( 1.0 + x ) / ( 1.0 - x ) ) / 2.0; +} +#endif + +namespace TRANSLINE_CALCULATIONS +{ +constexpr double MU0 = 12.566370614e-7; // magnetic constant +constexpr double E0 = 8.854e-12; // permittivity of free space +constexpr double C0 = 299792458.0; // speed of light in vacuum +constexpr double ZF0 = 376.730313668; // wave resistance in vacuum + +// const to convert a attenuation / loss from log (Neper) to decibel +// (1 Np = 8.68589 dB) +const double LOG2DB = 20.0 / log( 10.0 ); + +// ZF0 value update: +// https://physics.nist.gov/cgi-bin/cuu/Value?z0 +}; // namespace TRANSLINE_CALCULATIONS + +#endif // TRANSLINE_CALCULATIONS_UNITS_H diff --git a/common/transline_calculations/units_scales.h b/common/transline_calculations/units_scales.h new file mode 100644 index 0000000000..9579b69e33 --- /dev/null +++ b/common/transline_calculations/units_scales.h @@ -0,0 +1,72 @@ +/* + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef TRANSLINE_CALCULATION_UNITS_SCALES_H +#define TRANSLINE_CALCULATION_UNITS_SCALES_H + + +namespace TRANSLINE_CALCULATIONS +{ +constexpr double UNIT_KM = 1e3; // km to meter +constexpr double UNIT_M = 1; // m to meter +constexpr double UNIT_CM = 1e-2; // cm to meter +constexpr double UNIT_MM = 1e-3; // mm to meter +constexpr double UNIT_MICRON = 1e-6; // um to meter +constexpr double UNIT_INCH = ( 1e-2 * 2.54 ); // inch to meter +constexpr double UNIT_MIL = ( 1e-5 * 2.54 ); // mil (or thou) to meter +constexpr double UNIT_FEET = 0.3048; // feet to meter +constexpr double UNIT_OZSQFT = ( 34.40 * UNIT_MICRON ); // 1 oz/ft^2 is 34.30 microns nominal, 30.90 minimum + +constexpr double UNIT_GHZ = 1e9; +constexpr double UNIT_MHZ = 1e6; +constexpr double UNIT_KHZ = 1e3; + +constexpr double UNIT_DEGREE = M_PI / 180.0; // degree to radian +constexpr double UNIT_RADIAN = 1.0; // Radian to radian + +constexpr double UNIT_OHM = 1.0; // Ohm to Ohm +constexpr double UNIT_KOHM = 1e3; // KOhm to Ohm + +constexpr double UNIT_OHM_PER_METER = 1.0; // Ohm per meter to Ohm per meter +constexpr double UNIT_OHM_PER_KILOMETER = 1e-3; // Ohm per kilometer to Ohm per meter +constexpr double UNIT_OHM_PER_FEET = 3.28084; // Ohm per feet to Ohm per meter +constexpr double UNIT_OHM_PER_1000FEET = 3.28084e-3; // Ohm per 1000feet to Ohm per meter + +constexpr double UNIT_KILOVOLT = 1e-3; // Kilovolt to Volt +constexpr double UNIT_VOLT = 1.0; // Volt to Volt +constexpr double UNIT_MILLIVOLT = 1e+3; // Millivolt to Volt + +constexpr double UNIT_MEGAWATT = 1e-6; // Kilowatt to Watt +constexpr double UNIT_KILOWATT = 1e-3; // Kilowatt to Watt +constexpr double UNIT_WATT = 1.0; // Watt to Watt +constexpr double UNIT_MILLIWATT = 1e+3; // Milliwatt to Watt + +constexpr double UNIT_METER_PER_SECOND = 1.0; // meter per second to meter per second +constexpr double UNIT_KILOMETER_PER_HOUR = ( 1 / 3.6 ); // km/h to m/s +constexpr double UNIT_FEET_PER_SECOND = 0.3048; // ft/s to m/s +constexpr double UNIT_MILES_PER_HOUR = 1609.34; // mi/h to m/s + +constexpr double UNIT_SECOND = 1.0; // second to second +constexpr double UNIT_MSECOND = 1e-3; // millisecond to second +constexpr double UNIT_USECOND = 1e-6; // microsecond to second +constexpr double UNIT_NSECOND = 1e-9; // nanosecond to second +constexpr double UNIT_PSECOND = 1e-12; // picosecond to second +}; // namespace TRANSLINE_CALCULATIONS + +#endif // TRANSLINE_CALCULATION_UNITS_SCALES_H diff --git a/include/bitmaps/bitmaps_list.h b/include/bitmaps/bitmaps_list.h index 99add04c8e..e3ce4a3907 100644 --- a/include/bitmaps/bitmaps_list.h +++ b/include/bitmaps/bitmaps_list.h @@ -139,6 +139,7 @@ enum class BITMAPS : unsigned int copper_layers_setup, copy, copy_pad_settings, + coupled_stripline, cpw, cpw_back, cursor, diff --git a/pcb_calculator/CMakeLists.txt b/pcb_calculator/CMakeLists.txt index 8fcf58e46c..c26173a829 100644 --- a/pcb_calculator/CMakeLists.txt +++ b/pcb_calculator/CMakeLists.txt @@ -57,6 +57,7 @@ set( PCB_CALCULATOR_SRCS transline/coax.cpp transline/rectwaveguide.cpp transline/stripline.cpp + transline/c_stripline.cpp transline/twistedpair.cpp transline_dlg_funct.cpp attenuators/attenuator_classes.cpp diff --git a/pcb_calculator/calculator_panels/panel_transline.cpp b/pcb_calculator/calculator_panels/panel_transline.cpp index 0b59d73935..eb60b5623f 100644 --- a/pcb_calculator/calculator_panels/panel_transline.cpp +++ b/pcb_calculator/calculator_panels/panel_transline.cpp @@ -37,19 +37,11 @@ PANEL_TRANSLINE::PANEL_TRANSLINE( wxWindow* parent, wxWindowID id, const wxPoint // Populate transline list ordered like in dialog menu list - const static TRANSLINE_TYPE_ID tltype_list[8] = - { - MICROSTRIP_TYPE, - CPW_TYPE, - GROUNDED_CPW_TYPE, - RECTWAVEGUIDE_TYPE, - COAX_TYPE, - C_MICROSTRIP_TYPE, - STRIPLINE_TYPE, - TWISTEDPAIR_TYPE - }; + const static TRANSLINE_TYPE_ID tltype_list[9] = { MICROSTRIP_TYPE, C_MICROSTRIP_TYPE, STRIPLINE_TYPE, + C_STRIPLINE_TYPE, CPW_TYPE, GROUNDED_CPW_TYPE, + RECTWAVEGUIDE_TYPE, COAX_TYPE, TWISTEDPAIR_TYPE }; - for( int ii = 0; ii < 8; ii++ ) + for( int ii = 0; ii < 9; ii++ ) m_transline_list.push_back( new TRANSLINE_IDENT( tltype_list[ii] ) ); m_EpsilonR_label->SetLabel( wxT( "εr" ) ); diff --git a/pcb_calculator/calculator_panels/panel_transline_base.cpp b/pcb_calculator/calculator_panels/panel_transline_base.cpp index 0a836fb1da..bac39caa0f 100644 --- a/pcb_calculator/calculator_panels/panel_transline_base.cpp +++ b/pcb_calculator/calculator_panels/panel_transline_base.cpp @@ -20,14 +20,22 @@ PANEL_TRANSLINE_BASE::PANEL_TRANSLINE_BASE( wxWindow* parent, wxWindowID id, con wxBoxSizer* bLeftSizer; bLeftSizer = new wxBoxSizer( wxVERTICAL ); - wxString m_TranslineSelectionChoices[] = { _("Microstrip Line"), _("Coplanar wave guide"), _("Coplanar wave guide w/ ground plane"), _("Rectangular Waveguide"), _("Coaxial Line"), _("Coupled Microstrip Line"), _("Stripline"), _("Twisted Pair") }; - int m_TranslineSelectionNChoices = sizeof( m_TranslineSelectionChoices ) / sizeof( wxString ); - m_TranslineSelection = new wxRadioBox( this, wxID_ANY, _("Transmission Line Type"), wxDefaultPosition, wxDefaultSize, m_TranslineSelectionNChoices, m_TranslineSelectionChoices, 1, wxRA_SPECIFY_COLS ); - m_TranslineSelection->SetSelection( 1 ); - bLeftSizer->Add( m_TranslineSelection, 0, wxTOP|wxRIGHT|wxLEFT|wxEXPAND, 5 ); + wxString m_TranslineSelectionChoices[] = { _( "Microstrip Line" ), + _( "Coupled Microstrip Line" ), + _( "Stripline" ), + _( "Coupled Stripline" ), + _( "Coplanar wave guide" ), + _( "Coplanar wave guide w/ ground plane" ), + _( "Rectangular Waveguide" ), + _( "Coaxial Line" ), + _( "Twisted Pair" ) }; + int m_TranslineSelectionNChoices = sizeof( m_TranslineSelectionChoices ) / sizeof( wxString ); + m_TranslineSelection = new wxRadioBox( this, wxID_ANY, _("Transmission Line Type"), wxDefaultPosition, wxDefaultSize, m_TranslineSelectionNChoices, m_TranslineSelectionChoices, 1, wxRA_SPECIFY_COLS ); + m_TranslineSelection->SetSelection( 0 ); + bLeftSizer->Add( m_TranslineSelection, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, 5 ); - bLeftSizer->Add( 0, 5, 0, wxEXPAND, 5 ); + bLeftSizer->Add( 0, 5, 0, wxEXPAND, 5 ); m_translineBitmap = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); bLeftSizer->Add( m_translineBitmap, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxBOTTOM, 10 ); diff --git a/pcb_calculator/calculator_panels/panel_transline_base.fbp b/pcb_calculator/calculator_panels/panel_transline_base.fbp index c0f1f08662..9d7b3bfd2e 100644 --- a/pcb_calculator/calculator_panels/panel_transline_base.fbp +++ b/pcb_calculator/calculator_panels/panel_transline_base.fbp @@ -87,7 +87,7 @@ 1 0 - "Microstrip Line" "Coplanar wave guide" "Coplanar wave guide w/ ground plane" "Rectangular Waveguide" "Coaxial Line" "Coupled Microstrip Line" "Stripline" "Twisted Pair" + "Microstrip Line" "Coupled Microstrip Line" "Stripline" "Coupled Stripline" "Coplanar wave guide" "Coplanar wave guide w/ ground plane" "Rectangular Waveguide" "Coaxial Line" "Twisted Pair" 1 1 @@ -120,7 +120,7 @@ 1 Resizable - 1 + 0 1 wxRA_SPECIFY_COLS diff --git a/pcb_calculator/transline/c_microstrip.cpp b/pcb_calculator/transline/c_microstrip.cpp index d91d094fe2..7a357326be 100644 --- a/pcb_calculator/transline/c_microstrip.cpp +++ b/pcb_calculator/transline/c_microstrip.cpp @@ -1,8 +1,7 @@ /* - * c_microstrip.cpp - coupled microstrip class implementation - * * Copyright (C) 2002 Claudio Girardi * Copyright (C) 2005, 2006 Stefan Jahn + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,955 +17,113 @@ * along with this package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. - * */ -/* c_microstrip.c - Puts up window for coupled microstrips and - * performs the associated calculations - * Based on the original microstrip.c by Gopal Narayanan - */ - -#include -#include -#include -#include #include "c_microstrip.h" -#include "microstrip.h" #include "transline.h" #include "units.h" -C_MICROSTRIP::C_MICROSTRIP() : TRANSLINE(), - h( 0.0 ), // height of substrate - ht( 0.0 ), // height to the top of box - t( 0.0 ), // thickness of top metal - rough( 0.0 ), // Roughness of top metal - w( 0.0 ), // width of lines - w_t_e( 0.0 ), // even-mode thickness-corrected line width - w_t_o( 0.0 ), // odd-mode thickness-corrected line width - l( 0.0 ), // length of lines - s( 0.0 ), // spacing of lines - Z0_e_0( 0.0 ), // static even-mode impedance - Z0_o_0( 0.0 ), // static odd-mode impedance - Zdiff( 0.0), // differential impedance - Z0e( 0.0 ), // even-mode impedance - Z0o( 0.0 ), // odd-mode impedance - c_e( 0.0 ), // even-mode capacitance - c_o( 0.0 ), // odd-mode capacitance - ang_l_e( 0.0 ), // even-mode electrical length in angle - ang_l_o( 0.0 ), // odd-mode electrical length in angle - er_eff_e( 0.0 ), // even-mode effective dielectric constant - er_eff_o( 0.0 ), // odd-mode effective dielectric constant - er_eff_e_0( 0.0 ), // static even-mode effective dielectric constant - er_eff_o_0( 0.0 ), // static odd-mode effective dielectric constant - w_eff( 0.0 ), // Effective width of line - atten_dielectric_e( 0.0 ), // even-mode dielectric losses (dB) - atten_cond_e( 0.0 ), // even-mode conductors losses (dB) - atten_dielectric_o( 0.0 ), // odd-mode dielectric losses (dB) - atten_cond_o( 0.0 ), // odd-mode conductors losses (dB) - aux_ms( nullptr ) + +C_MICROSTRIP::C_MICROSTRIP() { m_Name = "Coupled_MicroStrip"; Init(); } -C_MICROSTRIP::~C_MICROSTRIP() -{ - delete aux_ms; -} - - -/* - * delta_u_thickness_single() computes the thickness effect on - * normalized width for a single microstrip line - * - * References: H. A. Atwater, "Simplified Design Equations for - * Microstrip Line Parameters", Microwave Journal, pp. 109-115, - * November 1989. - */ -double C_MICROSTRIP::delta_u_thickness_single( double u, double t_h ) -{ - double delta_u; - - if( t_h > 0.0 ) - { - delta_u = - (1.25 * t_h / - M_PI) * - ( 1.0 + - log( ( 2.0 + - (4.0 * M_PI * u - - 2.0) / ( 1.0 + exp( -100.0 * ( u - 1.0 / (2.0 * M_PI) ) ) ) ) / t_h ) ); - - } - else - { - delta_u = 0.0; - } - return delta_u; -} - - -/* - * delta_u_thickness() - compute the thickness effect on normalized - * width for coupled microstrips - * - * References: Rolf Jansen, "High-Speed Computation of Single and - * Coupled Microstrip Parameters Including Dispersion, High-Order - * Modes, Loss and Finite Strip Thickness", IEEE Trans. MTT, vol. 26, - * no. 2, pp. 75-82, Feb. 1978 - */ -void C_MICROSTRIP::delta_u_thickness() -{ - double e_r, u, g, t_h; - double delta_u, delta_t, delta_u_e, delta_u_o; - - e_r = m_parameters[EPSILONR_PRM]; - u = m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM]; /* normalized line width */ - g = m_parameters[PHYS_S_PRM] / m_parameters[H_PRM]; /* normalized line spacing */ - t_h = m_parameters[T_PRM] / m_parameters[H_PRM]; /* normalized strip thickness */ - - if( t_h > 0.0 ) - { - /* single microstrip correction for finite strip thickness */ - delta_u = delta_u_thickness_single( u, t_h ); - delta_t = t_h / ( g * e_r ); - /* thickness correction for the even- and odd-mode */ - delta_u_e = delta_u * ( 1.0 - 0.5 * exp( -0.69 * delta_u / delta_t ) ); - delta_u_o = delta_u_e + delta_t; - } - else - { - delta_u_e = delta_u_o = 0.0; - } - - w_t_e = m_parameters[PHYS_WIDTH_PRM] + delta_u_e * m_parameters[H_PRM]; - w_t_o = m_parameters[PHYS_WIDTH_PRM] + delta_u_o * m_parameters[H_PRM]; -} - - -/* - * compute various parameters for a single line - */ -void C_MICROSTRIP::compute_single_line() -{ - if( aux_ms == NULL ) - aux_ms = new MICROSTRIP(); - - /* prepare parameters for single microstrip computations */ - aux_ms->m_parameters[EPSILONR_PRM] = m_parameters[EPSILONR_PRM]; - aux_ms->m_parameters[PHYS_WIDTH_PRM] = m_parameters[PHYS_WIDTH_PRM]; - aux_ms->m_parameters[H_PRM] = m_parameters[H_PRM]; - aux_ms->m_parameters[T_PRM] = 0.0; - - //aux_ms->m_parameters[H_T_PRM] = m_parameters[H_T_PRM]; - aux_ms->m_parameters[H_T_PRM] = 1e12; /* arbitrarily high */ - aux_ms->m_parameters[FREQUENCY_PRM] = m_parameters[FREQUENCY_PRM]; - aux_ms->m_parameters[MURC_PRM] = m_parameters[MURC_PRM]; - aux_ms->microstrip_Z0(); - aux_ms->dispersion(); -} - - -/* - * filling_factor_even() - compute the filling factor for the coupled - * microstrips even-mode without cover and zero conductor thickness - */ -double C_MICROSTRIP::filling_factor_even( double u, double g, double e_r ) -{ - double v, v3, v4, a_e, b_e, q_inf; - - v = u * ( 20.0 + g * g ) / ( 10.0 + g * g ) + g * exp( -g ); - v3 = v * v * v; - v4 = v3 * v; - a_e = 1.0 + log( ( v4 + v * v / 2704.0 ) / ( v4 + 0.432 ) ) / 49.0 - + log( 1.0 + v3 / 5929.741 ) / 18.7; - b_e = 0.564 * pow( ( ( e_r - 0.9 ) / ( e_r + 3.0 ) ), 0.053 ); - - /* filling factor, with width corrected for thickness */ - q_inf = pow( ( 1.0 + 10.0 / v ), -a_e * b_e ); - - return q_inf; -} - - -/** - * filling_factor_odd() - compute the filling factor for the coupled - * microstrips odd-mode without cover and zero conductor thickness - */ -double C_MICROSTRIP::filling_factor_odd( double u, double g, double e_r ) -{ - double b_odd = 0.747 * e_r / ( 0.15 + e_r ); - double c_odd = b_odd - ( b_odd - 0.207 ) * exp( -0.414 * u ); - double d_odd = 0.593 + 0.694 * exp( -0.562 * u ); - - /* filling factor, with width corrected for thickness */ - double q_inf = exp( -c_odd * pow( g, d_odd ) ); - - return q_inf; -} - - -/* - * delta_q_cover_even() - compute the cover effect on filling factor - * for the even-mode - */ -double C_MICROSTRIP::delta_q_cover_even( double h2h ) -{ - double q_c; - - if( h2h <= 39 ) - q_c = tanh( 1.626 + 0.107 * h2h - 1.733 / sqrt( h2h ) ); - else - q_c = 1.0; - - return q_c; -} - - -/* - * delta_q_cover_odd() - compute the cover effect on filling factor - * for the odd-mode - */ -double C_MICROSTRIP::delta_q_cover_odd( double h2h ) -{ - double q_c; - - if( h2h <= 7 ) - q_c = tanh( 9.575 / ( 7.0 - h2h ) - 2.965 + 1.68 * h2h - 0.311 * h2h * h2h ); - else - q_c = 1.0; - - return q_c; -} - - -/** - * er_eff_static() - compute the static effective dielectric constants - * - * References: Manfred Kirschning and Rolf Jansen, "Accurate - * Wide-Range Design Equations for the Frequency-Dependent - * Characteristic of Parallel Coupled Microstrip Lines", IEEE - * Trans. MTT, vol. 32, no. 1, Jan. 1984 - */ -void C_MICROSTRIP::er_eff_static() -{ - double u_t_e, u_t_o, g, h2, h2h; - double a_o, t_h, q, q_c, q_t, q_inf; - double er_eff_single; - double er; - - er = m_parameters[EPSILONR_PRM]; - - /* compute zero-thickness single line parameters */ - compute_single_line(); - er_eff_single = aux_ms->er_eff_0; - - h2 = m_parameters[H_T_PRM]; - u_t_e = w_t_e / m_parameters[H_PRM]; /* normalized even_mode line width */ - u_t_o = w_t_o / m_parameters[H_PRM]; /* normalized odd_mode line width */ - g = m_parameters[PHYS_S_PRM] / m_parameters[H_PRM]; /* normalized line spacing */ - h2h = h2 / m_parameters[H_PRM]; /* normalized cover height */ - t_h = m_parameters[T_PRM] / m_parameters[H_PRM]; /* normalized strip thickness */ - - /* filling factor, computed with thickness corrected width */ - q_inf = filling_factor_even( u_t_e, g, er ); - /* cover effect */ - q_c = delta_q_cover_even( h2h ); - /* thickness effect */ - q_t = aux_ms->delta_q_thickness( u_t_e, t_h ); - /* resultant filling factor */ - q = ( q_inf - q_t ) * q_c; - /* static even-mode effective dielectric constant */ - er_eff_e_0 = 0.5 * ( er + 1.0 ) + 0.5 * ( er - 1.0 ) * q; - - /* filling factor, with width corrected for thickness */ - q_inf = filling_factor_odd( u_t_o, g, er ); - /* cover effect */ - q_c = delta_q_cover_odd( h2h ); - /* thickness effect */ - q_t = aux_ms->delta_q_thickness( u_t_o, t_h ); - /* resultant filling factor */ - q = ( q_inf - q_t ) * q_c; - - a_o = 0.7287 * ( er_eff_single - 0.5 * ( er + 1.0 ) ) * ( 1.0 - exp( -0.179 * u_t_o ) ); - - /* static odd-mode effective dielectric constant */ - er_eff_o_0 = ( 0.5 * ( er + 1.0 ) + a_o - er_eff_single ) * q + er_eff_single; -} - - -/** - * delta_Z0_even_cover() - compute the even-mode impedance correction - * for a homogeneous microstrip due to the cover - * - * References: S. March, "Microstrip Packaging: Watch the Last Step", - * Microwaves, vol. 20, no. 13, pp. 83.94, Dec. 1981. - */ -double C_MICROSTRIP::delta_Z0_even_cover( double g, double u, double h2h ) -{ - double f_e, g_e, delta_Z0_even; - double x, y, A, B, C, D, E, F; - - A = -4.351 / pow( 1.0 + h2h, 1.842 ); - B = 6.639 / pow( 1.0 + h2h, 1.861 ); - C = -2.291 / pow( 1.0 + h2h, 1.90 ); - f_e = 1.0 - atanh( A + ( B + C * u ) * u ); - - x = pow( 10.0, 0.103 * g - 0.159 ); - y = pow( 10.0, 0.0492 * g - 0.073 ); - D = 0.747 / sin( 0.5 * M_PI * x ); - E = 0.725 * sin( 0.5 * M_PI * y ); - F = pow( 10.0, 0.11 - 0.0947 * g ); - g_e = 270.0 * ( 1.0 - tanh( D + E * sqrt( 1.0 + h2h ) - F / ( 1.0 + h2h ) ) ); - - delta_Z0_even = f_e * g_e; - - return delta_Z0_even; -} - - -/** - * delta_Z0_odd_cover() - compute the odd-mode impedance correction - * for a homogeneous microstrip due to the cover - * - * References: S. March, "Microstrip Packaging: Watch the Last Step", - * Microwaves, vol. 20, no. 13, pp. 83.94, Dec. 1981. - */ -double C_MICROSTRIP::delta_Z0_odd_cover( double g, double u, double h2h ) -{ - double f_o, g_o, delta_Z0_odd; - double G, J, K, L; - - J = tanh( pow( 1.0 + h2h, 1.585 ) / 6.0 ); - f_o = pow( u, J ); - - G = 2.178 - 0.796 * g; - - if( g > 0.858 ) - K = log10( 20.492 * pow( g, 0.174 ) ); - else - K = 1.30; - - if( g > 0.873 ) - L = 2.51 * pow( g, -0.462 ); - else - L = 2.674; - - g_o = 270.0 * ( 1.0 - tanh( G + K * sqrt( 1.0 + h2h ) - L / ( 1.0 + h2h ) ) ); - - delta_Z0_odd = f_o * g_o; - - return delta_Z0_odd; -} - - -/** - * Z0_even_odd() - compute the static even- and odd-mode static - * impedances - * - * References: Manfred Kirschning and Rolf Jansen, "Accurate - * Wide-Range Design Equations for the Frequency-Dependent - * Characteristic of Parallel Coupled Microstrip Lines", IEEE - * Trans. MTT, vol. 32, no. 1, Jan. 1984 - */ -void C_MICROSTRIP::Z0_even_odd() -{ - double er_eff, h2, u_t_e, u_t_o, g, h2h; - double Q_1, Q_2, Q_3, Q_4, Q_5, Q_6, Q_7, Q_8, Q_9, Q_10; - double delta_Z0_e_0, delta_Z0_o_0, Z0_single, er_eff_single; - - h2 = m_parameters[H_T_PRM]; - u_t_e = w_t_e / m_parameters[H_PRM]; /* normalized even-mode line width */ - u_t_o = w_t_o / m_parameters[H_PRM]; /* normalized odd-mode line width */ - g = m_parameters[PHYS_S_PRM] / m_parameters[H_PRM]; /* normalized line spacing */ - h2h = h2 / m_parameters[H_PRM]; /* normalized cover height */ - - Z0_single = aux_ms->Z0_0; - er_eff_single = aux_ms->er_eff_0; - - /* even-mode */ - er_eff = er_eff_e_0; - Q_1 = 0.8695 * pow( u_t_e, 0.194 ); - Q_2 = 1.0 + 0.7519 * g + 0.189 * pow( g, 2.31 ); - Q_3 = 0.1975 + pow( ( 16.6 + pow( ( 8.4 / g ), 6.0 ) ), -0.387 ) - + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 3.4, 10.0 ) ) ) / 241.0; - 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 ) ) ); - /* static even-mode impedance */ - Z0_e_0 = Z0_single * sqrt( er_eff_single / er_eff ) - / ( 1.0 - sqrt( er_eff_single ) * Q_4 * Z0_single / ZF0 ); - /* correction for cover */ - delta_Z0_e_0 = delta_Z0_even_cover( g, u_t_e, h2h ) / sqrt( er_eff ); - - Z0_e_0 = Z0_e_0 - delta_Z0_e_0; - - /* odd-mode */ - er_eff = er_eff_o_0; - Q_5 = 1.794 + 1.14 * log( 1.0 + 0.638 / ( g + 0.517 * pow( g, 2.43 ) ) ); - Q_6 = 0.2305 + log( pow( g, 10.0 ) / ( 1.0 + pow( g / 5.8, 10.0 ) ) ) / 281.3 - + log( 1.0 + 0.598 * pow( g, 1.154 ) ) / 5.1; - Q_7 = ( 10.0 + 190.0 * g * g ) / ( 1.0 + 82.3 * g * g * g ); - Q_8 = exp( -6.5 - 0.95 * log( g ) - pow( g / 0.15, 5.0 ) ); - Q_9 = log( Q_7 ) * ( Q_8 + 1.0 / 16.5 ); - Q_10 = ( Q_2 * Q_4 - Q_5 * exp( log( u_t_o ) * Q_6 * pow( u_t_o, -Q_9 ) ) ) / Q_2; - - /* static odd-mode impedance */ - Z0_o_0 = Z0_single * sqrt( er_eff_single / er_eff ) - / ( 1.0 - sqrt( er_eff_single ) * Q_10 * Z0_single / ZF0 ); - /* correction for cover */ - delta_Z0_o_0 = delta_Z0_odd_cover( g, u_t_o, h2h ) / sqrt( er_eff ); - - Z0_o_0 = Z0_o_0 - delta_Z0_o_0; -} - - -/* - * er_eff_freq() - compute er_eff as a function of frequency - */ -void C_MICROSTRIP::er_eff_freq() -{ - double P_1, P_2, P_3, P_4, P_5, P_6, P_7; - double P_8, P_9, P_10, P_11, P_12, P_13, P_14, P_15; - double F_e, F_o; - double er_eff, u, g, f_n; - - u = m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM]; /* normalize line width */ - g = m_parameters[PHYS_S_PRM] / m_parameters[H_PRM]; /* normalize line spacing */ - - /* normalized frequency [GHz * mm] */ - f_n = m_parameters[FREQUENCY_PRM] * m_parameters[H_PRM] / 1e06; - - er_eff = er_eff_e_0; - P_1 = 0.27488 + ( 0.6315 + 0.525 / pow( 1.0 + 0.0157 * f_n, 20.0 ) ) * u - - 0.065683 * exp( -8.7513 * u ); - P_2 = 0.33622 * ( 1.0 - exp( -0.03442 * m_parameters[EPSILONR_PRM] ) ); - P_3 = 0.0363 * exp( -4.6 * u ) * ( 1.0 - exp( -pow( f_n / 38.7, 4.97 ) ) ); - P_4 = 1.0 + 2.751 * ( 1.0 - exp( -pow( m_parameters[EPSILONR_PRM] / 15.916, 8.0 ) ) ); - P_5 = 0.334 * exp( -3.3 * pow( m_parameters[EPSILONR_PRM] / 15.0, 3.0 ) ) + 0.746; - P_6 = P_5 * exp( -pow( f_n / 18.0, 0.368 ) ); - 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 ) ); - - F_e = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 * P_7 ) * f_n, 1.5763 ); - /* even-mode effective dielectric constant */ - er_eff_e = m_parameters[EPSILONR_PRM] - ( m_parameters[EPSILONR_PRM] - er_eff ) / ( 1.0 + F_e ); - prop_delay_e = calcUnitPropagationDelay( er_eff_e ); - - er_eff = er_eff_o_0; - P_8 = 0.7168 * ( 1.0 + 1.076 / ( 1.0 + 0.0576 * ( m_parameters[EPSILONR_PRM] - 1.0 ) ) ); - P_9 = P_8 - - 0.7913 * ( 1.0 - exp( -pow( f_n / 20.0, 1.424 ) ) ) - * atan( 2.481 * pow( m_parameters[EPSILONR_PRM] / 8.0, 0.946 ) ); - P_10 = 0.242 * pow( m_parameters[EPSILONR_PRM] - 1.0, 0.55 ); - P_11 = 0.6366 * ( exp( -0.3401 * f_n ) - 1.0 ) * atan( 1.263 * pow( u / 3.0, 1.629 ) ); - P_12 = P_9 + ( 1.0 - P_9 ) / ( 1.0 + 1.183 * pow( u, 1.376 ) ); - P_13 = 1.695 * P_10 / ( 0.414 + 1.605 * P_10 ); - P_14 = 0.8928 + 0.1072 * ( 1.0 - exp( -0.42 * pow( f_n / 20.0, 3.215 ) ) ); - P_15 = fabs( 1.0 - 0.8928 * ( 1.0 + P_11 ) * P_12 * exp( -P_13 * pow( g, 1.092 ) ) / P_14 ); - - F_o = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 ) * f_n * P_15, 1.5763 ); - /* odd-mode effective dielectric constant */ - er_eff_o = m_parameters[EPSILONR_PRM] - ( m_parameters[EPSILONR_PRM] - er_eff ) / ( 1.0 + F_o ); - prop_delay_o = calcUnitPropagationDelay( er_eff_o ); -} - - -/* - * conductor_losses() - compute microstrips conductor losses per unit - * length - */ -void C_MICROSTRIP::conductor_losses() -{ - double e_r_eff_e_0, e_r_eff_o_0, Z0_h_e, Z0_h_o, delta; - double K, R_s, Q_c_e, Q_c_o, alpha_c_e, alpha_c_o; - - e_r_eff_e_0 = er_eff_e_0; - e_r_eff_o_0 = er_eff_o_0; - Z0_h_e = Z0_e_0 * sqrt( e_r_eff_e_0 ); /* homogeneous stripline impedance */ - Z0_h_o = Z0_o_0 * sqrt( e_r_eff_o_0 ); /* homogeneous stripline impedance */ - delta = m_parameters[SKIN_DEPTH_PRM]; - - if( m_parameters[FREQUENCY_PRM] > 0.0 ) - { - /* current distribution factor (same for the two modes) */ - K = exp( -1.2 * pow( ( Z0_h_e + Z0_h_o ) / ( 2.0 * ZF0 ), 0.7 ) ); - /* skin resistance */ - R_s = 1.0 / ( m_parameters[SIGMA_PRM] * delta ); - /* correction for surface roughness */ - R_s *= 1.0 - + ( ( 2.0 / M_PI ) - * atan( 1.40 * pow( ( m_parameters[ROUGH_PRM] / delta ), 2.0 ) ) ); - - /* even-mode strip inductive quality factor */ - Q_c_e = ( M_PI * Z0_h_e * m_parameters[PHYS_WIDTH_PRM] * m_parameters[FREQUENCY_PRM] ) - / ( R_s * C0 * K ); - /* even-mode losses per unit length */ - alpha_c_e = ( 20.0 * M_PI / log( 10.0 ) ) * m_parameters[FREQUENCY_PRM] - * sqrt( e_r_eff_e_0 ) / ( C0 * Q_c_e ); - - /* odd-mode strip inductive quality factor */ - Q_c_o = ( M_PI * Z0_h_o * m_parameters[PHYS_WIDTH_PRM] * m_parameters[FREQUENCY_PRM] ) - / ( R_s * C0 * K ); - /* odd-mode losses per unit length */ - alpha_c_o = ( 20.0 * M_PI / log( 10.0 ) ) * m_parameters[FREQUENCY_PRM] - * sqrt( e_r_eff_o_0 ) / ( C0 * Q_c_o ); - } - else - { - alpha_c_e = alpha_c_o = 0.0; - } - - atten_cond_e = alpha_c_e * m_parameters[PHYS_LEN_PRM]; - atten_cond_o = alpha_c_o * m_parameters[PHYS_LEN_PRM]; -} - - -/* - * dielectric_losses() - compute microstrips dielectric losses per - * unit length - */ -void C_MICROSTRIP::dielectric_losses() -{ - double e_r, e_r_eff_e_0, e_r_eff_o_0; - double alpha_d_e, alpha_d_o; - - e_r = m_parameters[EPSILONR_PRM]; - e_r_eff_e_0 = er_eff_e_0; - e_r_eff_o_0 = er_eff_o_0; - - alpha_d_e = ( 20.0 * M_PI / log( 10.0 ) ) * ( m_parameters[FREQUENCY_PRM] / C0 ) - * ( e_r / sqrt( e_r_eff_e_0 ) ) * ( ( e_r_eff_e_0 - 1.0 ) / ( e_r - 1.0 ) ) - * m_parameters[TAND_PRM]; - alpha_d_o = ( 20.0 * M_PI / log( 10.0 ) ) * ( m_parameters[FREQUENCY_PRM] / C0 ) - * ( e_r / sqrt( e_r_eff_o_0 ) ) * ( ( e_r_eff_o_0 - 1.0 ) / ( e_r - 1.0 ) ) - * m_parameters[TAND_PRM]; - - atten_dielectric_e = alpha_d_e * m_parameters[PHYS_LEN_PRM]; - atten_dielectric_o = alpha_d_o * m_parameters[PHYS_LEN_PRM]; -} - - -/* - * c_microstrip_attenuation() - compute attenuation of coupled - * microstrips - */ -void C_MICROSTRIP::attenuation() -{ - m_parameters[SKIN_DEPTH_PRM] = skin_depth(); - conductor_losses(); - dielectric_losses(); -} - - -/* - * line_angle() - calculate strips electrical lengths in radians - */ -void C_MICROSTRIP::line_angle() -{ - double e_r_eff_e, e_r_eff_o; - double v_e, v_o, lambda_g_e, lambda_g_o; - - e_r_eff_e = er_eff_e; - e_r_eff_o = er_eff_o; - - /* even-mode velocity */ - v_e = C0 / sqrt( e_r_eff_e ); - /* odd-mode velocity */ - v_o = C0 / sqrt( e_r_eff_o ); - /* even-mode wavelength */ - lambda_g_e = v_e / m_parameters[FREQUENCY_PRM]; - /* odd-mode wavelength */ - lambda_g_o = v_o / m_parameters[FREQUENCY_PRM]; - /* electrical angles */ - ang_l_e = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] / lambda_g_e; /* in radians */ - ang_l_o = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] / lambda_g_o; /* in radians */ -} - - -/** - * Note that differential impedance is exactly twice the odd mode impedance. - * Odd mode is not the same as single-ended impedance, so avoid approximations found - * on websites that use static single ended impedance as the starting point - */ -void C_MICROSTRIP::diff_impedance() -{ - Zdiff = 2 * Z0_o_0; -} - - -void C_MICROSTRIP::syn_err_fun( double* f1, double* f2, double s_h, double w_h, double e_r, - double w_h_se, double w_h_so ) -{ - double g, he; - - g = cosh( 0.5 * M_PI * s_h ); - he = cosh( M_PI * w_h + 0.5 * M_PI * s_h ); - - *f1 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g + 1.0 ) / ( g + 1.0 ) ); - *f2 = ( 2.0 / M_PI ) * acosh( ( 2.0 * he - g - 1.0 ) / ( g - 1.0 ) ); - - if( e_r <= 6.0 ) - *f2 += ( 4.0 / ( M_PI * ( 1.0 + e_r / 2.0 ) ) ) * acosh( 1.0 + 2.0 * w_h / s_h ); - else - *f2 += ( 1.0 / M_PI ) * acosh( 1.0 + 2.0 * w_h / s_h ); - - *f1 -= w_h_se; - *f2 -= w_h_so; -} - - -/* - * synth_width - calculate widths given Z0 and e_r - * from Akhtarzad S. et al., "The design of coupled microstrip lines", - * IEEE Trans. MTT-23, June 1975 and - * Hinton, J.H., "On design of coupled microstrip lines", IEEE Trans. - * MTT-28, March 1980 - */ -void C_MICROSTRIP::synth_width() -{ - double Z0, e_r; - double w_h_se, w_h_so, w_h, a, ce, co, s_h; - double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err; - double eps = 1e-04; - - f1 = f2 = 0; - e_r = m_parameters[EPSILONR_PRM]; - - Z0 = m_parameters[Z0_E_PRM] / 2.0; - /* Wheeler formula for single microstrip synthesis */ - a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0; - w_h_se = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a; - - Z0 = m_parameters[Z0_O_PRM] / 2.0; - /* Wheeler formula for single microstrip synthesis */ - a = exp( Z0 * sqrt( e_r + 1.0 ) / 42.4 ) - 1.0; - w_h_so = 8.0 * sqrt( a * ( ( 7.0 + 4.0 / e_r ) / 11.0 ) + ( ( 1.0 + 1.0 / e_r ) / 0.81 ) ) / a; - - ce = cosh( 0.5 * M_PI * w_h_se ); - co = cosh( 0.5 * M_PI * w_h_so ); - /* first guess at m_parameters[PHYS_S_PRM]/h */ - s_h = ( 2.0 / M_PI ) * acosh( ( ce + co - 2.0 ) / ( co - ce ) ); - /* first guess at w/h */ - w_h = acosh( ( ce * co - 1.0 ) / ( co - ce ) ) / M_PI - s_h / 2.0; - - m_parameters[PHYS_S_PRM] = s_h * m_parameters[H_PRM]; - m_parameters[PHYS_WIDTH_PRM] = w_h * m_parameters[H_PRM]; - - syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so ); - - /* rather crude Newton-Rhapson; we need this because the estimate of */ - /* w_h is often quite far from the true value (see Akhtarzad S. et al.) */ - do - { - /* compute Jacobian */ - syn_err_fun( &ft1, &ft2, s_h + eps, w_h, e_r, w_h_se, w_h_so ); - j11 = ( ft1 - f1 ) / eps; - j21 = ( ft2 - f2 ) / eps; - syn_err_fun( &ft1, &ft2, s_h, w_h + eps, e_r, w_h_se, w_h_so ); - j12 = ( ft1 - f1 ) / eps; - j22 = ( ft2 - f2 ) / eps; - - /* compute next step */ - d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 ); - d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 ); - - //g_print("j11 = %e\tj12 = %e\tj21 = %e\tj22 = %e\n", j11, j12, j21, j22); - //g_print("det = %e\n", j11*j22 - j21*j22); - //g_print("d_s_h = %e\td_w_h = %e\n", d_s_h, d_w_h); - - s_h += d_s_h; - w_h += d_w_h; - - /* check the error */ - syn_err_fun( &f1, &f2, s_h, w_h, e_r, w_h_se, w_h_so ); - - err = sqrt( f1 * f1 + f2 * f2 ); - /* converged ? */ - } while( err > 1e-04 ); - - - m_parameters[PHYS_S_PRM] = s_h * m_parameters[H_PRM]; - m_parameters[PHYS_WIDTH_PRM] = w_h * m_parameters[H_PRM]; -} - - -/* - * Z0_dispersion() - calculate frequency dependency of characteristic - * impedances - */ -void C_MICROSTRIP::Z0_dispersion() -{ - double Q_0; - double Q_11, Q_12, Q_13, Q_14, Q_15, Q_16, Q_17, Q_18, Q_19, Q_20, Q_21; - double Q_22, Q_23, Q_24, Q_25, Q_26, Q_27, Q_28, Q_29; - double r_e, q_e, p_e, d_e, C_e; - double e_r_eff_o_f, e_r_eff_o_0; - double e_r_eff_single_f, e_r_eff_single_0, Z0_single_f; - double f_n, g, u, e_r; - double R_1, R_2, R_7, R_10, R_11, R_12, R_15, R_16, tmpf; - - e_r = m_parameters[EPSILONR_PRM]; - - u = m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM]; /* normalize line width */ - g = m_parameters[PHYS_S_PRM] / m_parameters[H_PRM]; /* normalize line spacing */ - - /* normalized frequency [GHz * mm] */ - f_n = m_parameters[FREQUENCY_PRM] * m_parameters[H_PRM] / 1e06; - - e_r_eff_single_f = aux_ms->m_parameters[EPSILON_EFF_PRM]; - e_r_eff_single_0 = aux_ms->er_eff_0; - Z0_single_f = aux_ms->m_parameters[Z0_PRM]; - - e_r_eff_o_f = er_eff_o; - e_r_eff_o_0 = er_eff_o_0; - - Q_11 = 0.893 * ( 1.0 - 0.3 / ( 1.0 + 0.7 * ( e_r - 1.0 ) ) ); - 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 ) * pow( g, 0.902 ); - Q_13 = 1.0 + 0.038 * pow( e_r / 8.0, 5.1 ); - Q_14 = 1.0 + 1.203 * pow( e_r / 15.0, 4.0 ) / ( 1.0 + pow( e_r / 15.0, 4.0 ) ); - Q_15 = 1.887 * exp( -1.5 * pow( g, 0.84 ) ) * pow( g, Q_14 ) - / ( 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 ) ) ); - Q_16 = ( 1.0 + 9.0 / ( 1.0 + 0.403 * pow( e_r - 1.0, 2 ) ) ) * Q_15; - 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 ) ) ); - Q_18 = 0.61 * ( 1.0 - exp( -2.13 * pow( u / 8.0, 1.593 ) ) ) / ( 1.0 + 6.544 * pow( g, 4.17 ) ); - Q_19 = 0.21 * g * g * g * g - / ( ( 1.0 + 0.18 * pow( g, 4.9 ) ) * ( 1.0 + 0.1 * u * u ) - * ( 1.0 + pow( f_n / 24.0, 3.0 ) ) ); - Q_20 = ( 0.09 + 1.0 / ( 1.0 + 0.1 * pow( e_r - 1, 2.7 ) ) ) * Q_19; - 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 ) ) ); - - r_e = pow( f_n / 28.843, 12 ); - q_e = 0.016 + pow( 0.0514 * e_r * Q_21, 4.524 ); - p_e = 4.766 * exp( -3.228 * pow( u, 0.641 ) ); - 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 ) ) - * ( pow( e_r - 1.0, 6.0 ) / ( 1.0 + 10 * pow( e_r - 1.0, 6.0 ) ) ); - 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 - Q_17 + Q_18 + Q_20; - - - R_1 = 0.03891 * pow( e_r, 1.4 ); - R_2 = 0.267 * pow( u, 7.0 ); - R_7 = 1.206 - 0.3144 * exp( -R_1 ) * ( 1.0 - exp( -R_2 ) ); - R_10 = 0.00044 * pow( e_r, 2.136 ) + 0.0184; - tmpf = pow( f_n / 19.47, 6.0 ); - R_11 = tmpf / ( 1.0 + 0.0962 * tmpf ); - R_12 = 1.0 / ( 1.0 + 0.00245 * u * u ); - R_15 = 0.707 * R_10 * pow( f_n / 12.3, 1.097 ); - R_16 = 1.0 + 0.0503 * e_r * e_r * R_11 * ( 1.0 - exp( -pow( u / 15.0, 6.0 ) ) ); - Q_0 = R_7 * ( 1.0 - 1.1241 * ( R_12 / R_16 ) * exp( -0.026 * pow( f_n, 1.15656 ) - R_15 ) ); - - /* even-mode frequency-dependent characteristic impedances */ - m_parameters[Z0_E_PRM] = Z0_e_0 * pow( 0.9408 * pow( e_r_eff_single_f, C_e ) - 0.9603, Q_0 ) - / pow( ( 0.9408 - d_e ) * pow( e_r_eff_single_0, C_e ) - 0.9603, Q_0 ); - - Q_29 = 15.16 / ( 1.0 + 0.196 * pow( e_r - 1.0, 2.0 ) ); - tmpf = pow( e_r - 1.0, 3.0 ); - Q_28 = 0.149 * tmpf / ( 94.5 + 0.038 * tmpf ); - tmpf = pow( e_r - 1.0, 1.5 ); - Q_27 = 0.4 * pow( g, 0.84 ) * ( 1.0 + 2.5 * tmpf / ( 5.0 + tmpf ) ); - tmpf = pow( ( e_r - 1.0 ) / 13.0, 12.0 ); - Q_26 = 30.0 - 22.2 * ( tmpf / ( 1.0 + 3.0 * tmpf ) ) - Q_29; - tmpf = ( e_r - 1.0 ) * ( e_r - 1.0 ); - Q_25 = ( 0.3 * f_n * f_n / ( 10.0 + f_n * f_n ) ) * ( 1.0 + 2.333 * tmpf / ( 5.0 + tmpf ) ); - 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 ) ); - 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 ) ); - Q_22 = 0.925 * pow( f_n / Q_26, 1.536 ) / ( 1.0 + 0.3 * pow( f_n / 30.0, 1.536 ) ); - - /* odd-mode frequency-dependent characteristic impedances */ - m_parameters[Z0_O_PRM] = - Z0_single_f - + ( Z0_o_0 * pow( e_r_eff_o_f / e_r_eff_o_0, Q_22 ) - Z0_single_f * Q_23 ) - / ( 1.0 + Q_24 + pow( 0.46 * g, 2.2 ) * Q_25 ); -} - - void C_MICROSTRIP::calcAnalyze() { - /* compute thickness corrections */ - delta_u_thickness(); - /* get effective dielectric constants */ - er_eff_static(); - /* impedances for even- and odd-mode */ - Z0_even_odd(); - /* calculate freq dependence of er_eff_e, er_eff_o */ - er_eff_freq(); - /* calculate frequency dependence of Z0e, Z0o */ - Z0_dispersion(); - /* calculate losses */ - attenuation(); - /* calculate electrical lengths */ - line_angle(); - /* calculate diff impedance */ - diff_impedance(); + m_calc.Analyse(); +} + + +void C_MICROSTRIP::calcSynthesize() +{ + m_calc.Synthesize( SYNTHESIZE_OPTS::DEFAULT ); } void C_MICROSTRIP::showAnalyze() { - setProperty( Z0_E_PRM, m_parameters[Z0_E_PRM] ); - setProperty( Z0_O_PRM, m_parameters[Z0_O_PRM] ); - setProperty( ANG_L_PRM, sqrt( ang_l_e * ang_l_o ) ); + std::unordered_map>& results = + m_calc.GetAnalysisResults(); - //Check for errors - if( !std::isfinite( m_parameters[Z0_O_PRM] ) || m_parameters[Z0_O_PRM] <= 0.0 ) - setErrorLevel( Z0_O_PRM, TRANSLINE_ERROR ); + setProperty( Z0_E_PRM, results[TRANSLINE_PARAMETERS::Z0_E].first ); + setProperty( Z0_O_PRM, results[TRANSLINE_PARAMETERS::Z0_O].first ); + setProperty( ANG_L_PRM, results[TRANSLINE_PARAMETERS::ANG_L].first ); - if( !std::isfinite( m_parameters[Z0_E_PRM] ) || m_parameters[Z0_E_PRM] <= 0.0 ) - setErrorLevel( Z0_E_PRM, TRANSLINE_ERROR ); + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF_EVEN].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::EPSILON_EFF_ODD].first, "" ); + setResult( 2, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_EVEN].first, "ps/cm" ); + setResult( 3, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_ODD].first, "ps/cm" ); + setResult( 4, results[TRANSLINE_PARAMETERS::ATTEN_COND_EVEN].first, "dB" ); + setResult( 5, results[TRANSLINE_PARAMETERS::ATTEN_COND_ODD].first, "dB" ); + setResult( 6, results[TRANSLINE_PARAMETERS::ATTEN_DILECTRIC_EVEN].first, "dB" ); + setResult( 7, results[TRANSLINE_PARAMETERS::ATTEN_DILECTRIC_ODD].first, "dB" ); + setResult( 8, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); + setResult( 9, results[TRANSLINE_PARAMETERS::Z_DIFF].first, "Ω" ); - if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] <= 0.0 ) - setErrorLevel( ANG_L_PRM, TRANSLINE_ERROR ); - - // Check for warnings - if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0.0 ) - setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING ); - - if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0.0 ) - setErrorLevel( PHYS_S_PRM, TRANSLINE_WARNING ); - - if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] <= 0.0 ) - setErrorLevel( PHYS_LEN_PRM, TRANSLINE_WARNING ); + setErrorLevel( Z0_E_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_E].second ) ); + setErrorLevel( Z0_O_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_O].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_S_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_S].second ) ); } + void C_MICROSTRIP::showSynthesize() { - setProperty( PHYS_WIDTH_PRM, m_parameters[PHYS_WIDTH_PRM] ); - setProperty( PHYS_S_PRM, m_parameters[PHYS_S_PRM] ); - setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); + std::unordered_map>& results = + m_calc.GetAnalysisResults(); - //Check for errors - if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0.0 ) - setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR ); + setProperty( PHYS_WIDTH_PRM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first ); + setProperty( PHYS_S_PRM, results[TRANSLINE_PARAMETERS::PHYS_S].first ); + setProperty( PHYS_LEN_PRM, results[TRANSLINE_PARAMETERS::PHYS_LEN].first ); - if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0.0 ) - setErrorLevel( PHYS_S_PRM, TRANSLINE_ERROR ); + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF_EVEN].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::EPSILON_EFF_ODD].first, "" ); + setResult( 2, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_EVEN].first, "ps/cm" ); + setResult( 3, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_ODD].first, "ps/cm" ); + setResult( 4, results[TRANSLINE_PARAMETERS::ATTEN_COND_EVEN].first, "dB" ); + setResult( 5, results[TRANSLINE_PARAMETERS::ATTEN_COND_ODD].first, "dB" ); + setResult( 6, results[TRANSLINE_PARAMETERS::ATTEN_DILECTRIC_EVEN].first, "dB" ); + setResult( 7, results[TRANSLINE_PARAMETERS::ATTEN_DILECTRIC_ODD].first, "dB" ); + setResult( 8, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); + setResult( 9, results[TRANSLINE_PARAMETERS::Z_DIFF].first, "Ω" ); - if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] <= 0.0 ) - setErrorLevel( PHYS_LEN_PRM, TRANSLINE_ERROR ); + setErrorLevel( Z0_E_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_E].second ) ); + setErrorLevel( Z0_O_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_O].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_S_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_S].second ) ); +} - // Check for warnings - if( !std::isfinite( m_parameters[Z0_O_PRM] ) || m_parameters[Z0_O_PRM] <= 0.0 ) - setErrorLevel( Z0_O_PRM, TRANSLINE_WARNING ); - if( !std::isfinite( m_parameters[Z0_E_PRM] ) || m_parameters[Z0_E_PRM] <= 0.0 ) - setErrorLevel( Z0_E_PRM, TRANSLINE_WARNING ); +void C_MICROSTRIP::getProperties() +{ + TRANSLINE::getProperties(); - if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] <= 0.0 ) - setErrorLevel( ANG_L_PRM, TRANSLINE_WARNING ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, m_parameters[Z0_E_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, m_parameters[Z0_O_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, m_parameters[EPSILONR_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_WIDTH, m_parameters[PHYS_WIDTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_LEN, m_parameters[PHYS_LEN_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_S, m_parameters[PHYS_S_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::H, m_parameters[H_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::T, m_parameters[T_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::H_T, m_parameters[H_T_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, m_parameters[FREQUENCY_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::MURC, m_parameters[MURC_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, m_parameters[SKIN_DEPTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, m_parameters[SIGMA_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::ROUGH, m_parameters[ROUGH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::TAND, m_parameters[TAND_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, m_parameters[ANG_L_PRM] ); } void C_MICROSTRIP::show_results() { - - setResult( 0, er_eff_e, "" ); - setResult( 1, er_eff_o, "" ); - setResult( 2, prop_delay_e, "ps/cm" ); - setResult( 3, prop_delay_o, "ps/cm" ); - setResult( 4, atten_cond_e, "dB" ); - setResult( 5, atten_cond_o, "dB" ); - setResult( 6, atten_dielectric_e, "dB" ); - setResult( 7, atten_dielectric_o, "dB" ); - - setResult( 8, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); - setResult( 9, Zdiff, "Ω" ); -} - - -void C_MICROSTRIP::syn_fun( - double* f1, double* f2, double s_h, double w_h, double Z0_e, double Z0_o ) -{ - m_parameters[PHYS_S_PRM] = s_h * m_parameters[H_PRM]; - m_parameters[PHYS_WIDTH_PRM] = w_h * m_parameters[H_PRM]; - - /* compute coupled microstrip parameters */ - calcAnalyze(); - - *f1 = m_parameters[Z0_E_PRM] - Z0_e; - *f2 = m_parameters[Z0_O_PRM] - Z0_o; -} - - -/* - * synthesis function - */ -void C_MICROSTRIP::calcSynthesize() -{ - double Z0_e, Z0_o, ang_l_dest; - double f1, f2, ft1, ft2, j11, j12, j21, j22, d_s_h, d_w_h, err; - double eps = 1e-04; - double w_h, s_h, le, lo; - - - /* required value of Z0_e and Z0_o */ - Z0_e = m_parameters[Z0_E_PRM]; - Z0_o = m_parameters[Z0_O_PRM]; - - - ang_l_e = m_parameters[ANG_L_PRM]; - ang_l_o = m_parameters[ANG_L_PRM]; - ang_l_dest = m_parameters[ANG_L_PRM]; - - - /* calculate width and use for initial value in Newton's method */ - synth_width(); - w_h = m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM]; - s_h = m_parameters[PHYS_S_PRM] / m_parameters[H_PRM]; - f1 = f2 = 0; - - /* rather crude Newton-Rhapson */ - do - { - /* compute Jacobian */ - syn_fun( &ft1, &ft2, s_h + eps, w_h, Z0_e, Z0_o ); - j11 = ( ft1 - f1 ) / eps; - j21 = ( ft2 - f2 ) / eps; - syn_fun( &ft1, &ft2, s_h, w_h + eps, Z0_e, Z0_o ); - j12 = ( ft1 - f1 ) / eps; - j22 = ( ft2 - f2 ) / eps; - - /* compute next step; increments of s_h and w_h */ - d_s_h = ( -f1 * j22 + f2 * j12 ) / ( j11 * j22 - j21 * j12 ); - d_w_h = ( -f2 * j11 + f1 * j21 ) / ( j11 * j22 - j21 * j12 ); - - s_h += d_s_h; - w_h += d_w_h; - - /* compute the error with the new values of s_h and w_h */ - syn_fun( &f1, &f2, s_h, w_h, Z0_e, Z0_o ); - err = sqrt( f1 * f1 + f2 * f2 ); - - /* converged ? */ - } while( err > 1e-04 ); - - /* denormalize computed width and spacing */ - m_parameters[PHYS_S_PRM] = s_h * m_parameters[H_PRM]; - m_parameters[PHYS_WIDTH_PRM] = w_h * m_parameters[H_PRM]; - - - /* calculate physical length */ - le = C0 / m_parameters[FREQUENCY_PRM] / sqrt( er_eff_e ) * ang_l_dest / 2.0 / M_PI; - lo = C0 / m_parameters[FREQUENCY_PRM] / sqrt( er_eff_o ) * ang_l_dest / 2.0 / M_PI; - m_parameters[PHYS_LEN_PRM] = sqrt( le * lo ); - - calcAnalyze(); - - m_parameters[ANG_L_PRM] = ang_l_dest; - m_parameters[Z0_E_PRM] = Z0_e; - m_parameters[Z0_O_PRM] = Z0_o; } diff --git a/pcb_calculator/transline/c_microstrip.h b/pcb_calculator/transline/c_microstrip.h index c651204cce..12c6b2795d 100644 --- a/pcb_calculator/transline/c_microstrip.h +++ b/pcb_calculator/transline/c_microstrip.h @@ -4,6 +4,7 @@ * Copyright (C) 2002 Claudio Girardi * Copyright (C) 2005 Stefan Jahn * Modifications for Kicad: 2015 Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,81 +22,28 @@ * Boston, MA 02110-1301, USA. */ - #ifndef _C_MICROSTRIP_H_ #define _C_MICROSTRIP_H_ -#include "transline/microstrip.h" + #include "transline/transline.h" +#include + class C_MICROSTRIP : public TRANSLINE { public: C_MICROSTRIP(); - ~C_MICROSTRIP(); private: - double h; // height of substrate - double ht; // height to the top of box - double t; // thickness of top metal - double rough; // Roughness of top metal - double w; // width of lines - double w_t_e; // even-mode thickness-corrected line width - double w_t_o; // odd-mode thickness-corrected line width - double l; // length of lines - double s; // spacing of lines - double Z0_e_0; // static even-mode impedance - double Z0_o_0; // static odd-mode impedance - double Zdiff; // differential impedance - double Z0e; // even-mode impedance - double Z0o; // odd-mode impedance - double c_e; // even-mode capacitance - double c_o; // odd-mode capacitance - double ang_l_e; // even-mode electrical length in angle - double ang_l_o; // odd-mode electrical length in angle - double er_eff_e; // even-mode effective dielectric constant - double er_eff_o; // odd-mode effective dielectric constant - double prop_delay_e; // even-mode unit propagation delay (ps/cm) - double prop_delay_o; // odd-mode unit propagation delay (ps/cm) - double er_eff_e_0; // static even-mode effective dielectric constant - double er_eff_o_0; // static odd-mode effective dielectric constant - double w_eff; // Effective width of line - double atten_dielectric_e; // even-mode dielectric losses (dB) - double atten_cond_e; // even-mode conductors losses (dB) - double atten_dielectric_o; // odd-mode dielectric losses (dB) - double atten_cond_o; // odd-mode conductors losses (dB) + void calcAnalyze() override; + void calcSynthesize() override; + void showAnalyze() override; + void showSynthesize() override; + void show_results() override; + void getProperties() override; -private: - double delta_u_thickness_single( double, double ); - void delta_u_thickness(); - void compute_single_line(); - double filling_factor_even( double, double, double ); - double filling_factor_odd( double, double, double ); - double delta_q_cover_even( double ); - double delta_q_cover_odd( double ); - void er_eff_static(); - double delta_Z0_even_cover( double, double, double ); - double delta_Z0_odd_cover( double, double, double ); - void Z0_even_odd(); - void er_eff_freq(); - void conductor_losses(); - void dielectric_losses(); - void attenuation(); - void line_angle(); - void diff_impedance(); - void syn_err_fun( double*, double*, double, double, double, double, double ); - void synth_width(); - void Z0_dispersion(); - void calcAnalyze() override; - void calcSynthesize() override; - void showAnalyze() override; - void showSynthesize() override; - void show_results() override; - void syn_fun( double*, double*, double, double, double, double ); - - -private: - MICROSTRIP* aux_ms; + COUPLED_MICROSTRIP m_calc; }; #endif // _C_MICROSTRIP_H_ diff --git a/pcb_calculator/transline/c_stripline.cpp b/pcb_calculator/transline/c_stripline.cpp new file mode 100644 index 0000000000..10517f99d9 --- /dev/null +++ b/pcb_calculator/transline/c_stripline.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2002 Claudio Girardi + * Copyright (C) 2005, 2006 Stefan Jahn + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#include "c_stripline.h" +#include "transline.h" +#include "units.h" + + +C_STRIPLINE::C_STRIPLINE() +{ + m_Name = "Coupled_MicroStrip"; + Init(); +} + + +void C_STRIPLINE::calcAnalyze() +{ + m_calc.Analyse(); +} + + +void C_STRIPLINE::calcSynthesize() +{ + m_calc.Synthesize( SYNTHESIZE_OPTS::DEFAULT ); +} + + +void C_STRIPLINE::showAnalyze() +{ + std::unordered_map>& results = + m_calc.GetAnalysisResults(); + + setProperty( Z0_E_PRM, results[TRANSLINE_PARAMETERS::Z0_E].first ); + setProperty( Z0_O_PRM, results[TRANSLINE_PARAMETERS::Z0_O].first ); + setProperty( ANG_L_PRM, results[TRANSLINE_PARAMETERS::ANG_L].first ); + + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF_EVEN].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::EPSILON_EFF_ODD].first, "" ); + setResult( 2, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_EVEN].first, "ps/cm" ); + setResult( 3, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_ODD].first, "ps/cm" ); + setResult( 4, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); + setResult( 5, results[TRANSLINE_PARAMETERS::Z_DIFF].first, "Ω" ); + + setErrorLevel( Z0_E_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_E].second ) ); + setErrorLevel( Z0_O_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_O].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_S_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_S].second ) ); +} + + +void C_STRIPLINE::showSynthesize() +{ + std::unordered_map>& results = + m_calc.GetAnalysisResults(); + + setProperty( PHYS_WIDTH_PRM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first ); + setProperty( PHYS_S_PRM, results[TRANSLINE_PARAMETERS::PHYS_S].first ); + setProperty( PHYS_LEN_PRM, results[TRANSLINE_PARAMETERS::PHYS_LEN].first ); + + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF_EVEN].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::EPSILON_EFF_ODD].first, "" ); + setResult( 2, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_EVEN].first, "ps/cm" ); + setResult( 3, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY_ODD].first, "ps/cm" ); + setResult( 4, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); + setResult( 5, results[TRANSLINE_PARAMETERS::Z_DIFF].first, "Ω" ); + + setErrorLevel( Z0_E_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_E].second ) ); + setErrorLevel( Z0_O_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0_O].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_S_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_S].second ) ); +} + + +void C_STRIPLINE::getProperties() +{ + TRANSLINE::getProperties(); + + m_calc.SetParameter( TRANSLINE_PARAMETERS::Z0_E, m_parameters[Z0_E_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::Z0_O, m_parameters[Z0_O_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, m_parameters[EPSILONR_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_WIDTH, m_parameters[PHYS_WIDTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_LEN, m_parameters[PHYS_LEN_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_S, m_parameters[PHYS_S_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::H, m_parameters[H_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::T, m_parameters[T_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, m_parameters[FREQUENCY_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::MURC, m_parameters[MURC_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, m_parameters[SKIN_DEPTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, m_parameters[SIGMA_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, m_parameters[ANG_L_PRM] ); +} + +void C_STRIPLINE::show_results() +{ +} diff --git a/pcb_calculator/transline/c_stripline.h b/pcb_calculator/transline/c_stripline.h new file mode 100644 index 0000000000..7cbae0cb9e --- /dev/null +++ b/pcb_calculator/transline/c_stripline.h @@ -0,0 +1,44 @@ +/* + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef C_STRIPLINE_H_ +#define C_STRIPLINE_H_ + + +#include "transline/transline.h" +#include + + +class C_STRIPLINE : public TRANSLINE +{ +public: + C_STRIPLINE(); + +private: + void calcAnalyze() override; + void calcSynthesize() override; + void showAnalyze() override; + void showSynthesize() override; + void show_results() override; + void getProperties() override; + + COUPLED_STRIPLINE m_calc; +}; + +#endif // C_STRIPLINE_H_ diff --git a/pcb_calculator/transline/microstrip.cpp b/pcb_calculator/transline/microstrip.cpp index fb0235d1de..719b40c524 100644 --- a/pcb_calculator/transline/microstrip.cpp +++ b/pcb_calculator/transline/microstrip.cpp @@ -30,512 +30,100 @@ * Based on the original microstrip.c by Gopal Narayanan */ -#include -#include -#include -#include - #include "microstrip.h" #include "transline.h" - #include "units.h" -MICROSTRIP::MICROSTRIP() : TRANSLINE(), - h( 0.0 ), // height of substrate - ht( 0.0 ), // height to the top of box - t( 0.0 ), // thickness of top metal - rough( 0.0 ), // Roughness of top metal - mur( 0.0 ), // magnetic permeability of substrate - w( 0.0 ), // width of line - l( 0.0 ), // length of line - Z0_0( 0.0 ), // static characteristic impedance - Z0( 0.0 ), // characteristic impedance - er_eff_0( 0.0 ), // Static effective dielectric constant - mur_eff( 0.0 ), // Effective mag. permeability - w_eff( 0.0 ), // Effective width of line - atten_dielectric( 0.0 ), // Loss in dielectric (dB) - atten_cond( 0.0 ), // Loss in conductors (dB) - Z0_h_1( 0.0 ) // homogeneous stripline impedance + +MICROSTRIP_UI::MICROSTRIP_UI() { m_Name = "MicroStrip"; Init(); } -/* - * Z0_homogeneous() - compute the impedance for a stripline in a - * homogeneous medium, without cover effects - */ -double MICROSTRIP::Z0_homogeneous( double u ) +void MICROSTRIP_UI::calcAnalyze() { - double freq, Z0_value; - - freq = 6.0 + ( 2.0 * M_PI - 6.0 ) * exp( -pow( 30.666 / u, 0.7528 ) ); - Z0_value = ( ZF0 / ( 2.0 * M_PI ) ) * log( freq / u + sqrt( 1.0 + 4.0 / ( u * u ) ) ); - return Z0_value; + m_calc.Analyse(); } -/* - * delta_Z0_cover() - compute the cover effect on impedance for a - * stripline in a homogeneous medium - */ -double MICROSTRIP::delta_Z0_cover( double u, double h2h ) +void MICROSTRIP_UI::showAnalyze() { - double P, Q; - double h2hp1; + std::unordered_map>& results = + m_calc.GetAnalysisResults(); - h2hp1 = 1.0 + h2h; - P = 270.0 * ( 1.0 - tanh( 1.192 + 0.706 * sqrt( h2hp1 ) - 1.389 / h2hp1 ) ); - Q = 1.0109 - atanh( ( 0.012 * u + 0.177 * u * u - 0.027 * u * u * u ) / ( h2hp1 * h2hp1 ) ); - return P * Q; + setProperty( Z0_PRM, results[TRANSLINE_PARAMETERS::Z0].first ); + setProperty( ANG_L_PRM, results[TRANSLINE_PARAMETERS::ANG_L].first ); + + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY].first, "ps/cm" ); + setResult( 2, results[TRANSLINE_PARAMETERS::ATTEN_COND].first, "dB" ); + setResult( 3, results[TRANSLINE_PARAMETERS::ATTEN_DILECTRIC].first, "dB" ); + setResult( 4, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); + + setErrorLevel( Z0_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); } -/* - * filling_factor() - compute the filling factor for a microstrip - * without cover and zero conductor thickness - */ -double MICROSTRIP::filling_factor( double u, double e_r ) +void MICROSTRIP_UI::showSynthesize() { - double a, b, q_inf; - double u2, u3, u4; + std::unordered_map>& results = + m_calc.GetSynthesisResults(); - u2 = u * u; - u3 = u2 * u; - u4 = u3 * u; - a = 1.0 + log( ( u4 + u2 / 2704 ) / ( u4 + 0.432 ) ) / 49.0 + log( 1.0 + u3 / 5929.741 ) / 18.7; - b = 0.564 * pow( ( e_r - 0.9 ) / ( e_r + 3.0 ), 0.053 ); - q_inf = pow( 1.0 + 10.0 / u, -a * b ); - return q_inf; + setProperty( PHYS_WIDTH_PRM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first ); + setProperty( PHYS_LEN_PRM, results[TRANSLINE_PARAMETERS::PHYS_LEN].first ); + setProperty( Z0_PRM, results[TRANSLINE_PARAMETERS::Z0].first ); + setProperty( ANG_L_PRM, results[TRANSLINE_PARAMETERS::ANG_L].first ); + + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY].first, "ps/cm" ); + setResult( 2, results[TRANSLINE_PARAMETERS::ATTEN_COND].first, "dB" ); + setResult( 3, results[TRANSLINE_PARAMETERS::ATTEN_DILECTRIC].first, "dB" ); + setResult( 4, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); + + setErrorLevel( Z0_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); } -/* - * delta_q_cover() - compute the cover effect on filling factor - */ -double MICROSTRIP::delta_q_cover( double h2h ) +void MICROSTRIP_UI::getProperties() { - double q_c; + TRANSLINE::getProperties(); - q_c = tanh( 1.043 + 0.121 * h2h - 1.164 / h2h ); - return q_c; + m_calc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, m_parameters[SIGMA_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::EPSILON_EFF, m_parameters[EPSILON_EFF_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, m_parameters[SKIN_DEPTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, m_parameters[EPSILONR_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::H_T, m_parameters[H_T_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::H, m_parameters[H_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_WIDTH, m_parameters[PHYS_WIDTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::T, m_parameters[T_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::Z0, m_parameters[Z0_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, m_parameters[FREQUENCY_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::ROUGH, m_parameters[ROUGH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::TAND, m_parameters[TAND_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_LEN, m_parameters[PHYS_LEN_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::MUR, m_parameters[MUR_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::MURC, m_parameters[MURC_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, m_parameters[ANG_L_PRM] ); } -/* - * delta_q_thickness() - compute the thickness effect on filling factor - */ -double MICROSTRIP::delta_q_thickness( double u, double t_h ) +void MICROSTRIP_UI::show_results() { - double q_t; - - q_t = ( 2.0 * log( 2.0 ) / M_PI ) * ( t_h / sqrt( u ) ); - return q_t; } -/* - * e_r_effective() - compute effective dielectric constant from - * material e_r and filling factor - */ -double MICROSTRIP::e_r_effective( double e_r, double q ) -{ - double e_r_eff; - - e_r_eff = 0.5 * ( e_r + 1.0 ) + 0.5 * q * ( e_r - 1.0 ); - return e_r_eff; -} - - -/* - * delta_u_thickness - compute the thickness effect on normalized width - */ -double MICROSTRIP::delta_u_thickness( double u, double t_h, double e_r ) -{ - double delta_u; - - if( t_h > 0.0 ) - { - /* correction for thickness for a homogeneous microstrip */ - delta_u = ( t_h / M_PI ) - * log( 1.0 + ( 4.0 * M_E ) * pow( tanh( sqrt( 6.517 * u ) ), 2.0 ) / t_h ); - /* correction for strip on a substrate with relative permettivity e_r */ - delta_u = 0.5 * delta_u * ( 1.0 + 1.0 / cosh( sqrt( e_r - 1.0 ) ) ); - } - else - { - delta_u = 0.0; - } - return delta_u; -} - - -/* - * microstrip_Z0() - compute microstrip static impedance - */ -void MICROSTRIP::microstrip_Z0() -{ - double e_r, h2, h2h, u, t_h; - double Z0_h_r; - double delta_u_1, delta_u_r, q_inf, q_c, q_t, e_r_eff, e_r_eff_t, q; - - e_r = m_parameters[EPSILONR_PRM]; - h2 = m_parameters[H_T_PRM]; - h2h = h2 / m_parameters[H_PRM]; - u = m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM]; - t_h = m_parameters[T_PRM] / m_parameters[H_PRM]; - - /* compute normalized width correction for e_r = 1.0 */ - delta_u_1 = delta_u_thickness( u, t_h, 1.0 ); - /* compute homogeneous stripline impedance */ - Z0_h_1 = Z0_homogeneous( u + delta_u_1 ); - /* compute normalized width correction */ - delta_u_r = delta_u_thickness( u, t_h, e_r ); - u += delta_u_r; - /* compute homogeneous stripline impedance */ - Z0_h_r = Z0_homogeneous( u ); - - /* filling factor, with width corrected for thickness */ - q_inf = filling_factor( u, e_r ); - /* cover effect */ - q_c = delta_q_cover( h2h ); - /* thickness effect */ - q_t = delta_q_thickness( u, t_h ); - /* resultant filling factor */ - q = ( q_inf - q_t ) * q_c; - - /* e_r corrected for thickness and non homogeneous material */ - e_r_eff_t = e_r_effective( e_r, q ); - - /* effective dielectric constant */ - e_r_eff = e_r_eff_t * pow( Z0_h_1 / Z0_h_r, 2.0 ); - - /* characteristic impedance, corrected for thickness, cover */ - /* and non homogeneous material */ - m_parameters[Z0_PRM] = Z0_h_r / sqrt( e_r_eff_t ); - - w_eff = u * m_parameters[H_PRM]; - er_eff_0 = e_r_eff; - Z0_0 = m_parameters[Z0_PRM]; -} - - -/* - * e_r_dispersion() - computes the dispersion correction factor for - * the effective permeability - */ -double MICROSTRIP::e_r_dispersion( double u, double e_r, double f_n ) -{ - double P_1, P_2, P_3, P_4, P; - - P_1 = 0.27488 + u * ( 0.6315 + 0.525 / pow( 1.0 + 0.0157 * f_n, 20.0 ) ) - - 0.065683 * exp( -8.7513 * u ); - P_2 = 0.33622 * ( 1.0 - exp( -0.03442 * e_r ) ); - P_3 = 0.0363 * exp( -4.6 * u ) * ( 1.0 - exp( -pow( f_n / 38.7, 4.97 ) ) ); - P_4 = 1.0 + 2.751 * ( 1.0 - exp( -pow( e_r / 15.916, 8.0 ) ) ); - - P = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 ) * f_n, 1.5763 ); - - return P; -} - - -/* - * Z0_dispersion() - computes the dispersion correction factor for the - * characteristic impedance - */ -double MICROSTRIP::Z0_dispersion( - double u, double e_r, double e_r_eff_0, double e_r_eff_f, double f_n ) -{ - double R_1, R_2, R_3, R_4, R_5, R_6, R_7, R_8, R_9, R_10, R_11, R_12, R_13, R_14, R_15, R_16, - R_17, D, tmpf; - - R_1 = 0.03891 * pow( e_r, 1.4 ); - R_2 = 0.267 * pow( u, 7.0 ); - R_3 = 4.766 * exp( -3.228 * pow( u, 0.641 ) ); - R_4 = 0.016 + pow( 0.0514 * e_r, 4.524 ); - R_5 = pow( f_n / 28.843, 12.0 ); - R_6 = 22.2 * pow( u, 1.92 ); - R_7 = 1.206 - 0.3144 * exp( -R_1 ) * ( 1.0 - exp( -R_2 ) ); - R_8 = 1.0 - + 1.275 - * ( 1.0 - - exp( -0.004625 * R_3 * pow( e_r, 1.674 ) - * pow( f_n / 18.365, 2.745 ) ) ); - tmpf = pow( e_r - 1.0, 6.0 ); - R_9 = 5.086 * R_4 * ( R_5 / ( 0.3838 + 0.386 * R_4 ) ) - * ( exp( -R_6 ) / ( 1.0 + 1.2992 * R_5 ) ) * ( tmpf / ( 1.0 + 10.0 * tmpf ) ); - R_10 = 0.00044 * pow( e_r, 2.136 ) + 0.0184; - tmpf = pow( f_n / 19.47, 6.0 ); - R_11 = tmpf / ( 1.0 + 0.0962 * tmpf ); - R_12 = 1.0 / ( 1.0 + 0.00245 * u * u ); - R_13 = 0.9408 * pow( e_r_eff_f, R_8 ) - 0.9603; - R_14 = ( 0.9408 - R_9 ) * pow( e_r_eff_0, R_8 ) - 0.9603; - R_15 = 0.707 * R_10 * pow( f_n / 12.3, 1.097 ); - R_16 = 1.0 + 0.0503 * e_r * e_r * R_11 * ( 1.0 - exp( -pow( u / 15.0, 6.0 ) ) ); - R_17 = R_7 * ( 1.0 - 1.1241 * ( R_12 / R_16 ) * exp( -0.026 * pow( f_n, 1.15656 ) - R_15 ) ); - - D = pow( R_13 / R_14, R_17 ); - - return D; -} - - -/* - * dispersion() - compute frequency dependent parameters of - * microstrip - */ -void MICROSTRIP::dispersion() -{ - double e_r, e_r_eff_0; - double u, f_n, P, e_r_eff_f, D, Z0_f; - - e_r = m_parameters[EPSILONR_PRM]; - e_r_eff_0 = er_eff_0; - u = m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM]; - - /* normalized frequency [GHz * mm] */ - f_n = m_parameters[FREQUENCY_PRM] * m_parameters[H_PRM] / 1e06; - - P = e_r_dispersion( u, e_r, f_n ); - /* effective dielectric constant corrected for dispersion */ - e_r_eff_f = e_r - ( e_r - e_r_eff_0 ) / ( 1.0 + P ); - - D = Z0_dispersion( u, e_r, e_r_eff_0, e_r_eff_f, f_n ); - Z0_f = Z0_0 * D; - - // 1e10 factor is to convert from s/m to ps/cm - unit_prop_delay = calcUnitPropagationDelay( e_r_eff_f ); - - m_parameters[EPSILON_EFF_PRM] = e_r_eff_f; - m_parameters[Z0_PRM] = Z0_f; -} - - -/* - * conductor_losses() - compute microstrip conductor losses per unit - * length - */ -double MICROSTRIP::conductor_losses() -{ - double e_r_eff_0, delta; - double K, R_s, Q_c, alpha_c; - - e_r_eff_0 = er_eff_0; - delta = m_parameters[SKIN_DEPTH_PRM]; - - if( m_parameters[FREQUENCY_PRM] > 0.0 ) - { - /* current distribution factor */ - K = exp( -1.2 * pow( Z0_h_1 / ZF0, 0.7 ) ); - /* skin resistance */ - R_s = 1.0 / ( m_parameters[SIGMA_PRM] * delta ); - - /* correction for surface roughness */ - R_s *= 1.0 - + ( ( 2.0 / M_PI ) - * atan( 1.40 * pow( ( m_parameters[ROUGH_PRM] / delta ), 2.0 ) ) ); - /* strip inductive quality factor */ - Q_c = ( M_PI * Z0_h_1 * m_parameters[PHYS_WIDTH_PRM] * m_parameters[FREQUENCY_PRM] ) - / ( R_s * C0 * K ); - alpha_c = ( 20.0 * M_PI / log( 10.0 ) ) * m_parameters[FREQUENCY_PRM] * sqrt( e_r_eff_0 ) - / ( C0 * Q_c ); - } - else - { - alpha_c = 0.0; - } - - return alpha_c; -} - - -/* - * dielectric_losses() - compute microstrip dielectric losses per unit - * length - */ -double MICROSTRIP::dielectric_losses() -{ - double e_r, e_r_eff_0; - double alpha_d; - - e_r = m_parameters[EPSILONR_PRM]; - e_r_eff_0 = er_eff_0; - - alpha_d = ( 20.0 * M_PI / log( 10.0 ) ) * ( m_parameters[FREQUENCY_PRM] / C0 ) - * ( e_r / sqrt( e_r_eff_0 ) ) * ( ( e_r_eff_0 - 1.0 ) / ( e_r - 1.0 ) ) - * m_parameters[TAND_PRM]; - - return alpha_d; -} - - -/* - * attenuation() - compute attenuation of microstrip - */ -void MICROSTRIP::attenuation() -{ - m_parameters[SKIN_DEPTH_PRM] = skin_depth(); - - atten_cond = conductor_losses() * m_parameters[PHYS_LEN_PRM]; - atten_dielectric = dielectric_losses() * m_parameters[PHYS_LEN_PRM]; -} - - -/* - * mur_eff_ms() - returns effective magnetic permeability - */ -void MICROSTRIP::mur_eff_ms() -{ - double* mur = &m_parameters[MUR_PRM]; - double* h = &m_parameters[H_PRM]; - double* w = &m_parameters[PHYS_WIDTH_PRM]; - mur_eff = ( 2.0 * *mur ) - / ( ( 1.0 + *mur ) + ( ( 1.0 - *mur ) * pow( ( 1.0 + ( 10.0 * *h / *w ) ), -0.5 ) ) ); -} - - -// synth_width - calculate width given Z0 and e_r -double MICROSTRIP::synth_width() -{ - double e_r, a, b; - double w_h, width; - - e_r = m_parameters[EPSILONR_PRM]; - - a = ( ( m_parameters[Z0_PRM] / ZF0 / 2 / M_PI ) * sqrt( ( e_r + 1 ) / 2. ) ) - + ( ( e_r - 1 ) / ( e_r + 1 ) * ( 0.23 + ( 0.11 / e_r ) ) ); - b = ZF0 / 2 * M_PI / ( m_parameters[Z0_PRM] * sqrt( e_r ) ); - - if( a > 1.52 ) - { - w_h = 8 * exp( a ) / ( exp( 2. * a ) - 2 ); - } - else - { - w_h = ( 2. / M_PI ) - * ( b - 1. - log( ( 2 * b ) - 1. ) - + ( ( e_r - 1 ) / ( 2 * e_r ) ) * ( log( b - 1. ) + 0.39 - 0.61 / e_r ) ); - } - - if( m_parameters[H_PRM] > 0.0 ) - width = w_h * m_parameters[H_PRM]; - else - width = 0; - - return width; -} - - -/* - * line_angle() - calculate microstrip length in radians - */ -void MICROSTRIP::line_angle() -{ - double e_r_eff; - double v, lambda_g; - - e_r_eff = m_parameters[EPSILON_EFF_PRM]; - - /* velocity */ - v = C0 / sqrt( e_r_eff * mur_eff ); - /* wavelength */ - lambda_g = v / m_parameters[FREQUENCY_PRM]; - /* electrical angles */ - m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] / lambda_g; /* in radians */ -} - - -void MICROSTRIP::calcAnalyze() -{ - /* effective permeability */ - mur_eff_ms(); - /* static impedance */ - microstrip_Z0(); - /* calculate freq dependence of er and Z0 */ - dispersion(); - /* calculate electrical lengths */ - line_angle(); - /* calculate losses */ - attenuation(); -} - - -void MICROSTRIP::show_results() -{ - setProperty( Z0_PRM, m_parameters[Z0_PRM] ); - setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] ); - - setResult( 0, m_parameters[EPSILON_EFF_PRM], "" ); - setResult( 1, unit_prop_delay, "ps/cm" ); - setResult( 2, atten_cond, "dB" ); - setResult( 3, atten_dielectric, "dB" ); - - setResult( 4, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); -} - - -void MICROSTRIP::showSynthesize() -{ - setProperty( PHYS_WIDTH_PRM, m_parameters[PHYS_WIDTH_PRM] ); - setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); - - // Check for errors - if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || ( m_parameters[PHYS_LEN_PRM] < 0 ) ) - setErrorLevel( PHYS_LEN_PRM, TRANSLINE_ERROR ); - - if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || ( m_parameters[PHYS_WIDTH_PRM] <= 0 ) ) - setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR ); - - // Check for warnings - if( !std::isfinite( m_parameters[Z0_PRM] ) || ( m_parameters[Z0_PRM] < 0 ) ) - setErrorLevel( Z0_PRM, TRANSLINE_WARNING ); - - if( !std::isfinite( m_parameters[ANG_L_PRM] ) || ( m_parameters[ANG_L_PRM] < 0 ) ) - setErrorLevel( ANG_L_PRM, TRANSLINE_WARNING ); -} - -void MICROSTRIP::showAnalyze() -{ - setProperty( Z0_PRM, m_parameters[Z0_PRM] ); - setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] ); - - // Check for errors - if( !std::isfinite( m_parameters[Z0_PRM] ) || ( m_parameters[Z0_PRM] < 0 ) ) - setErrorLevel( Z0_PRM, TRANSLINE_ERROR ); - - if( !std::isfinite( m_parameters[ANG_L_PRM] ) || ( m_parameters[ANG_L_PRM] < 0 ) ) - setErrorLevel( ANG_L_PRM, TRANSLINE_ERROR ); - - // Check for warnings - if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || ( m_parameters[PHYS_LEN_PRM] < 0 ) ) - setErrorLevel( PHYS_LEN_PRM, TRANSLINE_WARNING ); - - if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || ( m_parameters[PHYS_WIDTH_PRM] <= 0 ) ) - setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING ); -} - /* * synthesis function */ -void MICROSTRIP::calcSynthesize() +void MICROSTRIP_UI::calcSynthesize() { - double z0_dest = m_parameters[Z0_PRM]; - double angl_dest = m_parameters[ANG_L_PRM]; - /* calculate width and use for initial value in Newton's method */ - m_parameters[PHYS_WIDTH_PRM] = synth_width(); - minimizeZ0Error1D( &( m_parameters[PHYS_WIDTH_PRM] ) ); - - m_parameters[Z0_PRM] = z0_dest; - m_parameters[ANG_L_PRM] = angl_dest; - double const er_eff = m_parameters[EPSILON_EFF_PRM]; - m_parameters[PHYS_LEN_PRM] = C0 / m_parameters[FREQUENCY_PRM] / sqrt( er_eff * mur_eff ) - * m_parameters[ANG_L_PRM] / 2.0 / M_PI; /* in m */ - calcAnalyze(); - - m_parameters[Z0_PRM] = z0_dest; - m_parameters[ANG_L_PRM] = angl_dest; - m_parameters[PHYS_LEN_PRM] = C0 / m_parameters[FREQUENCY_PRM] / sqrt( er_eff * mur_eff ) - * m_parameters[ANG_L_PRM] / 2.0 / M_PI; /* in m */ + m_calc.Synthesize( SYNTHESIZE_OPTS::DEFAULT ); } diff --git a/pcb_calculator/transline/microstrip.h b/pcb_calculator/transline/microstrip.h index 599711f5a6..7a573e2171 100644 --- a/pcb_calculator/transline/microstrip.h +++ b/pcb_calculator/transline/microstrip.h @@ -4,6 +4,7 @@ * Copyright (C) 2001 Gopal Narayanan * Copyright (C) 2005 Stefan Jahn * Modified for Kicad: 2015 jean-pierre.charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,69 +22,30 @@ * Boston, MA 02110-1301, USA. */ - #ifndef __MICROSTRIP_H #define __MICROSTRIP_H -#include "transline/transline.h" -class MICROSTRIP : public TRANSLINE +#include "transline/transline.h" +#include + + +class MICROSTRIP_UI : public TRANSLINE { public: - MICROSTRIP(); + MICROSTRIP_UI(); friend class C_MICROSTRIP; private: - double h; // height of substrate - double ht; // height to the top of box - double t; // thickness of top metal - double rough; // Roughness of top metal - double mur; // magnetic permeability of substrate - double w; // width of line - double l; // length of line - double Z0_0; // static characteristic impedance - double Z0; // characteristic impedance - double er_eff_0; // Static effective dielectric constant - double mur_eff; // Effective mag. permeability - double w_eff; // Effective width of line - double atten_dielectric; // Loss in dielectric (dB) - double atten_cond; // Loss in conductors (dB) - double unit_prop_delay; // Unit propagation delay (ps/cm) + MICROSTRIP m_calc; - // private params - double Z0_h_1; // homogeneous stripline impedance - -private: - double er_eff_freq(); - double alpha_c(); - double alpha_c_roughness(); - double alpha_dielectric(); - double char_impedance_ht(); - double synth_width(); - double ereff_dispersion(); - double Z0_dispersion(); - double Z0_homogeneous( double ); - double delta_Z0_cover( double, double ); - double filling_factor( double, double ); - double delta_q_cover( double ); - double delta_q_thickness( double, double ); - double e_r_effective( double, double ); - double delta_u_thickness( double, double, double ); - double e_r_dispersion( double, double, double ); - double Z0_dispersion( double, double, double, double, double ); - double conductor_losses(); - double dielectric_losses(); - void microstrip_Z0(); - void dispersion(); - void attenuation(); - void mur_eff_ms(); - void line_angle(); - void show_results() override; - void showSynthesize() override; - void showAnalyze() override; - void calcAnalyze() override; - void calcSynthesize() override; + void getProperties() override; + void show_results() override; + void showSynthesize() override; + void showAnalyze() override; + void calcAnalyze() override; + void calcSynthesize() override; }; #endif // __MICROSTRIP_H diff --git a/pcb_calculator/transline/stripline.cpp b/pcb_calculator/transline/stripline.cpp index edd2220596..4c3c97194c 100644 --- a/pcb_calculator/transline/stripline.cpp +++ b/pcb_calculator/transline/stripline.cpp @@ -3,6 +3,7 @@ * * Copyright (C) 2011 Michael Margraf * Modifications 2018 for Kicad: Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,162 +22,97 @@ * */ - -#include -#include -#include -#include - #include "stripline.h" -#include "units.h" +#include -STRIPLINE::STRIPLINE() : TRANSLINE(), unit_prop_delay( 0.0 ) + +STRIPLINE_UI::STRIPLINE_UI() { m_Name = "StripLine"; Init(); } -// ------------------------------------------------------------------- -// calculate characteristic impedance and conductor loss (in db/meter) -double STRIPLINE::lineImpedance( double height, double& ac ) +void STRIPLINE_UI::calcAnalyze() { - double ZL; - double hmt = height - m_parameters[T_PRM]; - - ac = sqrt( m_parameters[FREQUENCY_PRM] / m_parameters[SIGMA_PRM] / 17.2 ); - - if( m_parameters[PHYS_WIDTH_PRM] / hmt >= 0.35 ) - { - ZL = m_parameters[PHYS_WIDTH_PRM] - + ( 2.0 * height * log( ( 2.0 * height - m_parameters[T_PRM] ) / hmt ) - - m_parameters[T_PRM] * log( height * height / hmt / hmt - 1.0 ) ) - / M_PI; - ZL = ZF0 * hmt / sqrt( m_parameters[EPSILONR_PRM] ) / 4.0 / ZL; - - ac *= 2.02e-6 * m_parameters[EPSILONR_PRM] * ZL / hmt; - ac *= 1.0 + 2.0 * m_parameters[PHYS_WIDTH_PRM] / hmt - + ( height + m_parameters[T_PRM] ) / hmt / M_PI - * log( 2.0 * height / m_parameters[T_PRM] - 1.0 ); - } - else - { - double tdw = m_parameters[T_PRM] / m_parameters[PHYS_WIDTH_PRM]; - if( m_parameters[T_PRM] / m_parameters[PHYS_WIDTH_PRM] > 1.0 ) - tdw = m_parameters[PHYS_WIDTH_PRM] / m_parameters[T_PRM]; - double de = 1.0 + tdw / M_PI * ( 1.0 + log( 4.0 * M_PI / tdw ) ) + 0.236 * pow( tdw, 1.65 ); - if( m_parameters[T_PRM] / m_parameters[PHYS_WIDTH_PRM] > 1.0 ) - de *= m_parameters[T_PRM] / 2.0; - else - de *= m_parameters[PHYS_WIDTH_PRM] / 2.0; - ZL = ZF0 / 2.0 / M_PI / sqrt( m_parameters[EPSILONR_PRM] ) - * log( 4.0 * height / M_PI / de ); - - ac *= 0.01141 / ZL / de; - ac *= de / height + 0.5 + tdw / 2.0 / M_PI + 0.5 / M_PI * log( 4.0 * M_PI / tdw ) - + 0.1947 * pow( tdw, 0.65 ) - 0.0767 * pow( tdw, 1.65 ); - } - - return ZL; + m_calc.Analyse(); } -// ------------------------------------------------------------------- -void STRIPLINE::calcAnalyze() +void STRIPLINE_UI::calcSynthesize() { - m_parameters[SKIN_DEPTH_PRM] = skin_depth(); - - m_parameters[EPSILON_EFF_PRM] = m_parameters[EPSILONR_PRM]; // no dispersion - - double ac1, ac2; - double t = m_parameters[T_PRM]; - double a = m_parameters[STRIPLINE_A_PRM]; - double h = m_parameters[H_PRM]; - m_parameters[Z0_PRM] = 2.0 - / ( 1.0 / lineImpedance( 2.0 * a + t, ac1 ) - + 1.0 / lineImpedance( 2.0 * ( h - a ) - t, ac2 ) ); - m_parameters[LOSS_CONDUCTOR_PRM] = m_parameters[PHYS_LEN_PRM] * ( ac1 + ac2 ); - m_parameters[LOSS_DIELECTRIC_PRM] = LOG2DB * m_parameters[PHYS_LEN_PRM] - * ( M_PI / C0 ) * m_parameters[FREQUENCY_PRM] - * sqrt( m_parameters[EPSILONR_PRM] ) - * m_parameters[TAND_PRM]; - - m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] - * sqrt( m_parameters[EPSILONR_PRM] ) * m_parameters[FREQUENCY_PRM] - / C0; // in radians - - unit_prop_delay = calcUnitPropagationDelay( m_parameters[EPSILON_EFF_PRM] ); + m_calc.Synthesize( SYNTHESIZE_OPTS::DEFAULT ); } -void STRIPLINE::showAnalyze() +void STRIPLINE_UI::showAnalyze() { - setProperty( Z0_PRM, m_parameters[Z0_PRM] ); - setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] ); + std::unordered_map>& results = + m_calc.GetAnalysisResults(); - if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 ) - setErrorLevel( Z0_PRM, TRANSLINE_ERROR ); + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY].first, "ps/cm" ); + setResult( 2, results[TRANSLINE_PARAMETERS::LOSS_CONDUCTOR].first, "dB" ); + setResult( 3, results[TRANSLINE_PARAMETERS::LOSS_DIELECTRIC].first, "dB" ); + setResult( 4, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); - if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 ) - setErrorLevel( ANG_L_PRM, TRANSLINE_ERROR ); + setProperty( Z0_PRM, results[TRANSLINE_PARAMETERS::Z0].first ); + setProperty( ANG_L_PRM, results[TRANSLINE_PARAMETERS::ANG_L].first ); - if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 ) - setErrorLevel( PHYS_LEN_PRM, TRANSLINE_WARNING ); - - if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] < 0 ) - setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING ); - - if( m_parameters[STRIPLINE_A_PRM] + m_parameters[T_PRM] >= m_parameters[H_PRM] ) - { - setErrorLevel( STRIPLINE_A_PRM, TRANSLINE_WARNING ); - setErrorLevel( T_PRM, TRANSLINE_WARNING ); - setErrorLevel( H_PRM, TRANSLINE_WARNING ); - setErrorLevel( Z0_PRM, TRANSLINE_ERROR ); - } -} - -void STRIPLINE::showSynthesize() -{ - setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); - setProperty( PHYS_WIDTH_PRM, m_parameters[PHYS_WIDTH_PRM] ); - - if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0 ) - setErrorLevel( PHYS_LEN_PRM, TRANSLINE_ERROR ); - - if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] < 0 ) - setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR ); - - if( !std::isfinite( m_parameters[Z0_PRM] ) || m_parameters[Z0_PRM] < 0 ) - setErrorLevel( Z0_PRM, TRANSLINE_WARNING ); - - if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] < 0 ) - setErrorLevel( ANG_L_PRM, TRANSLINE_WARNING ); - - if( m_parameters[STRIPLINE_A_PRM] + m_parameters[T_PRM] >= m_parameters[H_PRM] ) - { - setErrorLevel( STRIPLINE_A_PRM, TRANSLINE_WARNING ); - setErrorLevel( T_PRM, TRANSLINE_WARNING ); - setErrorLevel( H_PRM, TRANSLINE_WARNING ); - setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR ); - } -} -// ------------------------------------------------------------------- -void STRIPLINE::show_results() -{ - - setResult( 0, m_parameters[EPSILON_EFF_PRM], "" ); - setResult( 1, unit_prop_delay, "ps/cm" ); - setResult( 2, m_parameters[LOSS_CONDUCTOR_PRM], "dB" ); - setResult( 3, m_parameters[LOSS_DIELECTRIC_PRM], "dB" ); - - setResult( 4, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); + setErrorLevel( Z0_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); + setErrorLevel( STRIPLINE_A_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::STRIPLINE_A].second ) ); + setErrorLevel( T_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::T].second ) ); + setErrorLevel( H_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::T].second ) ); } -#define MAX_ERROR 0.000001 - -// ------------------------------------------------------------------- -void STRIPLINE::calcSynthesize() +void STRIPLINE_UI::showSynthesize() { - minimizeZ0Error1D( &( m_parameters[PHYS_WIDTH_PRM] ) ); + std::unordered_map>& results = + m_calc.GetSynthesisResults(); + + setResult( 0, results[TRANSLINE_PARAMETERS::EPSILON_EFF].first, "" ); + setResult( 1, results[TRANSLINE_PARAMETERS::UNIT_PROP_DELAY].first, "ps/cm" ); + setResult( 2, results[TRANSLINE_PARAMETERS::LOSS_CONDUCTOR].first, "dB" ); + setResult( 3, results[TRANSLINE_PARAMETERS::LOSS_DIELECTRIC].first, "dB" ); + setResult( 4, results[TRANSLINE_PARAMETERS::SKIN_DEPTH].first / UNIT_MICRON, "µm" ); + + setProperty( PHYS_LEN_PRM, results[TRANSLINE_PARAMETERS::PHYS_LEN].first ); + setProperty( PHYS_WIDTH_PRM, results[TRANSLINE_PARAMETERS::PHYS_WIDTH].first ); + + setErrorLevel( Z0_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::Z0].second ) ); + setErrorLevel( ANG_L_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::ANG_L].second ) ); + setErrorLevel( PHYS_LEN_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_LEN].second ) ); + setErrorLevel( PHYS_WIDTH_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::PHYS_WIDTH].second ) ); + setErrorLevel( STRIPLINE_A_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::STRIPLINE_A].second ) ); + setErrorLevel( T_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::T].second ) ); + setErrorLevel( H_PRM, convertParameterStatusCode( results[TRANSLINE_PARAMETERS::T].second ) ); +} + + +void STRIPLINE_UI::show_results() +{ +} + + +void STRIPLINE_UI::getProperties() +{ + TRANSLINE::getProperties(); + + m_calc.SetParameter( TRANSLINE_PARAMETERS::SKIN_DEPTH, m_parameters[SKIN_DEPTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::EPSILONR, m_parameters[EPSILONR_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::T, m_parameters[T_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::STRIPLINE_A, m_parameters[STRIPLINE_A_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::H, m_parameters[H_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::Z0, m_parameters[Z0_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_LEN, m_parameters[PHYS_LEN_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::FREQUENCY, m_parameters[FREQUENCY_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::TAND, m_parameters[TAND_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::PHYS_WIDTH, m_parameters[PHYS_WIDTH_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::ANG_L, m_parameters[ANG_L_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::SIGMA, m_parameters[SIGMA_PRM] ); + m_calc.SetParameter( TRANSLINE_PARAMETERS::MURC, m_parameters[MURC_PRM] ); } diff --git a/pcb_calculator/transline/stripline.h b/pcb_calculator/transline/stripline.h index b4e4efede9..c262eda4b2 100644 --- a/pcb_calculator/transline/stripline.h +++ b/pcb_calculator/transline/stripline.h @@ -3,6 +3,7 @@ * * Copyright (C) 2011 Michael Margraf * Modifications 2011 for Kicad: Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,26 +22,27 @@ * */ -#ifndef __STRIPLINE_H -#define __STRIPLINE_H +#ifndef STRIPLINE_UI_H +#define STRIPLINE_UI_H #include "transline/transline.h" +#include -class STRIPLINE : public TRANSLINE +class STRIPLINE_UI : public TRANSLINE { public: - STRIPLINE(); + STRIPLINE_UI(); private: - void calcAnalyze() override; - void calcSynthesize() override; - void showSynthesize() override; - void showAnalyze() override; - double lineImpedance( double, double& ); - void show_results() override; + void calcAnalyze() override; + void calcSynthesize() override; + void showSynthesize() override; + void showAnalyze() override; + void show_results() override; + void getProperties() override; - double unit_prop_delay; + STRIPLINE m_calc; }; -#endif +#endif //STRIPLINE_UI_H diff --git a/pcb_calculator/transline/transline.cpp b/pcb_calculator/transline/transline.cpp index aee2582ef9..f40b31a6a1 100644 --- a/pcb_calculator/transline/transline.cpp +++ b/pcb_calculator/transline/transline.cpp @@ -443,4 +443,17 @@ void TRANSLINE::setErrorLevel( PRMS_ID aP, char aErrorLevel ) double TRANSLINE::calcUnitPropagationDelay( const double epsilonEff ) { return std::sqrt( epsilonEff ) * ( 1.0e10 / 2.99e8 ); -} \ No newline at end of file +} + + +char TRANSLINE::convertParameterStatusCode( TRANSLINE_STATUS aStatus ) +{ + switch( aStatus ) + { + case TRANSLINE_STATUS::OK: return TRANSLINE_OK; + case TRANSLINE_STATUS::WARNING: return TRANSLINE_WARNING; + case TRANSLINE_STATUS::ERROR: return TRANSLINE_ERROR; + } + + return TRANSLINE_OK; +} diff --git a/pcb_calculator/transline/transline.h b/pcb_calculator/transline/transline.h index bc67a03d8c..339fa90a2a 100644 --- a/pcb_calculator/transline/transline.h +++ b/pcb_calculator/transline/transline.h @@ -3,6 +3,7 @@ * * Copyright (C) 2005 Stefan Jahn * Modifications 2018 for Kicad: Jean-Pierre Charras + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,6 +26,7 @@ #define __TRANSLINE_H #include +#include #define TRANSLINE_OK 0 #define TRANSLINE_WARNING 1 @@ -86,7 +88,7 @@ public: double getProperty( enum PRMS_ID aPrmId ); - void getProperties(); + virtual void getProperties(); void checkProperties(); void setResult( int, double, const char* ); void setResult( int, const char* ); @@ -138,6 +140,9 @@ protected: /// Calculates the unit propagation delay (in ps/cm) for the given effective dielectric constant static double calcUnitPropagationDelay( double epsilonEff ); + + /// Converts a TRANSLINE_PARAMETER status to a PCB Calculation status + static char convertParameterStatusCode( TRANSLINE_STATUS aStatus ); }; #endif /* __TRANSLINE_H */ diff --git a/pcb_calculator/transline_dlg_funct.cpp b/pcb_calculator/transline_dlg_funct.cpp index 9277dcd92a..df98e9b078 100644 --- a/pcb_calculator/transline_dlg_funct.cpp +++ b/pcb_calculator/transline_dlg_funct.cpp @@ -106,7 +106,7 @@ void PANEL_TRANSLINE::TranslineTypeSelection( enum TRANSLINE_TYPE_ID aType ) m_translineBitmap->SetBitmap( KiBitmapBundle( m_transline_list[m_currTransLineType]->m_BitmapName ) ); // This helper bitmap is shown for coupled microstrip only: - m_bmCMicrostripZoddZeven->Show( aType == C_MICROSTRIP_TYPE ); + m_bmCMicrostripZoddZeven->Show( aType == C_MICROSTRIP_TYPE || aType == C_STRIPLINE_TYPE ); m_bmCMicrostripZoddZeven->SetBitmap( KiBitmapBundle( BITMAPS::microstrip_zodd_zeven ) ); TRANSLINE_IDENT* tr_ident = m_transline_list[m_currTransLineType]; diff --git a/pcb_calculator/transline_ident.cpp b/pcb_calculator/transline_ident.cpp index bfedcc204a..19565c490c 100644 --- a/pcb_calculator/transline_ident.cpp +++ b/pcb_calculator/transline_ident.cpp @@ -36,6 +36,7 @@ #include "transline/c_microstrip.h" #include "transline/stripline.h" #include "transline/twistedpair.h" +#include "transline/c_stripline.h" #include "pcb_calculator_settings.h" #include "widgets/unit_selector.h" @@ -113,7 +114,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) switch( m_Type ) { case MICROSTRIP_TYPE: // microstrip - m_TLine = new MICROSTRIP(); + m_TLine = new MICROSTRIP_UI(); m_BitmapName = BITMAPS::microstrip; m_Messages.Add( wxString::Format( _( "Effective %s:" ), wxT( "εr" ) ) ); @@ -336,6 +337,37 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, "L", "L", _( "Line length" ), 50.0, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_E_PRM, "Zeven", _( "Zeven" ), + _( "Even mode impedance (lines driven by common voltages)" ), 50.0, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_O_PRM, "Zodd", _( "Zodd" ), + _( "Odd mode impedance (lines driven by opposite " + "(differential) voltages)" ), + 50.0, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, "Ang_l", "Ang_l", _( "Electrical length" ), 0.0, true ) ); + break; + + case C_STRIPLINE_TYPE: // Coupled stripline + m_TLine = new C_STRIPLINE(); + m_BitmapName = BITMAPS::coupled_stripline; + m_HasPrmSelection = true; + + m_Messages.Add( wxString::Format( _( "Effective %s (even):" ), wxT( "εr" ) ) ); + m_Messages.Add( wxString::Format( _( "Effective %s (odd):" ), wxT( "εr" ) ) ); + m_Messages.Add( _( "Unit propagation delay (even):" ) ); + m_Messages.Add( _( "Unit propagation delay (odd):" ) ); + m_Messages.Add( _( "Skin depth:" ) ); + m_Messages.Add( _( "Differential Impedance (Zd):" ) ); + + AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_PRM, "H", "H", _( "Height of substrate" ), 0.2, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, T_PRM, "T", "T", _( "Strip thickness" ), 0.035, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, "mu rel C", + wxString::Format( wxT( "μ(%s)" ), _( "conductor" ) ), + _( "Relative permeability (mu) of conductor" ), 1, false ) ); + + AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_WIDTH_PRM, "W", "W", _( "Line width" ), 0.2, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_S_PRM, "S", "S", _( "Gap width" ), 0.2, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, "L", "L", _( "Line length" ), 50.0, true ) ); + AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_E_PRM, "Zeven", _( "Zeven" ), _( "Even mode impedance (lines driven by common voltages)" ), @@ -350,7 +382,7 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) break; case STRIPLINE_TYPE: // stripline - m_TLine = new STRIPLINE(); + m_TLine = new STRIPLINE_UI(); m_BitmapName = BITMAPS::stripline; m_Messages.Add( wxString::Format( _( "Effective %s:" ), wxT( "εr" ) ) ); diff --git a/pcb_calculator/transline_ident.h b/pcb_calculator/transline_ident.h index 8ab17afdb3..47de3a4c89 100644 --- a/pcb_calculator/transline_ident.h +++ b/pcb_calculator/transline_ident.h @@ -33,16 +33,18 @@ enum class BITMAPS : unsigned int; // An enum to handle muwave shapes: -enum TRANSLINE_TYPE_ID { +enum TRANSLINE_TYPE_ID +{ START_OF_LIST_TYPE = 0, DEFAULT_TYPE = START_OF_LIST_TYPE, MICROSTRIP_TYPE = DEFAULT_TYPE, + C_MICROSTRIP_TYPE, + STRIPLINE_TYPE, + C_STRIPLINE_TYPE, CPW_TYPE, GROUNDED_CPW_TYPE, RECTWAVEGUIDE_TYPE, COAX_TYPE, - C_MICROSTRIP_TYPE, - STRIPLINE_TYPE, TWISTEDPAIR_TYPE, END_OF_LIST_TYPE }; diff --git a/resources/bitmaps_png/CMakeLists.txt b/resources/bitmaps_png/CMakeLists.txt index 049977a1a3..3d06cfd7f7 100644 --- a/resources/bitmaps_png/CMakeLists.txt +++ b/resources/bitmaps_png/CMakeLists.txt @@ -720,6 +720,7 @@ set( BMAPS_OTHER color_code_tolerance color_code_value color_code_value_and_name + coupled_stripline creepage_clearance cpw cpw_back diff --git a/resources/bitmaps_png/png/coupled_stripline.png b/resources/bitmaps_png/png/coupled_stripline.png new file mode 100644 index 0000000000000000000000000000000000000000..34f7f7fe6e67bd5f3d9fa41611def8e7f58c6c19 GIT binary patch literal 10179 zcmY*fWmr^Qv?c~P^r0JPq&t+(89+t48)*=bZV;GZDCrWVK~ZUxE@4QKRHR!(K#&lm zIZ1uMnVzYZpnN+GK-UAD)bYv>{@;(=X%8R>>Uh=LVEO}2YUKEF z1N^#Q!>yT#>ZhUTMk?#~J95!?4Uvk;v&e;Z`LCj9g3=8L#m>yTnhTd7*7JN{an+~$ z%6Fn}Ld%AG41A!LYZ8ZLba@kxq?7Tf<2kj2*5#p=*StHaop?iz!s_XGwndj4I_JKm z*Kwrpxw}ZIn?he`F|{qO&R9!*70s9ZK@x2{^(w=*pjOWPjzi4gz~85as&XnuWRIJ3 zX!2LW(wkiq^YP2B4WQPFRL6sbxDhYylO2?seGcYR{y3f70N~}51J+ZME5UTgQN?Gq z)R&#N^7Q#vka6M7B6c{}mU1am_fY4)vv;N0OVBpvD{DJ@J%8>;@DYRJz~_w{Tv&5R zG((t~Dp>FQ)JlpWCjntQ^xiK>?3j6hCY*@<*-mu)D#`I)U~=9o|8!}{P?J0b7m=dP zjUs2nj!6Jzx9(Zn@`ezmh7p3_zB=^1<*2mQ;Htz+7$Lw*ev_>KBR? ze`v45E_{-^AX)2gH8O&l7^~FI-CvW#!`itmaaL&x=Y)W!&(4|@D?gv|Dep@`Fy3Eo zx#oQXTg`rXrup{&P{VYrM#;kCQVhaUp>gHXm3~Pl-a1bmv!RCYeNrw+2Qi8oAI8sd zQzXm%j_(;IHH3ifcW!^dyin*lOB?>`=Pch_WGk#n_W?qo!x$Y>0HqIEoxM}+72$9L zGTMcKR?g>^0P0=()n463V2Hw1l@(G{Q@B$}S#i%m0-{3$DFwO@)hbq2KUwn%&JYH_ z4LIDbMSYKgz@LD-p<~y|pP-*)!cidE57_Cp0R+y6+Ba9nk*A&|pFIoxmXfd7kZ%@4 zdy5k&_tiL5LNj*0o$puX|QV)&0PD(uL zer&CdWzo5#W(OONUV@O-?6W$k;)+bbg7qFx*W&ss0ZB>(+9uU~bO6B6X>_cvg`tXQ z;WJjPwCoALP|fW?$H3*s{%A#-c$IzaYJAShODZ{G-=49q5l2O7Il01y$Dp`|uHs22 zfci>k>-kbdo@x?TFZfISPYApN+)?<6b06=K&48olnasCoTbf{i;x;5( z=zvg-y)XPV(0#+3jhPT@TG7>Jt&)Q4ia_S?{6yI854i#X3+;qjT3U_di0d)5vPXbO zR8fr-88w89xcjDjKgQYKqc+FR+znNv2sDpwZ^Euch7ynUDCOdf zLR$XAb*jFOn9{YiHzusA>xG%VUnlMW+w;V4=_4LZql&bmKp121$SyT>MhDE~1R@N! za76|h5H|OOFYA_&Q!kAp^184_bgJP$y3BNcFRX6BRf=8qrW9PU63%~1IO zTy@Va`AAUxd**I_Gq{|OsB75a_^<>+ngHpo8aAlgGq4IB-K1m8e>`1(yaW zS=yK@Jv2xl1Inv*)!@M{&27??*h_e7AoP?7K+S=dZ=C3V^j1da{hqiB4I1QyJi$X_ z{+Rs*;J0LmroV1XWFt`La(j4frJ3DC@{k)-jb&U^ktC$EIv{eV`H5H9iC~u8Wy~O0 z9|FdB-4TEQjc&`EIE@=$!iUBOcv zQpJoe{zIuj05rZ%r-Q0JHBn*-o6yGStcmD0F`|mJfosn*)=%0=k!zu>_sHQD1grcW zPGSh%(ZL`for_n^7IpODC@e_fnj}nb{hk{F{5HxZvzF z-=@U)zCsmEB1H`qIqp}ZR$4e9@X)FC66kZrs_m911Ny7?#h&bA6{6l40{?yfr#o2J zFqQP|;%5#4%9xCp#`E8w`pRnRg%up|>9N@^)<0}tQsy-_5zYVyu9S)%g zbd7y-VvAmVW@DFwR1u;pTDI=XX!k>BGL^wh)b@poA%kY3ZWqgeiRmFEEG$ABPo8d( z0)O4doCj4jCH5@L1RosdP`fR&}?FCmI|&t7O9g&WEA#5wrS$fpcU^x=rE*NhP@kSqY0_}=RM zWCT_w7PE@+4GR1vqx@K`MbCX8dI=vEn(`@}ii7fQn(yj2`AVLeZf+8KaszG9-L8;eQ~gDRI%Qe8fEkMxNJYAm9inZ6mub@i=B#M9 zus5-TGMSZEm**)|p7F~-jsUA%3jdtl-ir% z)o?iJmJ|kO*1PXKl+4h7t^_F?;z==keBE!~rdyI!4L5Cf??b#K|HM zVl*f9;BDye+;(;NWd#3*ii*}tYLvHz;qE?-JY=Y!0QE0bb)W)Cs{V#Q+QJ*r`t0}O zYcGxjq^3ZCO$wj})H&1DlurwJeqtEb*}aNe)Cn+IJ1q`3_lrxnhMN(o$`5X*sS>T; zV@Ka&7+m>NN=hc{I0)Z4;Jn%E$?EU+#(LY>XpCc%A#dH zQHdbv<5j6dM~%diXGF(HVPKj;cM-o^!emPiJyCH&!cdJ74@})qTU)!Hg4*ceLy~%{ z$LLCOrJswdcok7aeQ-urRm1aGPK_Vg|dSf)Sv}lE;uE|Lw zaksY66Oa9)BZuvTZNaJFfSnm!c6Rn!zb*YQV-n0QZEY3sPmvRoj#=Qh1&N;#wk8P_ z-KVEP9iBhjEu@A=+3V+`Kk%&o_#rCY($WIg(@S&Nz>Hbcl7M9Trt?GDB0cF`8Z#0c z?^;z`&sbPkW<|v0bzEF{FIbdJ+{{T|YD&_gjRh-kS1%XfQ-#9s-)Gx!mHheh=Nl;R zd$0Yns=ofN1kQow($Z2uXQN4tb@cjBcHQ<;;}aIYfPiN{1wVf}NjP-(^uT0gbFMB< z57ry$zfa=p2DEpQyP)=z#+ppyNCefs$P@3y-NP~&}d{d8`2T{(e2#f%jz| zG1`7fqWXh0P~-2{b7D_xo-w?;2Hy+`i-bB6W<7si4h!0u5&JTlk(*l)Q}o8s=l7h% zF##z6)V4KX{WVYlr35{e+W9^QS6jA}EHN#8eA;HbLxqVOD<;r}*2BT`!Y${i!s_?Q z(m3ra`ji-VGQ>8-iVyPb%d7iB)S>dhe}1HHn46o=Fpwc_J+~9O2HdPWLKQ-ix>045fg%?Rt{6*8*AR(91;vs&g9Wg$>_&z+Um>9d17l^1_iBpXfWfv8w`;)zx zB*&*JoN}|2l=lVd*;C$abAZYF_*V5UR2RB5G&E|SE?;J3AqTQj zPv%}H2isj5?2t3oH)^R{4p<`GEJQ5uV9b>KpmDMr;_m^ef~bVHt$|cb15&qc4k|9L zZ>XU=6DdX;niwCimwjOSEWS#`>+t8uPRKZO?@Yd_hg3i7fqaE=m0jCzO!EB-suZhc zFPKIR45S9Q$Ppv1_?oqJ+wzR51G%F!43@k#D%;=Y>`XZ5THkiZKoGidlsOhn9*g=a zqMV$)E<4^q-(}6v5QKUZxaP$=@Saj!P*C%mNW!=#ju4f>=k3Y^LN-1~;P1J<>VdH_ zo%-e?Ftqp3rWqdBk(1Nxk>qwC$_bj&q7Z{wP7TPG$?e?LQBqk*pNr`|% zpZll#WF3p|&1cp#ggvs88i9i5e83uW2<(k@SGG(4sOA$dEJ57CQ3C{z5P_XXJN@|VbPBK@}2(9aoo1sLuPG%{|4El{;8=K z$}ZfX>(uSol-lkew<#4z=GH5JTIUiLJ2l|8_C9wx@!Ma4N0Aea8}&R(6BZ~?vn}6u zqNC3ELPAf9LhLCoM1C=OE-mlP=A1V3oq3)bIABP2oo>!kb}5DS{=#Do;|gfwF|Zi1 zC~wFv<@}*w_gP0xEgH-0AbtVS06k-Z!uO=d55LPIQ?+(JAS>M1Q!;E^G_+K1X(u_lW<-dCT}I3znh{)-H=ht;CjPOgJlGIl93<|Fe7S+^h5y=r_h zae0qA^qYH*Ew6XJ@&hQV6lmNOpt8DN01M$V!`*&((ZJq0r`X8mI-HlB@D%h@q zy|RsQsFxntHH1=I+PVKleXAsjQ&85ODN{Rnv}5jaNr2)L@3%{Fxgw2vDcU*C zu8%Fb1+a4r55SK?l;e8dSZlF6bg@>Iq9l4Y%b(Fv(n6u%%1YeacPvfkxSTRfG>C_0 z$LZ)V%teoR$@Ih}rfDY9uyzWd51_Qf=tEy3o2QQp2TAyU(KyyQ;NB?iPKX6l;>J&l zngezxjKzx?rui`vQZ{7kH^mh(EWA^a`1bW53_nvo?_8A;E#S`_XL8L!PDy*D&d^)} z=-W|VmEsJ*SfjsN60{F)FdBUIDh6uoWm>YB!B_S3{RVsYjP-(T{V00TL(KC*Wu0Wh z9WsP25*At&#kapa`vbL01dqVi+OY;uW> zq0EX87N)EuE`>ytMP+2n>JME4V#KCsah;oh`0bc`e$?1|DGQgDa>hYuoNG-zyK_~7 z+`s26rI}<>>-`$QG?c!oBlQ0BqKwPL9$7T*x|BNqdI`}lF`HlGp~7Z-Oni=8~Z zFCvMnn&#gn&(KZE_uls}{IPsEGMZ))g=oNCstlTVMgT9KY)?r^Su#G%F@9G3N7f?E zX$ebID3^^dl`W&6Ka0ya8w~$1h4l$&gcpbb#7P_xR_!ucLM_as5UqHHx!f$2e>-C7 z)y%}@`0smwlao{OyT>u_sq+8hJtQcl-LLNx?dWC)AJ3e5)nUdbWFm~TYy=i8f2yd? z;BGeiThSUlXXq)3e$&S;vEA3_o&$&8r3CWx@*VNWm6F9lMm~C7VJH{>0Pk6%FVlPFZq5rmL+4LOP`X z-DX*U%8QZm?rZt$4tulw_iO2+hUPo>wDxb17*+{eyaI(5S3IB&kGtm}HC9b8<_3R< zb&DuFcVSs?codFBv)bI&&tc@|E7KPLSyGAOraYJH*~hAvgQICw=OxwxYP=#n9^Z~> zYp9h^xAO`yoxhypOBy#BW@UaQ?@7IA7S5c4k@dM^(Q$%vihx?H9yt>9)J-I?`(E>+ z>g{VX1k8KU_@2kV<4?ycE;SETXF~VTOeZC6V$~+4RwWfnV_0^43%%RWo~$e#0+MLm z>8)nq!HOU;`V~%bW@Y99Ua@G&gz10mg(VFl@ZrcqCQ6Xv))ziwtV9$$Du1f`RWgYL zefO+2^h8VVCRO%LW?3{%DkaGJm)-Y)X69tsJqFFo9}^;V!))oOB}Yv+SC3mJk>g7a z>R`W6sJ@T!vr_oG*}FY6aoTvre?N{L9r=0bwe~?z{xqvWzZK`^w-QM`F0WU6{G>q4 zi|m(bw0NE!v1DDAw~$qz(RDJU7y7f}GQQhG z&E*kcPmJVEOwIdUbE)|Q$pFnZBup>X^KIu=sh2a!6_>7*@3s@-TlvA`AhHTS?q^a#V#?k_mf+$$Jfg5hCi2R5I(g-Tsf z`&X}2mJQY?J*FNU7rU%Wf6Y#Jr$N84ILGO{m(sV0bjua=$$|>GL>*Kh()^k)F0O?_~kbl9l;SQloc^wxK3#B=agcN z^(#?k>KBI41%pWEFp8#NbuXo){zMg&&lX`mV}+& z)A?7pITvojgYCALr6EUHz&uf+D#mK9t3*-A4YUO<7sjZ&#KL71G`7ya-y3bu!#%!4d&&7Goi+3( z-CDq*Mi6=oJg!44zx&l4Ud{acvt?GDV`DhvrgDND^UTHZ7ump|O;T7+_G>$|r!(1y zTw<8RuQ5)kzl^N1De=?S(Hw3R-p2Tb4?%v@ki_CbDksTT{%HE;%Z2dfqBNfa_dMhR~|P5WF(7t{V~U&ilAl9^vC`n{5$+krx{h3DqX zdNlq{yXRZV51DysuP=A1e>sD}llLZ^u{FD{wO$;{)>*Au82Bq@rH_06#M@xBVac5t zVlw3XI++%QT?EfLXqaTtA#s{KBCLM!v&-Vjy}>h<7*C%CI&C?*^G3Vo?Ib=)r;&=C z))7ghw&jlPS(2$mlJcJTnvD49U&fL5oa!v-s_Zcg$*oc@#+Go!Fq4XTHsK_{7E<^u z5w_y%V70b7XI{K8nE5B0EwK9wqUZEowHNLi(vA$7Px=;MCIrAMHf>$Q5r#;4?Q!PfqafX4k>JpdXc7UPp@Z}!zAt&9jv@Pn z&j&o&M8oP+hT}SWZ~V6nR_$5@?H-u!d28GAH>4h4zgfQ;p}-pVtN6|DZd!(3naUzv zsWF0Q8FMpZL|Ve{@FCzy+{bY(oe!LVoJRwuF|}`}VOrP%C!&0u9A5m2EUGBw47)+B96+G) zlE08W^HJOL7Xi2L+I4k0J8da3cxVDOGS6964A3`~cIS#O2CXnORR_*_(DUq}y|PGilzA9;>Ly_aznBFUJ!Sb4yRq3eqwKmU$SIJ}sg z=5PwreW#20OgpkGH$%muu{56F>67q1lJhXCw(b?%aizgWr_HYf`w{2RcOM{qF;L_< zSzG^%AkNqgqGUISJsG!aL+md^;~27;_px&RoLcs4dzQz`uQGW%C+^)vOJQ)q`6RjndW?!$4765OvcW-Z_L))n@$@&OEEF&?|5Pay3#t6NeyplLRphqWmor| zWJ0Ty3kmiws29QE*|+GTngvqH!6i*P7HmQFPNZn%u}7XzxwYJz6YUru6@s<+(+EnV zJ5y!@^b)J zix?&TDEJi@6GHT9=65w3>PhTz7<{LX8XHJCxaf_$0l^*G6q`wuBu_ReE4t#Z$YN8# zzCs3mc|URqX3Evj-V=7iZ&HwFh(cBDC;~4eSVJ`6?XA$Hb#b24?}?I-8;k`i2VCgx zuoe5aFW3&F!T!F2O_G3^ z(RV7;ci_*SNUh6JTfOwMsuvTL4#V5Bo2`=<^_&BsfrJcan8jK9aDGm$+2I|jlAN0N{ECYd^fB209|BeX-`(9b9elk zFN&Y9sblD4ry!h}W{bHxuuk3mbZ<7Ki?RsWIi@$#(dJ1E@NV>Pt=bj4WVc}6OKR8ito9A&aY+=OXE#fNDZ>c6RI z*Xz38q+*tQS{6>wb=#raJYWG4$g?>#)d=aVQUgNDVa*w#gV@%9BxqNP!PlFUq8+Vn zm@)+GP7Jr(t48a5N89A4>U4GZ@^O^v>(S?S?#ZrO%`E1>UT%cU==%HZNeC&yw0<_w z5>#Zo;dI3-w#Mo;gn_|%-_I9SVBZR3Y??G!rw~C~{b3NVBtSVWN?1Rd8n|am(L`A4 zcL<2xwO#8S?~i>WCy4WnuW8w}D0#%BrZHpvzBonq_oF9dsNHJq@d7au9*BKY(7S)` z!X|Q{F2>;Zk*LEk9@T~Xh*h5Vu*Df?-9rYXQ%It4N2+xFEVAXkZ~6nfs9FeYbEg*? z#G%#1#aQtHlI>McYjNFU=oVEpi(S2NcL|7|V|H!fsuCgdV110zx?^j;!Lai~*Nd42 z(7A0!1624NBXb4JQKRE;@KMr8VW$LYl*W2NZT5w2js!wC6a6btJS!LHqP%qaoNZ`x zoFp&6FOqm8hf((0#kb~s=Bx$ZZz8Rd8C}Mw9ys5${@WS!Tetc?q&~MRO7Vzf`5iIF zxr!cD5?PzrdA6)sXQ?k5ulj)uNZ?plnQ(ilo7poWqK08L_Y+4*o`SM zUn2K?EmJ2eOztrLnpkaih#Jdyz&W4x_N`C1rCBqFpVKHVrId4{%vZ321r;mB3)>uk zo+eJJc=ba4{Qa+3gaK?ftN=v+X7V+CrfHSv0kB(&D37yIoGNCxl7g({K<9S?>jL4G z?RBznap(PPIn2Xb*e=nYtD#wBr@+)MqUis&x1x$pv>Q>BcxOO`HkNiT8~a*mg8 zu!(JK9igAEz#8Os2#J0uJ!s$pl3CFUl_Cdr783xrZ}zwu`y}?M`w%rN9iY-o+1W+v zq0WVEQRz=VDrdFXn^SWI*fVuT-m3x0c<4J!fXG`A+b%0p@fu_1f@BxV4Qq`w82$H5 zae%ZlRTava_PSijM7GO=9AN+84J0#S+x=TNNes(*o2rihYW45n(V8V}m;x&81NuxT z^$RGI|TwuicFLa~l~MXk8cG?;tE=EF3vO`muC!)V!~ zbwO?s$0ZKzA9ANXpr%?nbpP>Y;ld=eWkY_47{x(Ue0ingEruOpJF3s~MU8xzR;-o! z=L^w#%9VTJ*hKQb&ZR7Gp*+Xp-vS~|%KtOVma6)1=nXsa_7BSgPCOWP%8d$(nR@W! c(G70LhuF@+PuCgP;XE95HEq>ugbnI{05T)W5dZ)H literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/coupled_stripline_dark.png b/resources/bitmaps_png/png/coupled_stripline_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..34f7f7fe6e67bd5f3d9fa41611def8e7f58c6c19 GIT binary patch literal 10179 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 literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/sources/dark/coupled_stripline.svg b/resources/bitmaps_png/sources/dark/coupled_stripline.svg new file mode 100644 index 0000000000..5169de991b --- /dev/null +++ b/resources/bitmaps_png/sources/dark/coupled_stripline.svg @@ -0,0 +1,834 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T + + H + + + + + L + + + + + + + + + + + + W + S + + + + + + + + + + + + + + + + diff --git a/resources/bitmaps_png/sources/light/coupled_stripline.svg b/resources/bitmaps_png/sources/light/coupled_stripline.svg new file mode 100644 index 0000000000..110eb6629e --- /dev/null +++ b/resources/bitmaps_png/sources/light/coupled_stripline.svg @@ -0,0 +1,834 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T + + H + + + + + L + + + + + + + + + + + + W + S + + + + + + + + + + + + + + + +