/* * 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 }; }