From 8de6aa161fe9e02e6265c7510915b71ff07fb41a Mon Sep 17 00:00:00 2001 From: Fabien Corona Date: Fri, 7 Aug 2020 00:09:33 +0000 Subject: [PATCH] pcb_calculator : do not overwrite input parameters Split the computing / displaying code into different functions Add coloured warnings when a value is not finite / illogical . Fixes https://gitlab.com/kicad/code/kicad/-/issues/1849 --- pcb_calculator/params_read_write.cpp | 131 +++-- pcb_calculator/pcb_calculator.h | 73 +-- pcb_calculator/transline/c_microstrip.cpp | 652 +++++++++------------ pcb_calculator/transline/c_microstrip.h | 75 ++- pcb_calculator/transline/coax.cpp | 295 +++++----- pcb_calculator/transline/coax.h | 32 +- pcb_calculator/transline/coplanar.cpp | 313 +++++----- pcb_calculator/transline/coplanar.h | 32 +- pcb_calculator/transline/microstrip.cpp | 363 +++++------- pcb_calculator/transline/microstrip.h | 56 +- pcb_calculator/transline/rectwaveguide.cpp | 273 +++++---- pcb_calculator/transline/rectwaveguide.h | 44 +- pcb_calculator/transline/stripline.cpp | 238 ++++---- pcb_calculator/transline/stripline.h | 28 +- pcb_calculator/transline/transline.cpp | 276 ++++++++- pcb_calculator/transline/transline.h | 110 +++- pcb_calculator/transline/twistedpair.cpp | 272 +++++---- pcb_calculator/transline/twistedpair.h | 27 +- pcb_calculator/transline_dlg_funct.cpp | 24 +- pcb_calculator/transline_ident.cpp | 152 ++--- 20 files changed, 1803 insertions(+), 1663 deletions(-) diff --git a/pcb_calculator/params_read_write.cpp b/pcb_calculator/params_read_write.cpp index e1f0f5585a..456dfaf5a2 100644 --- a/pcb_calculator/params_read_write.cpp +++ b/pcb_calculator/params_read_write.cpp @@ -19,11 +19,12 @@ */ #include -#include +#include #include +#include -#include #include +#include #include /* @@ -39,8 +40,8 @@ double DoubleFromString( const wxString& TextValue ) double value = 0; /* Acquire the 'right' decimal point separator */ - const struct lconv* lc = localeconv(); - wxChar decimal_point = lc->decimal_point[0]; + const struct lconv* lc = localeconv(); + wxChar decimal_point = lc->decimal_point[0]; wxString buf( TextValue.Strip( wxString::both ) ); /* Convert the period in decimal point */ @@ -56,17 +57,25 @@ double DoubleFromString( const wxString& TextValue ) while( brk_point < buf.Len() ) { wxChar ch = buf[brk_point]; - if( !( (ch >= '0' && ch <='9') || (ch == decimal_point) - || (ch == '-') || (ch == '+') || (ch == 'e') || (ch == 'E') ) ) + if( !( ( ch >= '0' && ch <= '9' ) || ( ch == decimal_point ) || ( ch == '-' ) + || ( ch == '+' ) || ( ch == 'e' ) || ( ch == 'E' ) ) ) { break; } ++brk_point; } - /* Extract the numeric part */ - buf.Left( brk_point ).ToDouble( &value ); + // Check for strings that cannot qualify as a number + if( brk_point == 0 ) + { + return std::nan( "" ); + } + /* Extract the numeric part */ + if( !buf.Left( brk_point ).ToDouble( &value ) ) + { + return std::nan( "" ); + } return value; } @@ -76,16 +85,22 @@ double DoubleFromString( const wxString& TextValue ) // depend on Graphic User Interface void SetPropertyInDialog( enum PRMS_ID aPrmId, double value ) { - PCB_CALCULATOR_FRAME * frame = (PCB_CALCULATOR_FRAME *) wxTheApp->GetTopWindow(); + PCB_CALCULATOR_FRAME* frame = (PCB_CALCULATOR_FRAME*) wxTheApp->GetTopWindow(); frame->SetPrmValue( aPrmId, value ); } +void SetPropertyBgColorInDialog( enum PRMS_ID aPrmId, const KIGFX::COLOR4D* aCol ) +{ + PCB_CALCULATOR_FRAME* frame = (PCB_CALCULATOR_FRAME*) wxTheApp->GetTopWindow(); + frame->SetPrmBgColor( aPrmId, aCol ); +} + /* Puts the text into the given result line. */ void SetResultInDialog( int line, const char* aText ) { - PCB_CALCULATOR_FRAME * frame = (PCB_CALCULATOR_FRAME *) wxTheApp->GetTopWindow(); - wxString msg = wxString::FromUTF8( aText ); + PCB_CALCULATOR_FRAME* frame = (PCB_CALCULATOR_FRAME*) wxTheApp->GetTopWindow(); + wxString msg = wxString::FromUTF8( aText ); frame->SetResult( line, msg ); } @@ -93,10 +108,10 @@ void SetResultInDialog( int line, const char* aText ) */ void SetResultInDialog( int aLineNumber, double aValue, const char* aText ) { - PCB_CALCULATOR_FRAME * frame = (PCB_CALCULATOR_FRAME *) wxTheApp->GetTopWindow(); - wxString msg = wxString::FromUTF8( aText ); - wxString fullmsg; - fullmsg.Printf( wxT("%g "), aValue ); + PCB_CALCULATOR_FRAME* frame = (PCB_CALCULATOR_FRAME*) wxTheApp->GetTopWindow(); + wxString msg = wxString::FromUTF8( aText ); + wxString fullmsg; + fullmsg.Printf( wxT( "%g " ), aValue ); fullmsg += msg; frame->SetResult( aLineNumber, fullmsg ); } @@ -104,15 +119,15 @@ void SetResultInDialog( int aLineNumber, double aValue, const char* aText ) /* Returns a named property value. */ double GetPropertyInDialog( enum PRMS_ID aPrmId ) { - PCB_CALCULATOR_FRAME * frame = (PCB_CALCULATOR_FRAME *) wxTheApp->GetTopWindow(); + PCB_CALCULATOR_FRAME* frame = (PCB_CALCULATOR_FRAME*) wxTheApp->GetTopWindow(); return frame->GetPrmValue( aPrmId ); } // Returns true if the param aPrmId is selected // Has meaning only for params that have a radio button -bool IsSelectedInDialog( enum PRMS_ID aPrmId ) +bool IsSelectedInDialog( enum PRMS_ID aPrmId ) { - PCB_CALCULATOR_FRAME * frame = (PCB_CALCULATOR_FRAME *) wxTheApp->GetTopWindow(); + PCB_CALCULATOR_FRAME* frame = (PCB_CALCULATOR_FRAME*) wxTheApp->GetTopWindow(); return frame->IsPrmSelected( aPrmId ); } @@ -132,8 +147,6 @@ double PCB_CALCULATOR_FRAME::GetPrmValue( enum PRMS_ID aPrmId ) if( aPrmId == prm->m_Id ) return prm->m_NormalizedValue; } - - wxLogMessage( wxT("GetPrmValue: prm %d not found"), (int) aPrmId ); return 1.0; } @@ -149,19 +162,52 @@ void PCB_CALCULATOR_FRAME::SetPrmValue( enum PRMS_ID aPrmId, double aValue ) for( unsigned ii = 0; ii < tr_ident->GetPrmsCount(); ii++ ) { TRANSLINE_PRM* prm = tr_ident->GetPrm( ii ); + if( aPrmId == prm->m_Id ) { - prm->m_Value = prm->m_NormalizedValue = aValue; - prm->m_NormalizedValue = aValue; - prm->m_Value = prm->m_NormalizedValue * prm->ToUserUnit(); + prm->m_NormalizedValue = aValue; + prm->m_Value = prm->m_NormalizedValue * prm->ToUserUnit(); wxString msg; - msg.Printf( wxT("%g"), prm->m_Value); - ((wxTextCtrl*)prm->m_ValueCtrl )->SetValue( msg ); + msg.Printf( wxT( "%g" ), prm->m_Value ); + ( (wxTextCtrl*) prm->m_ValueCtrl )->SetValue( msg ); return; } } + wxLogMessage( wxT( "GetPrmValue: prm %d not found" ), (int) aPrmId ); +} - wxLogMessage( wxT("GetPrmValue: prm %d not found"), (int) aPrmId ); +/** + * Function SetPrmBgColor + * Set the background color for a given parameter + * @param aPrmId = @ref PRMS_ID of the parameter + * @param aCol = color ( @ref KIGFX::COLOR4D * ) + */ +void PCB_CALCULATOR_FRAME::SetPrmBgColor( enum PRMS_ID aPrmId, const KIGFX::COLOR4D* aCol ) +{ + wxColour wxcol = wxColour( static_cast( aCol->r * 255 ), + static_cast( aCol->g * 255 ), + static_cast( aCol->b * 255 ) ); + + if( !wxcol.IsOk() ) + { + return; + } + + TRANSLINE_IDENT* tr_ident = m_transline_list[m_currTransLineType]; + + for( unsigned ii = 0; ii < tr_ident->GetPrmsCount(); ii++ ) + { + TRANSLINE_PRM* prm = tr_ident->GetPrm( ii ); + wxTextCtrl* ctl = static_cast( prm->m_ValueCtrl ); + + if( aPrmId == prm->m_Id ) + { + ctl->SetBackgroundColour( wxcol ); + ctl->SetStyle( 0, -1, ctl->GetDefaultStyle() ); + return; + } + + } } /** @@ -170,13 +216,13 @@ void PCB_CALCULATOR_FRAME::SetPrmValue( enum PRMS_ID aPrmId, double aValue ) * @param aLineNumber = the line (0 to MSG_CNT_MAX-1) wher to display the text * @param aText = the text to display */ -void PCB_CALCULATOR_FRAME::SetResult( int aLineNumber, const wxString & aText ) +void PCB_CALCULATOR_FRAME::SetResult( int aLineNumber, const wxString& aText ) { #define MSG_CNT_MAX 7 - wxStaticText * messages[MSG_CNT_MAX] = + wxStaticText* messages[MSG_CNT_MAX] = { m_Message1, m_Message2, m_Message3, m_Message4, m_Message5, m_Message6, - m_Message7 + m_Message7 }; wxASSERT( ( aLineNumber >= 0 ) && ( aLineNumber < MSG_CNT_MAX ) ); @@ -184,7 +230,7 @@ void PCB_CALCULATOR_FRAME::SetResult( int aLineNumber, const wxString & aText ) if( aLineNumber < 0 ) aLineNumber = 0; if( aLineNumber >= MSG_CNT_MAX ) - aLineNumber = MSG_CNT_MAX-1; + aLineNumber = MSG_CNT_MAX - 1; messages[aLineNumber]->SetLabel( aText ); } @@ -194,24 +240,23 @@ void PCB_CALCULATOR_FRAME::SetResult( int aLineNumber, const wxString & aText ) * @return true if the param aPrmId is selected * Has meaning only for params that have a radio button */ -bool PCB_CALCULATOR_FRAME::IsPrmSelected( enum PRMS_ID aPrmId ) +bool PCB_CALCULATOR_FRAME::IsPrmSelected( enum PRMS_ID aPrmId ) { switch( aPrmId ) { - default: - wxMessageBox( wxT("IsPrmSelected() error") ); - break; + default: + wxMessageBox( wxT( "IsPrmSelected() error" ) ); + break; - case PHYS_WIDTH_PRM: - case PHYS_DIAM_IN_PRM: - return m_radioBtnPrm1->GetValue(); - break; + case PHYS_WIDTH_PRM: + case PHYS_DIAM_IN_PRM: + return m_radioBtnPrm1->GetValue(); + break; - case PHYS_S_PRM: - case PHYS_DIAM_OUT_PRM: - return m_radioBtnPrm2->GetValue(); - break; + case PHYS_S_PRM: + case PHYS_DIAM_OUT_PRM: + return m_radioBtnPrm2->GetValue(); + break; } return false; } - diff --git a/pcb_calculator/pcb_calculator.h b/pcb_calculator/pcb_calculator.h index aa08e3270a..d11c424334 100644 --- a/pcb_calculator/pcb_calculator.h +++ b/pcb_calculator/pcb_calculator.h @@ -21,15 +21,15 @@ * @file pcb_calculator.h */ -#ifndef PCB_CALCULATOR_H -#define PCB_CALCULATOR_H +#ifndef PCB_CALCULATOR_H +#define PCB_CALCULATOR_H #include -#include // Included for SUBST_PRMS_ID definition. -#include #include #include +#include // Included for SUBST_PRMS_ID definition. +#include extern const wxString PcbCalcDataFileExt; @@ -42,29 +42,28 @@ public: REGULATOR_LIST m_RegulatorList; // the list of known regulator private: - bool m_RegulatorListChanged; // set to true when m_RegulatorList - // was modified, and the corresponging file - // must be rewritten + bool m_RegulatorListChanged; // set to true when m_RegulatorList + // was modified, and the corresponging file + // must be rewritten - enum // Which dimension is controlling the track - { // width / current calculations: - TW_MASTER_CURRENT, // the maximum current, - TW_MASTER_EXT_WIDTH, // the external trace width, - TW_MASTER_INT_WIDTH // or the internal trace width? + enum // Which dimension is controlling the track + { // width / current calculations: + TW_MASTER_CURRENT, // the maximum current, + TW_MASTER_EXT_WIDTH, // the external trace width, + TW_MASTER_INT_WIDTH // or the internal trace width? } m_TWMode; - bool m_TWNested; // Used to stop events caused by setting the answers. + bool m_TWNested; // Used to stop events caused by setting the answers. enum TRANSLINE_TYPE_ID m_currTransLineType; - TRANSLINE * m_currTransLine; // a pointer to the active transline + TRANSLINE* m_currTransLine; // a pointer to the active transline // List of translines: ordered like in dialog menu list - std::vector m_transline_list; + std::vector m_transline_list; - ATTENUATOR * m_currAttenuator; + ATTENUATOR* m_currAttenuator; // List ofattenuators: ordered like in dialog menu list - std::vector m_attenuator_list; - wxString m_lastSelectedRegulatorName; // last regulator name selected - + std::vector m_attenuator_list; + wxString m_lastSelectedRegulatorName; // last regulator name selected public: @@ -72,7 +71,6 @@ public: ~PCB_CALCULATOR_FRAME(); private: - // Event handlers void OnClosePcbCalc( wxCloseEvent& event ) override; @@ -99,7 +97,7 @@ private: * force the standard extension of the file (.pcbcalc) * @param aFilename = the full filename, with or without extension */ - void SetDataFilename( const wxString & aFilename); + void SetDataFilename( const wxString& aFilename ); // Trace width / maximum current capability calculations. @@ -154,23 +152,23 @@ private: * Function TWCalculateWidth * Calculate track width required based on given current and temperature rise. */ - double TWCalculateWidth( double aCurrent, double aThickness, double aDeltaT_C, - bool aUseInternalLayer ); + double TWCalculateWidth( + double aCurrent, double aThickness, double aDeltaT_C, bool aUseInternalLayer ); /** * Function TWCalculateCurrent * Calculate maximum current based on given width and temperature rise. */ - double TWCalculateCurrent( double aWidth, double aThickness, double aDeltaT_C, - bool aUseInternalLayer ); + double TWCalculateCurrent( + double aWidth, double aThickness, double aDeltaT_C, bool aUseInternalLayer ); /** * Function TWDisplayValues * Displays the results of a calculation (including resulting values such * as the resistance and power loss). */ - void TWDisplayValues( double aCurrent, double aExtWidth, double aIntWidth, - double aExtThickness, double aIntThickness ); + void TWDisplayValues( double aCurrent, double aExtWidth, double aIntWidth, double aExtThickness, + double aIntThickness ); /** * Function TWUpdateModeDisplay @@ -226,8 +224,8 @@ private: * Displays the results of the calculation. */ void VSDisplayValues( double aViaResistance, double aVoltageDrop, double aPowerLoss, - double aEstimatedAmpacity, double aThermalResistance, double aCapacitance, - double aTimeDegradation, double aInductance, double aReactance ); + double aEstimatedAmpacity, double aThermalResistance, double aCapacitance, + double aTimeDegradation, double aInductance, double aReactance ); // Electrical spacing panel: void OnElectricalSpacingUnitsSelection( wxCommandEvent& event ) override; @@ -358,8 +356,14 @@ public: * @param aLineNumber = the line (0 to 5) wher to display the text * @param aText = the text to display */ - void SetResult( int aLineNumber, const wxString & aText ); + void SetResult( int aLineNumber, const wxString& aText ); + /** Function SetPrgmBgColor + * Set the background color of a parameter + * @param aPrmId = param id to set + * @param aCol = new color + */ + void SetPrmBgColor( enum PRMS_ID aPrmId, const KIGFX::COLOR4D* aCol ); /** * Function GetPrmValue * Returns a param value. @@ -373,17 +377,20 @@ public: * @return true if the param aPrmId is selected * Has meaning only for params that have a radio button */ - bool IsPrmSelected( enum PRMS_ID aPrmId ); + bool IsPrmSelected( enum PRMS_ID aPrmId ); // Board classes panel: void OnBoardClassesUnitsSelection( wxCommandEvent& event ) override; void BoardClassesUpdateData( double aUnitScale ); // Calculator doesn't host a tool framework - wxWindow* GetToolCanvas() const override { return nullptr; } + wxWindow* GetToolCanvas() const override + { + return nullptr; + } }; extern const wxString DataFileNameExt; -#endif // PCB_CALCULATOR_H +#endif // PCB_CALCULATOR_H diff --git a/pcb_calculator/transline/c_microstrip.cpp b/pcb_calculator/transline/c_microstrip.cpp index a21800ab3f..4d63b60ba0 100644 --- a/pcb_calculator/transline/c_microstrip.cpp +++ b/pcb_calculator/transline/c_microstrip.cpp @@ -31,43 +31,16 @@ #include #include -#include -#include -#include #include +#include +#include +#include C_MICROSTRIP::C_MICROSTRIP() : TRANSLINE() { m_Name = "Coupled_MicroStrip"; aux_ms = NULL; - - // Initialize these variables mainly to avoid warnings from a static analyzer - 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 - 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 conductors losses (dB) - atten_cond_o = 0.0; // odd-mode conductors losses (dB) + Init(); } @@ -99,6 +72,7 @@ double C_MICROSTRIP::delta_u_thickness_single( double u, double t_h ) 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 { @@ -122,16 +96,16 @@ 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 = er; - u = w / h; /* normalized line width */ - g = s / h; /* normalized line spacing */ - t_h = t / h; /* normalized strip thickness */ + 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); + 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; @@ -141,8 +115,8 @@ void C_MICROSTRIP::delta_u_thickness() delta_u_e = delta_u_o = 0.0; } - w_t_e = w + delta_u_e * h; - w_t_o = w + delta_u_o * h; + 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]; } @@ -155,15 +129,15 @@ void C_MICROSTRIP::compute_single_line() aux_ms = new MICROSTRIP(); /* prepare parameters for single microstrip computations */ - aux_ms->er = er; - aux_ms->w = w; - aux_ms->h = h; - aux_ms->t = 0.0; + 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->t = t; - aux_ms->ht = 1e12; /* arbitrarily high */ - aux_ms->m_freq = m_freq; - aux_ms->m_murC = m_murC; + //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(); } @@ -177,15 +151,15 @@ 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 ); + 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 ); + 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 ); + q_inf = pow( ( 1.0 + 10.0 / v ), -a_e * b_e ); return q_inf; } @@ -197,8 +171,8 @@ double C_MICROSTRIP::filling_factor_even( double u, double g, double e_r ) */ 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 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 */ @@ -239,7 +213,7 @@ double C_MICROSTRIP::delta_q_cover_odd( double h2h ) if( h2h <= 7 ) { - q_c = tanh( 9.575 / (7.0 - h2h) - 2.965 + 1.68 * h2h - 0.311 * h2h * h2h ); + q_c = tanh( 9.575 / ( 7.0 - h2h ) - 2.965 + 1.68 * h2h - 0.311 * h2h * h2h ); } else { @@ -263,17 +237,20 @@ 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 = ht; - u_t_e = w_t_e / h; /* normalized even_mode line width */ - u_t_o = w_t_o / h; /* normalized odd_mode line width */ - g = s / h; /* normalized line spacing */ - h2h = h2 / h; /* normalized cover height */ - t_h = t / h; /* normalized strip thickness */ + 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 ); @@ -282,9 +259,9 @@ void C_MICROSTRIP::er_eff_static() /* thickness effect */ q_t = aux_ms->delta_q_thickness( u_t_e, t_h ); /* resultant filling factor */ - q = (q_inf - q_t) * q_c; + 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; + 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 ); @@ -293,12 +270,12 @@ void C_MICROSTRIP::er_eff_static() /* thickness effect */ q_t = aux_ms->delta_q_thickness( u_t_o, t_h ); /* resultant filling factor */ - q = (q_inf - q_t) * q_c; + 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 ) ); + 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; + er_eff_o_0 = ( 0.5 * ( er + 1.0 ) + a_o - er_eff_single ) * q + er_eff_single; } @@ -317,14 +294,14 @@ double C_MICROSTRIP::delta_Z0_even_cover( double g, double u, double h2h ) 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 ); + 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) ) ); + g_e = 270.0 * ( 1.0 - tanh( D + E * sqrt( 1.0 + h2h ) - F / ( 1.0 + h2h ) ) ); delta_Z0_even = f_e * g_e; @@ -364,7 +341,7 @@ double C_MICROSTRIP::delta_Z0_odd_cover( double g, double u, double h2h ) { L = 2.674; } - g_o = 270.0 * ( 1.0 - tanh( G + K * sqrt( 1.0 + h2h ) - L / (1.0 + h2h) ) ); + g_o = 270.0 * ( 1.0 - tanh( G + K * sqrt( 1.0 + h2h ) - L / ( 1.0 + h2h ) ) ); delta_Z0_odd = f_o * g_o; @@ -387,11 +364,11 @@ void C_MICROSTRIP::Z0_even_odd() 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 = ht; - u_t_e = w_t_e / h; /* normalized even-mode line width */ - u_t_o = w_t_o / h; /* normalized odd-mode line width */ - g = s / h; /* normalized line spacing */ - h2h = h2 / h; /* normalized cover height */ + 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; @@ -400,16 +377,13 @@ void C_MICROSTRIP::Z0_even_odd() 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 ) ) ); + 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); + 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 ); @@ -418,17 +392,16 @@ void C_MICROSTRIP::Z0_even_odd() /* 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; + 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); + 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 ); @@ -446,41 +419,42 @@ void C_MICROSTRIP::er_eff_freq() double F_e, F_o; double er_eff, u, g, f_n; - u = w / h; /* normalize line width */ - g = s / h; /* normalize line spacing */ + 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_freq * h / 1e06; + 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 * er ) ); - 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( er / 15.916, 8.0 ) ) ); - P_5 = 0.334 * exp( -3.3 * pow( er / 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 ) ); + 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 ); + 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 = er - (er - er_eff) / (1.0 + F_e); + er_eff_e = m_parameters[EPSILONR_PRM] - ( m_parameters[EPSILONR_PRM] - er_eff ) / ( 1.0 + F_e ); er_eff = er_eff_o_0; - P_8 = 0.7168 * ( 1.0 + 1.076 / ( 1.0 + 0.0576 * (er - 1.0) ) ); - P_9 = P_8 - 0.7913 * - ( 1.0 - exp( -pow( f_n / 20.0, 1.424 ) ) ) * atan( 2.481 * pow( er / 8.0, 0.946 ) ); - P_10 = 0.242 * pow( er - 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_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 ); + 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 ); + 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 = er - (er - er_eff) / (1.0 + F_o); + er_eff_o = m_parameters[EPSILONR_PRM] - ( m_parameters[EPSILONR_PRM] - er_eff ) / ( 1.0 + F_o ); } @@ -495,36 +469,42 @@ void C_MICROSTRIP::conductor_losses() 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_skindepth; + 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_freq > 0.0 ) + 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 ) ); + K = exp( -1.2 * pow( ( Z0_h_e + Z0_h_o ) / ( 2.0 * ZF0 ), 0.7 ) ); /* skin resistance */ - R_s = 1.0 / (m_sigma * delta); + 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( (rough / delta), 2.0 ) ) ); + 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 * w * m_freq) / (R_s * C0 * K); + 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 unith length */ - alpha_c_e = ( 20.0 * M_PI / log( 10.0 ) ) * m_freq * sqrt( e_r_eff_e_0 ) / (C0 * Q_c_e); + 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 * w * m_freq) / (R_s * C0 * K); + 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 unith length */ - alpha_c_o = ( 20.0 * M_PI / log( 10.0 ) ) * m_freq * sqrt( e_r_eff_o_0 ) / (C0 * Q_c_o); + 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 * l; - atten_cond_o = alpha_c_o * l; + atten_cond_e = alpha_c_e * m_parameters[PHYS_LEN_PRM]; + atten_cond_o = alpha_c_o * m_parameters[PHYS_LEN_PRM]; } @@ -537,21 +517,19 @@ 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 = er; + 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_freq / C0) * ( e_r / sqrt( e_r_eff_e_0 ) ) * ( (e_r_eff_e_0 - 1.0) / (e_r - 1.0) ) * m_tand; - alpha_d_o = - ( 20.0 * M_PI / - log( 10.0 ) ) * - (m_freq / C0) * ( e_r / sqrt( e_r_eff_o_0 ) ) * ( (e_r_eff_o_0 - 1.0) / (e_r - 1.0) ) * m_tand; + 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 * l; - atten_dielectric_o = alpha_d_o * l; + atten_dielectric_e = alpha_d_e * m_parameters[PHYS_LEN_PRM]; + atten_dielectric_o = alpha_d_o * m_parameters[PHYS_LEN_PRM]; } @@ -561,7 +539,7 @@ void C_MICROSTRIP::dielectric_losses() */ void C_MICROSTRIP::attenuation() { - m_skindepth = skin_depth(); + m_parameters[SKIN_DEPTH_PRM] = skin_depth(); conductor_losses(); dielectric_losses(); } @@ -583,38 +561,33 @@ void C_MICROSTRIP::line_angle() /* odd-mode velocity */ v_o = C0 / sqrt( e_r_eff_o ); /* even-mode wavelength */ - lambda_g_e = v_e / m_freq; + lambda_g_e = v_e / m_parameters[FREQUENCY_PRM]; /* odd-mode wavelength */ - lambda_g_o = v_o / m_freq; + lambda_g_o = v_o / m_parameters[FREQUENCY_PRM]; /* electrical angles */ - ang_l_e = 2.0 * M_PI * l / lambda_g_e; /* in radians */ - ang_l_o = 2.0 * M_PI * l / lambda_g_o; /* in radians */ + 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 */ } -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 ) +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 ); + 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) ); + *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 ); + *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 ); + *f2 += ( 1.0 / M_PI ) * acosh( 1.0 + 2.0 * w_h / s_h ); } *f1 -= w_h_se; @@ -636,45 +609,46 @@ void C_MICROSTRIP::synth_width() 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 = er; + f1 = f2 = 0; + e_r = m_parameters[EPSILONR_PRM]; - Z0 = Z0e / 2.0; + 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; + 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 = Z0o / 2.0; + 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; + 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 s/h */ - s_h = (2.0 / M_PI) * acosh( (ce + co - 2.0) / (co - ce) ); + /* 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; + w_h = acosh( ( ce * co - 1.0 ) / ( co - ce ) ) / M_PI - s_h / 2.0; - s = s_h * h; - w = w_h * h; + 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 beacuse the estimate of */ /* w_h is often quite far from the true value (see Akhtarzad S. et al.) */ - do { + 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; + 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; + 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); + 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); @@ -691,8 +665,8 @@ void C_MICROSTRIP::synth_width() } while( err > 1e-04 ); - s = s_h * h; - w = w_h * h; + m_parameters[PHYS_S_PRM] = s_h * m_parameters[H_PRM]; + m_parameters[PHYS_WIDTH_PRM] = w_h * m_parameters[H_PRM]; } @@ -711,62 +685,54 @@ void C_MICROSTRIP::Z0_dispersion() 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 = er; + e_r = m_parameters[EPSILONR_PRM]; - u = w / h; /* normalize line width */ - g = s / h; /* normalize line spacing */ + 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_freq * h / 1e06; + f_n = m_parameters[FREQUENCY_PRM] * m_parameters[H_PRM] / 1e06; e_r_eff_single_f = aux_ms->er_eff; e_r_eff_single_0 = aux_ms->er_eff_0; - Z0_single_f = aux_ms->Z0; + 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_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_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_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_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 ) ) ); + 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; + 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 ); @@ -774,42 +740,41 @@ void C_MICROSTRIP::Z0_dispersion() 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_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 ) ); + 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 */ - Z0e = 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 ); + 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); + 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_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 */ - Z0o = 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); + 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::calc() +void C_MICROSTRIP::calcAnalyze() { /* compute thickness corrections */ delta_u_thickness(); @@ -828,67 +793,62 @@ void C_MICROSTRIP::calc() } -/* - * get_microstrip_sub - * get and assign microstrip substrate parameters - * into microstrip structure - */ -void C_MICROSTRIP::get_c_microstrip_sub() +void C_MICROSTRIP::showAnalyze() { - er = getProperty( EPSILONR_PRM ); - m_murC = getProperty( MURC_PRM ); - h = getProperty( H_PRM ); - ht = getProperty( H_T_PRM ); - t = getProperty( T_PRM ); - m_sigma = 1.0/getProperty( RHO_PRM ); - m_tand = getProperty( TAND_PRM ); - rough = getProperty( ROUGH_PRM ); + 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 ) ); + + //Check for errors + if( !std::isfinite( m_parameters[Z0_O_PRM] ) || m_parameters[Z0_O_PRM] <= 0.0 ) + setErrorLevel( Z0_O_PRM, TRANSLINE_ERROR ); + + if( !std::isfinite( m_parameters[Z0_E_PRM] ) || m_parameters[Z0_E_PRM] <= 0.0 ) + setErrorLevel( Z0_E_PRM, TRANSLINE_ERROR ); + + 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 ); } - -/* - * get_c_microstrip_comp - * get and assign microstrip component parameters - * into microstrip structure - */ -void C_MICROSTRIP::get_c_microstrip_comp() +void C_MICROSTRIP::showSynthesize() { - m_freq = getProperty( FREQUENCY_PRM ); + 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] ); + + //Check for errors + if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0.0 ) + setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR ); + + if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0.0 ) + setErrorLevel( PHYS_S_PRM, TRANSLINE_ERROR ); + + if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] <= 0.0 ) + setErrorLevel( PHYS_LEN_PRM, TRANSLINE_ERROR ); + + // 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 ); + + if( !std::isfinite( m_parameters[ANG_L_PRM] ) || m_parameters[ANG_L_PRM] <= 0.0 ) + setErrorLevel( ANG_L_PRM, TRANSLINE_WARNING ); } - -/* - * get_c_microstrip_elec - * get and assign microstrip electrical parameters - * into microstrip structure - */ -void C_MICROSTRIP::get_c_microstrip_elec() -{ - Z0e = getProperty( Z0_E_PRM ); - Z0o = getProperty( Z0_O_PRM ); - ang_l_e = getProperty( ANG_L_PRM ); - ang_l_o = getProperty( ANG_L_PRM ); -} - - -/* - * get_c_microstrip_phys - * get and assign microstrip physical parameters - * into microstrip structure - */ -void C_MICROSTRIP::get_c_microstrip_phys() -{ - w = getProperty( PHYS_WIDTH_PRM ); - s = getProperty( PHYS_S_PRM ); - l = getProperty( PHYS_LEN_PRM ); -} - - void C_MICROSTRIP::show_results() { - setProperty( Z0_E_PRM, Z0e ); - setProperty( Z0_O_PRM , Z0o ); - setProperty( ANG_L_PRM, sqrt( ang_l_e * ang_l_o ) ); setResult( 0, er_eff_e, "" ); setResult( 1, er_eff_o, "" ); @@ -897,94 +857,65 @@ void C_MICROSTRIP::show_results() setResult( 4, atten_dielectric_e, "dB" ); setResult( 5, atten_dielectric_o, "dB" ); - setResult( 6, m_skindepth / UNIT_MICRON, "µm" ); + setResult( 6, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); } -/* - * analysis function - */ -void C_MICROSTRIP::analyze() +void C_MICROSTRIP::syn_fun( + double* f1, double* f2, double s_h, double w_h, double Z0_e, double Z0_o ) { - /* Get and assign substrate parameters */ - get_c_microstrip_sub(); - /* Get and assign component parameters */ - get_c_microstrip_comp(); - /* Get and assign physical parameters */ - get_c_microstrip_phys(); + 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 */ - calc(); - /* print results in the subwindow */ - show_results(); -} + calcAnalyze(); - -void C_MICROSTRIP::syn_fun( double* f1, - double* f2, - double s_h, - double w_h, - double Z0_e, - double Z0_o ) -{ - s = s_h * h; - w = w_h * h; - - /* compute coupled microstrip parameters */ - calc(); - - *f1 = Z0e - Z0_e; - *f2 = Z0o - Z0_o; + *f1 = m_parameters[Z0_E_PRM] - Z0_e; + *f2 = m_parameters[Z0_O_PRM] - Z0_o; } /* * synthesis function */ -void C_MICROSTRIP::synthesize() +void C_MICROSTRIP::calcSynthesize() { - double Z0_e, 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; - /* Get and assign substrate parameters */ - get_c_microstrip_sub(); - - /* Get and assign component parameters */ - get_c_microstrip_comp(); - - /* Get and assign electrical parameters */ - get_c_microstrip_elec(); - - /* Get and assign physical parameters */ - /* at present it is required only for getting strips length */ - get_c_microstrip_phys(); - /* required value of Z0_e and Z0_o */ - Z0_e = Z0e; - Z0_o = Z0o; + 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 = w / h; - s_h = s / h; - f1 = f2 = 0; + 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 { + do + { /* compute Jacobian */ syn_fun( &ft1, &ft2, s_h + eps, w_h, Z0_e, Z0_o ); - j11 = (ft1 - f1) / eps; - j21 = (ft2 - f2) / eps; + 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; + 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); + 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; @@ -997,21 +928,18 @@ void C_MICROSTRIP::synthesize() } while( err > 1e-04 ); /* denormalize computed width and spacing */ - s = s_h * h; - w = w_h * h; + m_parameters[PHYS_S_PRM] = s_h * m_parameters[H_PRM]; + m_parameters[PHYS_WIDTH_PRM] = w_h * m_parameters[H_PRM]; - setProperty( PHYS_WIDTH_PRM, w ); - setProperty( PHYS_S_PRM, s ); /* calculate physical length */ - ang_l_e = getProperty( ANG_L_PRM ); - ang_l_o = getProperty( ANG_L_PRM ); - le = C0 / m_freq / sqrt( er_eff_e ) * ang_l_e / 2.0 / M_PI; - lo = C0 / m_freq / sqrt( er_eff_o ) * ang_l_o / 2.0 / M_PI; - l = sqrt( le * lo ); - setProperty( PHYS_LEN_PRM, l ); + 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 ); - calc(); - /* print results in the subwindow */ - show_results(); + 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 01ee17c66c..44eb04791a 100644 --- a/pcb_calculator/transline/c_microstrip.h +++ b/pcb_calculator/transline/c_microstrip.h @@ -25,42 +25,42 @@ #ifndef _C_MICROSTRIP_H_ #define _C_MICROSTRIP_H_ +#include +#include + class C_MICROSTRIP : public TRANSLINE { -public: C_MICROSTRIP(); +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 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 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) - -public: - void analyze() override; - void synthesize() override; + 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 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 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) private: double delta_u_thickness_single( double, double ); @@ -82,12 +82,11 @@ private: void syn_err_fun( double*, double*, double, double, double, double, double ); void synth_width(); void Z0_dispersion(); - void calc(); - void get_c_microstrip_sub(); - void get_c_microstrip_comp(); - void get_c_microstrip_elec(); - void get_c_microstrip_phys(); - void show_results(); + 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 ); @@ -95,4 +94,4 @@ private: MICROSTRIP* aux_ms; }; -#endif // _C_MICROSTRIP_H_ +#endif // _C_MICROSTRIP_H_ diff --git a/pcb_calculator/transline/coax.cpp b/pcb_calculator/transline/coax.cpp index 94bda6347d..bc4a09ec1b 100644 --- a/pcb_calculator/transline/coax.cpp +++ b/pcb_calculator/transline/coax.cpp @@ -27,86 +27,26 @@ * coax.c - Puts up window for microstrip and * performs the associated calculations */ - - #include #include #include #include -#include -#include #include +#include COAX::COAX() : TRANSLINE() { m_Name = "Coax"; - - // Initialize these variables mainly to avoid warnings from a static analyzer - mur = 0.0; // magnetic permeability of substrate - din = 0.0; // Inner diameter of cable - dout = 0.0; // Outer diameter of cable - l = 0.0; // Length of cable - Z0 = 0.0; // characteristic impedance - ang_l = 0.0; // Electrical length in angle - atten_dielectric = 0.0; // Loss in dielectric (dB) - atten_cond = 0.0; // Loss in conductors (dB) - fc = 0.0; // Cutoff frequency for higher order modes + Init(); } - -/* - * get_coax_sub() - get and assign coax substrate parameters into coax - * structure - */ -void COAX::get_coax_sub() -{ - er = getProperty( EPSILONR_PRM ); - mur = getProperty( MUR_PRM ); - m_murC = getProperty( MURC_PRM ); - m_tand = getProperty( TAND_PRM ); - m_sigma = 1.0 / getProperty( RHO_PRM ); -} - - -/* - * get_coax_comp() - get and assign coax component parameters into - * coax structure - */ -void COAX::get_coax_comp() -{ - m_freq = getProperty( FREQUENCY_PRM ); -} - - -/* - * get_coax_elec() - get and assign coax electrical parameters into - * coax structure - */ -void COAX::get_coax_elec() -{ - Z0 = getProperty( Z0_PRM ); - ang_l = getProperty( ANG_L_PRM ); -} - - -/* - * get_coax_phys() - get and assign coax physical parameters into coax - * structure - */ -void COAX::get_coax_phys() -{ - din = getProperty( PHYS_DIAM_IN_PRM ); - dout = getProperty( PHYS_DIAM_OUT_PRM ); - l = getProperty( PHYS_LEN_PRM ); -} - - double COAX::alphad_coax() { double ad; - ad = (M_PI / C0) * m_freq * sqrt( er ) * m_tand; + ad = ( M_PI / C0 ) * m_parameters[FREQUENCY_PRM] * sqrt( m_parameters[EPSILONR_PRM] ) + * m_parameters[TAND_PRM]; ad = ad * 20.0 / log( 10.0 ); return ad; } @@ -116,133 +56,224 @@ double COAX::alphac_coax() { double ac, Rs; - Rs = sqrt( M_PI * m_freq * m_murC * MU0 / m_sigma ); - ac = sqrt( er ) * ( ( (1 / din) + (1 / dout) ) / log( dout / din ) ) * (Rs / ZF0); + Rs = sqrt( M_PI * m_parameters[FREQUENCY_PRM] * m_parameters[MURC_PRM] * MU0 + / m_parameters[SIGMA_PRM] ); + ac = sqrt( m_parameters[EPSILONR_PRM] ) + * ( ( ( 1 / m_parameters[PHYS_DIAM_IN_PRM] ) + ( 1 / m_parameters[PHYS_DIAM_OUT_PRM] ) ) + / log( m_parameters[PHYS_DIAM_OUT_PRM] / m_parameters[PHYS_DIAM_IN_PRM] ) ) + * ( Rs / ZF0 ); ac = ac * 20.0 / log( 10.0 ); return ac; } -/* - * analyze() - analysis function - */ -void COAX::analyze() +/** + * \f$ Z_0 = \frac{Z_{0_{\mathrm{vaccum}}}}{\sqrt{\epsilon_r}}\log_{10}\left( \frac{D_{\mathrm{out}}}{D_{\mathrm{in}}}\right) \f$ + * + * \f$ \lambda_g = \frac{c}{f \cdot \sqrt{ \epsilon_r \cdot \mu_r}} \f$ + * + * \f$ L_{[\mathrm{rad}]} = \frac{ 2\pi\cdot L_{[\mathrm{m}]}}{\lambda_g} \f$ + * */ +void COAX::calcAnalyze() { double lambda_g; - /* Get and assign substrate parameters */ - get_coax_sub(); - /* Get and assign component parameters */ - get_coax_comp(); + m_parameters[Z0_PRM] = + ( ZF0 / 2 / M_PI / sqrt( m_parameters[EPSILONR_PRM] ) ) + * log( m_parameters[PHYS_DIAM_OUT_PRM] / m_parameters[PHYS_DIAM_IN_PRM] ); - /* Get and assign physical parameters */ - get_coax_phys(); - - if( din != 0.0 ) - { - Z0 = ( ZF0 / 2 / M_PI / sqrt( er ) ) * log( dout / din ); - } - - lambda_g = ( C0 / (m_freq) ) / sqrt( er * mur ); + lambda_g = ( C0 / ( m_parameters[FREQUENCY_PRM] ) ) + / sqrt( m_parameters[EPSILONR_PRM] * m_parameters[MUR_PRM] ); /* calculate electrical angle */ - ang_l = (2.0 * M_PI * l) / lambda_g; /* in radians */ - - setProperty( Z0_PRM, Z0 ); - setProperty( ANG_L_PRM, ang_l ); - - show_results(); + m_parameters[ANG_L_PRM] = + ( 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] ) / lambda_g; /* in radians */ } -/* - * synthesize() - synthesis function - */ -void COAX::synthesize() +/** + * \f$ D_{\mathrm{in}} = D_{\mathrm{out}} \cdot e^{-\frac{Z_0*\sqrt{\epsilon_r}}{2\pi \cdot Z_{0_{\mathrm{vaccum}}}}} \f$ + * + * \f$ D_{\mathrm{out}} = D_{\mathrm{in}} \cdot e^{ \frac{Z_0*\sqrt{\epsilon_r}}{2\pi \cdot Z_{0_{\mathrm{vaccum}}}}} \f$ + * + * \f$ \lambda_g = \frac{c}{f \cdot \sqrt{ \epsilon_r \cdot \mu_r}} \f$ + * + * \f$ L_{[\mathrm{m}]} = \frac{ \lambda_g cdot L_{[\mathrm{m}]}}{2\pi} \f$ + * */ +void COAX::calcSynthesize() { double lambda_g; - /* Get and assign substrate parameters */ - get_coax_sub(); - - /* Get and assign component parameters */ - get_coax_comp(); - - /* Get and assign electrical parameters */ - get_coax_elec(); - - /* Get and assign physical parameters */ - get_coax_phys(); - if( isSelected( PHYS_DIAM_IN_PRM ) ) { /* solve for din */ - din = dout / exp( Z0 * sqrt( er ) / ZF0 * 2 * M_PI ); - setProperty( PHYS_DIAM_IN_PRM, din ); + m_parameters[PHYS_DIAM_IN_PRM] = + m_parameters[PHYS_DIAM_OUT_PRM] + / exp( m_parameters[Z0_PRM] * sqrt( m_parameters[EPSILONR_PRM] ) / ZF0 * 2 * M_PI ); } else if( isSelected( PHYS_DIAM_OUT_PRM ) ) { /* solve for dout */ - dout = din * exp( Z0 * sqrt( er ) / ZF0 * 2 * M_PI ); - setProperty( PHYS_DIAM_OUT_PRM, dout ); + m_parameters[PHYS_DIAM_OUT_PRM] = + m_parameters[PHYS_DIAM_IN_PRM] + * exp( m_parameters[Z0_PRM] * sqrt( m_parameters[EPSILONR_PRM] ) / ZF0 * 2 * M_PI ); } - lambda_g = ( C0 / (m_freq) ) / sqrt( er * mur ); + lambda_g = ( C0 / ( m_parameters[FREQUENCY_PRM] ) ) + / sqrt( m_parameters[EPSILONR_PRM] * m_parameters[MUR_PRM] ); /* calculate physical length */ - l = (lambda_g * ang_l) / (2.0 * M_PI); /* in m */ - setProperty( PHYS_LEN_PRM, l ); - - show_results(); + m_parameters[PHYS_LEN_PRM] = ( lambda_g * m_parameters[ANG_L_PRM] ) / ( 2.0 * M_PI ); /* in m */ } +void COAX::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 ); + } + + // Find warnings to display - physical parameters + if( !std::isfinite( m_parameters[PHYS_DIAM_IN_PRM] ) || m_parameters[PHYS_DIAM_IN_PRM] <= 0.0 ) + { + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_WARNING ); + } + + if( !std::isfinite( m_parameters[PHYS_DIAM_OUT_PRM] ) + || m_parameters[PHYS_DIAM_OUT_PRM] <= 0.0 ) + { + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_WARNING ); + } + + if( m_parameters[PHYS_DIAM_IN_PRM] > m_parameters[PHYS_DIAM_OUT_PRM] ) + { + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_WARNING ); + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_WARNING ); + } + + if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0.0 ) + { + setErrorLevel( PHYS_LEN_PRM, TRANSLINE_WARNING ); + } +} + +void COAX::showSynthesize() +{ + if( isSelected( PHYS_DIAM_IN_PRM ) ) + setProperty( PHYS_DIAM_IN_PRM, m_parameters[PHYS_DIAM_IN_PRM] ); + else if( isSelected( PHYS_DIAM_OUT_PRM ) ) + setProperty( PHYS_DIAM_OUT_PRM, m_parameters[PHYS_DIAM_OUT_PRM] ); + setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); + + // Check for errors + if( !std::isfinite( m_parameters[PHYS_DIAM_IN_PRM] ) || m_parameters[PHYS_DIAM_IN_PRM] <= 0.0 ) + { + if( isSelected( PHYS_DIAM_IN_PRM ) ) + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_ERROR ); + else + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_WARNING ); + } + + if( !std::isfinite( m_parameters[PHYS_DIAM_OUT_PRM] ) + || m_parameters[PHYS_DIAM_OUT_PRM] <= 0.0 ) + { + if( isSelected( PHYS_DIAM_OUT_PRM ) ) + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_ERROR ); + else + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_WARNING ); + } + + if( m_parameters[PHYS_DIAM_IN_PRM] > m_parameters[PHYS_DIAM_OUT_PRM] ) + { + if( isSelected( PHYS_DIAM_IN_PRM ) ) + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_ERROR ); + else if( isSelected( PHYS_DIAM_OUT_PRM ) ) + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_ERROR ); + } + + if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0.0 ) + { + setErrorLevel( PHYS_LEN_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 ); + } +} /* * show_results() - show results */ void COAX::show_results() { int m, n; - char text[256], txt[256]; + char text[256], txt[256]; - atten_dielectric = alphad_coax() * l; - atten_cond = alphac_coax() * l; + m_parameters[LOSS_DIELECTRIC_PRM] = alphad_coax() * m_parameters[PHYS_LEN_PRM]; + m_parameters[LOSS_CONDUCTOR_PRM] = alphac_coax() * m_parameters[PHYS_LEN_PRM]; - setResult( 0, er, "" ); - setResult( 1, atten_cond, "dB" ); - setResult( 2, atten_dielectric, "dB" ); + setResult( 0, m_parameters[EPSILONR_PRM], "" ); + setResult( 1, m_parameters[LOSS_CONDUCTOR_PRM], "dB" ); + setResult( 2, m_parameters[LOSS_DIELECTRIC_PRM], "dB" ); - n = 1; - fc = C0 / (M_PI * (dout + din) / (double) n); - if( fc > m_freq ) + n = 1; + m_parameters[CUTOFF_FREQUENCY_PRM] = + C0 + / ( M_PI * ( m_parameters[PHYS_DIAM_OUT_PRM] + m_parameters[MUR_PRM] ) / (double) n ); + if( m_parameters[CUTOFF_FREQUENCY_PRM] > m_parameters[FREQUENCY_PRM] ) strcpy( text, "none" ); else { strcpy( text, "H(1,1) " ); - m = 2; - fc = C0 / ( 2 * (dout - din) / (double) (m - 1) ); - while( (fc <= m_freq) && ( m < 10 ) ) + m = 2; + m_parameters[CUTOFF_FREQUENCY_PRM] = + C0 + / ( 2 * ( m_parameters[PHYS_DIAM_OUT_PRM] - m_parameters[MUR_PRM] ) + / (double) ( m - 1 ) ); + while( ( m_parameters[CUTOFF_FREQUENCY_PRM] <= m_parameters[FREQUENCY_PRM] ) && ( m < 10 ) ) { sprintf( txt, "H(n,%d) ", m ); strcat( text, txt ); m++; - fc = C0 / ( 2 * (dout - din) / (double) (m - 1) ); + m_parameters[CUTOFF_FREQUENCY_PRM] = + C0 + / ( 2 * ( m_parameters[PHYS_DIAM_OUT_PRM] - m_parameters[MUR_PRM] ) + / (double) ( m - 1 ) ); } } setResult( 3, text ); - m = 1; - fc = C0 / (2 * (dout - din) / (double) m); - if( fc > m_freq ) + m = 1; + m_parameters[CUTOFF_FREQUENCY_PRM] = + C0 / ( 2 * ( m_parameters[PHYS_DIAM_OUT_PRM] - m_parameters[MUR_PRM] ) / (double) m ); + if( m_parameters[CUTOFF_FREQUENCY_PRM] > m_parameters[FREQUENCY_PRM] ) strcpy( text, "none" ); else { strcpy( text, "" ); - while( (fc <= m_freq) && ( m < 10 ) ) + while( ( m_parameters[CUTOFF_FREQUENCY_PRM] <= m_parameters[FREQUENCY_PRM] ) && ( m < 10 ) ) { sprintf( txt, "E(n,%d) ", m ); strcat( text, txt ); m++; - fc = C0 / (2 * (dout - din) / (double) m); + m_parameters[CUTOFF_FREQUENCY_PRM] = + C0 + / ( 2 * ( m_parameters[PHYS_DIAM_OUT_PRM] - m_parameters[MUR_PRM] ) + / (double) m ); } } setResult( 4, text ); diff --git a/pcb_calculator/transline/coax.h b/pcb_calculator/transline/coax.h index 07a2d16ad8..e56c2551c8 100644 --- a/pcb_calculator/transline/coax.h +++ b/pcb_calculator/transline/coax.h @@ -25,35 +25,21 @@ #ifndef __COAX_H #define __COAX_H +#include + class COAX : public TRANSLINE { -public: COAX(); - -private: - double mur; // magnetic permeability of substrate - double din; // Inner diameter of cable - double dout; // Outer diameter of cable - double l; // Length of cable - double Z0; // characteristic impedance - double ang_l; // Electrical length in angle - double atten_dielectric; // Loss in dielectric (dB) - double atten_cond; // Loss in conductors (dB) - double fc; // Cutoff frequency for higher order modes - public: - void analyze() override; - void synthesize() override; + COAX(); private: - void get_coax_sub(); - void get_coax_comp(); - void get_coax_phys(); - void get_coax_elec(); - void fixdin(); - void fixdout(); + void calcAnalyze() override; + void calcSynthesize() override; + void showAnalyze() override; + void showSynthesize() override; double alphad_coax(); double alphac_coax(); - void show_results(); + void show_results() override; }; -#endif // __COAX_H +#endif // __COAX_H diff --git a/pcb_calculator/transline/coplanar.cpp b/pcb_calculator/transline/coplanar.cpp index 819a68dc6c..0c2db46261 100644 --- a/pcb_calculator/transline/coplanar.cpp +++ b/pcb_calculator/transline/coplanar.cpp @@ -28,105 +28,86 @@ #include #include -#include -#include #include +#include COPLANAR::COPLANAR() : TRANSLINE() { - m_Name = "CoPlanar"; + m_Name = "CoPlanar"; backMetal = false; - - // Initialize these variables mainly to avoid warnings from a static analyzer - h = 0.0; // height of substrate - t = 0.0; // thickness of top metal - w = 0.0; // width of line - s = 0.0; // width of gap between line and ground - len = 0.0; // length of line - Z0 = 0.0; // characteristic impedance - ang_l = 0.0; // Electrical length in angle - atten_dielectric = 0.0; // Loss in dielectric (dB) - atten_cond = 0.0; // Loss in conductors (dB) - er_eff = 1.0; // Effective dielectric constant + Init(); } GROUNDEDCOPLANAR::GROUNDEDCOPLANAR() : COPLANAR() { - m_Name = "GrCoPlanar"; + m_Name = "GrCoPlanar"; backMetal = true; } // ------------------------------------------------------------------- -void COPLANAR::getProperties() +void COPLANAR::calcAnalyze() { - m_freq = getProperty( FREQUENCY_PRM ); - w = getProperty( PHYS_WIDTH_PRM ); - s = getProperty( PHYS_S_PRM ); - len = getProperty( PHYS_LEN_PRM ); - h = getProperty( H_PRM ); - t = getProperty( T_PRM ); - - er = getProperty( EPSILONR_PRM ); - m_murC = getProperty( MURC_PRM ); - m_tand = getProperty( TAND_PRM ); - m_sigma = 1.0 / getProperty( RHO_PRM ); - Z0 = getProperty( Z0_PRM ); - ang_l = getProperty( ANG_L_PRM ); -} - - -// ------------------------------------------------------------------- -void COPLANAR::calc() -{ - m_skindepth = skin_depth(); + m_parameters[SKIN_DEPTH_PRM] = skin_depth(); // other local variables (quasi-static constants) double k1, kk1, kpk1, k2, k3, q1, q2, q3 = 0, qz, er0 = 0; double zl_factor; // compute the necessary quasi-static approx. (K1, K3, er(0) and Z(0)) - k1 = w / (w + s + s); + k1 = m_parameters[PHYS_WIDTH_PRM] + / ( m_parameters[PHYS_WIDTH_PRM] + m_parameters[PHYS_S_PRM] + m_parameters[PHYS_S_PRM] ); kk1 = ellipk( k1 ); kpk1 = ellipk( sqrt( 1 - k1 * k1 ) ); q1 = kk1 / kpk1; + // backside is metal if( backMetal ) { - k3 = tanh( (M_PI / 4) * (w / h) ) / tanh( (M_PI / 4) * (w + s + s) / h ); - q3 = ellipk( k3 ) / ellipk( sqrt( 1 - k3 * k3 ) ); - qz = 1 / (q1 + q3); - er0 = 1 + q3 * qz * (er - 1); + k3 = tanh( ( M_PI / 4 ) * ( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] ) ) + / tanh( ( M_PI / 4 ) + * ( m_parameters[PHYS_WIDTH_PRM] + m_parameters[PHYS_S_PRM] + + m_parameters[PHYS_S_PRM] ) + / m_parameters[H_PRM] ); + q3 = ellipk( k3 ) / ellipk( sqrt( 1 - k3 * k3 ) ); + qz = 1 / ( q1 + q3 ); + er0 = 1 + q3 * qz * ( m_parameters[EPSILONR_PRM] - 1 ); zl_factor = ZF0 / 2 * qz; } // backside is air else { - k2 = sinh( (M_PI / 4) * (w / h) ) / sinh( (M_PI / 4) * (w + s + s) / h ); - q2 = ellipk( k2 ) / ellipk( sqrt( 1 - k2 * k2 ) ); - er0 = 1 + (er - 1) / 2 * q2 / q1; + k2 = sinh( ( M_PI / 4 ) * ( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] ) ) + / sinh( ( M_PI / 4 ) + * ( m_parameters[PHYS_WIDTH_PRM] + m_parameters[PHYS_S_PRM] + + m_parameters[PHYS_S_PRM] ) + / m_parameters[H_PRM] ); + q2 = ellipk( k2 ) / ellipk( sqrt( 1 - k2 * k2 ) ); + er0 = 1 + ( m_parameters[EPSILONR_PRM] - 1 ) / 2 * q2 / q1; zl_factor = ZF0 / 4 / q1; } + // adds effect of strip thickness - if( t > 0 ) + if( m_parameters[T_PRM] > 0 ) { double d, se, We, ke, qe; - d = (t * 1.25 / M_PI) * ( 1 + log( 4 * M_PI * w / t ) ); - se = s - d; - We = w + d; + d = ( m_parameters[T_PRM] * 1.25 / M_PI ) + * ( 1 + log( 4 * M_PI * m_parameters[PHYS_WIDTH_PRM] / m_parameters[T_PRM] ) ); + se = m_parameters[PHYS_S_PRM] - d; + We = m_parameters[PHYS_WIDTH_PRM] + d; // modifies k1 accordingly (k1 = ke) - ke = We / (We + se + se); // ke = k1 + (1 - k1 * k1) * d / 2 / s; + ke = We / ( We + se + se ); // ke = k1 + (1 - k1 * k1) * d / 2 / s; qe = ellipk( ke ) / ellipk( sqrt( 1 - ke * ke ) ); // backside is metal if( backMetal ) { - qz = 1 / (qe + q3); - er0 = 1 + q3 * qz * (er - 1); + qz = 1 / ( qe + q3 ); + er0 = 1 + q3 * qz * ( m_parameters[EPSILONR_PRM] - 1 ); zl_factor = ZF0 / 2 * qz; } // backside is air @@ -136,177 +117,147 @@ void COPLANAR::calc() } // modifies er0 as well - er0 = er0 - (0.7 * (er0 - 1) * t / s) / ( q1 + (0.7 * t / s) ); + er0 = er0 + - ( 0.7 * ( er0 - 1 ) * m_parameters[T_PRM] / m_parameters[PHYS_S_PRM] ) + / ( q1 + ( 0.7 * m_parameters[T_PRM] / m_parameters[PHYS_S_PRM] ) ); } // pre-compute square roots - double sr_er = sqrt( er ); + double sr_er = sqrt( m_parameters[EPSILONR_PRM] ); double sr_er0 = sqrt( er0 ); // cut-off frequency of the TE0 mode - double fte = (C0 / 4) / ( h * sqrt( er - 1 ) ); + double fte = ( C0 / 4 ) / ( m_parameters[H_PRM] * sqrt( m_parameters[EPSILONR_PRM] - 1 ) ); // dispersion factor G - double p = log( w / h ); - double u = 0.54 - (0.64 - 0.015 * p) * p; - double v = 0.43 - (0.86 - 0.54 * p) * p; - double G = exp( u * log( w / s ) + v ); + double p = log( m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM] ); + double u = 0.54 - ( 0.64 - 0.015 * p ) * p; + double v = 0.43 - ( 0.86 - 0.54 * p ) * p; + double G = exp( u * log( m_parameters[PHYS_WIDTH_PRM] / m_parameters[PHYS_S_PRM] ) + v ); // loss constant factors (computed only once for efficiency's sake) double ac = 0; - if( t > 0 ) + if( m_parameters[T_PRM] > 0 ) { // equations by GHIONE - double n = (1 - k1) * 8 * M_PI / ( t * (1 + k1) ); - double a = w / 2; - double b = a + s; - ac = ( M_PI + log( n * a ) ) / a + ( M_PI + log( n * b ) ) / b; + double n = ( 1 - k1 ) * 8 * M_PI / ( m_parameters[T_PRM] * ( 1 + k1 ) ); + double a = m_parameters[PHYS_WIDTH_PRM] / 2; + double b = a + m_parameters[PHYS_S_PRM]; + ac = ( M_PI + log( n * a ) ) / a + ( M_PI + log( n * b ) ) / b; } - double ac_factor = ac / ( 4 * ZF0 * kk1 * kpk1 * (1 - k1 * k1) ); - double ad_factor = ( er / (er - 1) ) * m_tand * M_PI / C0; + double ac_factor = ac / ( 4 * ZF0 * kk1 * kpk1 * ( 1 - k1 * k1 ) ); + double ad_factor = ( m_parameters[EPSILONR_PRM] / ( m_parameters[EPSILONR_PRM] - 1 ) ) + * m_parameters[TAND_PRM] * M_PI / C0; // .................................................... double sr_er_f = sr_er0; // add the dispersive effects to er0 - sr_er_f += (sr_er - sr_er0) / ( 1 + G * pow( m_freq / fte, -1.8 ) ); + sr_er_f += ( sr_er - sr_er0 ) / ( 1 + G * pow( m_parameters[FREQUENCY_PRM] / fte, -1.8 ) ); // for now, the loss are limited to strip losses (no radiation // losses yet) losses in neper/length - atten_cond = 20.0 / log( 10.0 ) * len - * ac_factor * sr_er0 * sqrt( M_PI * MU0 * m_freq / m_sigma ); - atten_dielectric = 20.0 / log( 10.0 ) * len - * ad_factor * m_freq * (sr_er_f * sr_er_f - 1) / sr_er_f; + m_parameters[LOSS_CONDUCTOR_PRM] = + 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] * ac_factor * sr_er0 + * sqrt( M_PI * MU0 * m_parameters[FREQUENCY_PRM] / m_parameters[SIGMA_PRM] ); + m_parameters[LOSS_DIELECTRIC_PRM] = 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] * ad_factor + * m_parameters[FREQUENCY_PRM] * ( sr_er_f * sr_er_f - 1 ) + / sr_er_f; - ang_l = 2.0 * M_PI * len * sr_er_f * m_freq / C0; /* in radians */ + m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] * sr_er_f + * m_parameters[FREQUENCY_PRM] / C0; /* in radians */ - er_eff = sr_er_f * sr_er_f; - Z0 = zl_factor / sr_er_f; + m_parameters[EPSILON_EFF_PRM] = sr_er_f * sr_er_f; + m_parameters[Z0_PRM] = zl_factor / sr_er_f; } // ------------------------------------------------------------------- void COPLANAR::show_results() { - setProperty( Z0_PRM, Z0 ); - setProperty( ANG_L_PRM, ang_l ); - setResult( 0, er_eff, "" ); - setResult( 1, atten_cond, "dB" ); - setResult( 2, atten_dielectric, "dB" ); + setResult( 0, m_parameters[EPSILON_EFF_PRM], "" ); + setResult( 1, m_parameters[LOSS_CONDUCTOR_PRM], "dB" ); + setResult( 2, m_parameters[LOSS_DIELECTRIC_PRM], "dB" ); - setResult( 3, m_skindepth / UNIT_MICRON, "µm" ); -} - - -// ------------------------------------------------------------------- -void COPLANAR::analyze() -{ - getProperties(); - - /* compute coplanar parameters */ - calc(); - - /* print results in the subwindow */ - show_results(); + setResult( 3, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); } #define MAX_ERROR 0.000001 // ------------------------------------------------------------------- -void COPLANAR::synthesize() +/* @function calcSynthesize + * + * @TODO Add a warning in case the synthetizin algorithm did not converge. + * Add it for all transmission lines that uses @ref minimizeZ0Error1D . + */ +void COPLANAR::calcSynthesize() { - double Z0_dest, Z0_current, Z0_result, increment, slope, error; - int iteration; - - getProperties(); - - /* required value of Z0 */ - Z0_dest = Z0; - double ang_l_tmp = getProperty( ANG_L_PRM ); - - // compute inital coplanar parameters. This function modify Z0 and ang_l - // (set to NaN in some cases) - calc(); - - if( std::isnan( Z0 ) ) // cannot be synthesized with current parameters + if( isSelected( PHYS_WIDTH_PRM ) ) { - Z0 = Z0_dest; - ang_l= ang_l_tmp; - - if( isSelected( PHYS_WIDTH_PRM ) ) - { - setProperty( PHYS_WIDTH_PRM, NAN ); - } - else - { - setProperty( PHYS_S_PRM, NAN ); - } - - setProperty( PHYS_LEN_PRM, NAN ); - - /* print results in the subwindow */ - show_results(); - return; + minimizeZ0Error1D( &( m_parameters[PHYS_WIDTH_PRM] ) ); } - - /* Newton's method */ - iteration = 0; - Z0_current = Z0; - error = fabs( Z0_dest - Z0_current ); - - while( error > MAX_ERROR ) + else { - iteration++; - if( isSelected( PHYS_WIDTH_PRM ) ) - { - increment = w / 100.0; - w += increment; - } - else - { - increment = s / 100.0; - s += increment; - } - /* compute coplanar parameters */ - calc(); - Z0_result = Z0; - /* 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)) */ - slope = (Z0_result - Z0_current) / increment; - slope = (Z0_dest - Z0_current) / slope - increment; - if( isSelected( PHYS_WIDTH_PRM ) ) - w += slope; - else - s += slope; - if( w <= 0.0 ) - w = increment; - if( s <= 0.0 ) - s = increment; - /* find new error */ - /* compute coplanar parameters */ - calc(); - Z0_current = Z0; - error = fabs( Z0_dest - Z0_current ); - - if( iteration > 100 ) - break; + minimizeZ0Error1D( &( m_parameters[PHYS_S_PRM] ) ); } - - setProperty( PHYS_WIDTH_PRM, w ); - setProperty( PHYS_S_PRM, s ); - /* calculate physical length */ - ang_l = getProperty( ANG_L_PRM ); - len = C0 / m_freq / sqrt( er_eff ) * ang_l / 2.0 / M_PI; /* in m */ - setProperty( PHYS_LEN_PRM, len ); - - /* compute coplanar parameters */ - calc(); - - /* print results in the subwindow */ - show_results(); +} + +// ------------------------------------------------------------------- +void COPLANAR::showSynthesize() +{ + if( isSelected( PHYS_WIDTH_PRM ) ) + setProperty( PHYS_WIDTH_PRM, m_parameters[PHYS_WIDTH_PRM] ); + + if( isSelected( PHYS_S_PRM ) ) + setProperty( PHYS_S_PRM, m_parameters[PHYS_S_PRM] ); + + setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); + + if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0 ) + { + if( isSelected( PHYS_S_PRM ) ) + setErrorLevel( PHYS_S_PRM, TRANSLINE_ERROR ); + else + setErrorLevel( PHYS_S_PRM, TRANSLINE_WARNING ); + } + if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0 ) + { + if( isSelected( PHYS_WIDTH_PRM ) ) + setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR ); + else + setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING ); + } + 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[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 COPLANAR::showAnalyze() +{ + setProperty( Z0_PRM, m_parameters[Z0_PRM] ); + setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] ); + + if( !std::isfinite( m_parameters[PHYS_S_PRM] ) || m_parameters[PHYS_S_PRM] <= 0 ) + setErrorLevel( PHYS_S_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || m_parameters[PHYS_WIDTH_PRM] <= 0 ) + setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_WARNING ); + + 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[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 ); } diff --git a/pcb_calculator/transline/coplanar.h b/pcb_calculator/transline/coplanar.h index d51411ad97..e7a3c57b8e 100644 --- a/pcb_calculator/transline/coplanar.h +++ b/pcb_calculator/transline/coplanar.h @@ -25,39 +25,31 @@ #ifndef __COPLANAR_H #define __COPLANAR_H +#include + class COPLANAR : public TRANSLINE { -public: COPLANAR(); - -private: - double h; // height of substrate - double t; // thickness of top metal - double w; // width of line - double s; // width of gap between line and ground - double len; // length of line - double Z0; // characteristic impedance - double er_eff; // effective dielectric constant - double ang_l; // Electrical length in angle - double atten_dielectric; // Loss in dielectric (dB) - double atten_cond; // Loss in conductors (dB) +public: + COPLANAR(); public: - void analyze() override; - void synthesize() override; + void calcSynthesize() override; protected: bool backMetal; private: - void calc(); - void show_results(); - void getProperties(); + void calcAnalyze() override; + void showSynthesize() override; + void showAnalyze() override; + void show_results() override; }; class GROUNDEDCOPLANAR : public COPLANAR { -public: GROUNDEDCOPLANAR(); +public: + GROUNDEDCOPLANAR(); }; -#endif // __COPLANAR_H +#endif // __COPLANAR_H diff --git a/pcb_calculator/transline/microstrip.cpp b/pcb_calculator/transline/microstrip.cpp index bbd01707a6..bea22ee14a 100644 --- a/pcb_calculator/transline/microstrip.cpp +++ b/pcb_calculator/transline/microstrip.cpp @@ -34,32 +34,15 @@ #include #include -#include -#include #include +#include + +#include MICROSTRIP::MICROSTRIP() : TRANSLINE() { m_Name = "MicroStrip"; - - // Initialize these variables mainly to avoid warnings from a static analyzer - 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 - ang_l = 0.0; // Electrical length in angle - er_eff_0 = 0.0; // Static effective dielectric constant - er_eff = 0.0; // 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 + Init(); } @@ -71,8 +54,8 @@ double MICROSTRIP::Z0_homogeneous( double u ) { 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) ) ); + 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; } @@ -88,7 +71,7 @@ double MICROSTRIP::delta_Z0_cover( double u, double h2h ) 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) ); + Q = 1.0109 - atanh( ( 0.012 * u + 0.177 * u * u - 0.027 * u * u * u ) / ( h2hp1 * h2hp1 ) ); return P * Q; } @@ -105,9 +88,8 @@ double MICROSTRIP::filling_factor( double u, double e_r ) 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 ); + 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; } @@ -132,7 +114,7 @@ double MICROSTRIP::delta_q_thickness( double u, double t_h ) { double q_t; - q_t = (2.0 * log( 2.0 ) / M_PI) * ( t_h / sqrt( u ) ); + q_t = ( 2.0 * log( 2.0 ) / M_PI ) * ( t_h / sqrt( u ) ); return q_t; } @@ -145,7 +127,7 @@ 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); + e_r_eff = 0.5 * ( e_r + 1.0 ) + 0.5 * q * ( e_r - 1.0 ); return e_r_eff; } @@ -160,8 +142,8 @@ double MICROSTRIP::delta_u_thickness( double u, double t_h, double e_r ) 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 ); + 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 ) ) ); } @@ -182,11 +164,11 @@ void MICROSTRIP::microstrip_Z0() 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 = er; - h2 = ht; - h2h = h2 / h; - u = w / h; - t_h = t / h; + 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 ); @@ -205,7 +187,7 @@ void MICROSTRIP::microstrip_Z0() /* thickness effect */ q_t = delta_q_thickness( u, t_h ); /* resultant filling factor */ - q = (q_inf - q_t) * q_c; + 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 ); @@ -215,11 +197,11 @@ void MICROSTRIP::microstrip_Z0() /* characteristic impedance, corrected for thickness, cover */ /* and non homogeneous material */ - Z0 = Z0_h_r / sqrt( e_r_eff_t ); + m_parameters[Z0_PRM] = Z0_h_r / sqrt( e_r_eff_t ); - w_eff = u * h; + w_eff = u * m_parameters[H_PRM]; er_eff_0 = e_r_eff; - Z0_0 = Z0; + Z0_0 = m_parameters[Z0_PRM]; } @@ -231,13 +213,13 @@ 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_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 ); + P = P_1 * P_2 * pow( ( P_3 * P_4 + 0.1844 ) * f_n, 1.5763 ); return P; } @@ -247,14 +229,11 @@ double MICROSTRIP::e_r_dispersion( double u, double e_r, double f_n ) * 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 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_17, D, tmpf; R_1 = 0.03891 * pow( e_r, 1.4 ); R_2 = 0.267 * pow( u, 7.0 ); @@ -263,22 +242,23 @@ double MICROSTRIP::Z0_dispersion( double u, 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 ) ) ); + 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_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_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_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 ) ); + 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 ); @@ -295,22 +275,22 @@ void MICROSTRIP::dispersion() double e_r, e_r_eff_0; double u, f_n, P, e_r_eff_f, D, Z0_f; - e_r = er; + e_r = m_parameters[EPSILONR_PRM]; e_r_eff_0 = er_eff_0; - u = w / h; + u = m_parameters[PHYS_WIDTH_PRM] / m_parameters[H_PRM]; /* normalized frequency [GHz * mm] */ - f_n = m_freq * h / 1e06; + 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); + 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; - er_eff = e_r_eff_f; - Z0 = Z0_f; + er_eff = e_r_eff_f; + m_parameters[Z0_PRM] = Z0_f; } @@ -324,20 +304,24 @@ double MICROSTRIP::conductor_losses() double K, R_s, Q_c, alpha_c; e_r_eff_0 = er_eff_0; - delta = m_skindepth; + delta = m_parameters[SKIN_DEPTH_PRM]; - if( m_freq > 0.0 ) + 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_sigma * delta); + 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( (rough / delta), 2.0 ) ) ); + 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 * w * m_freq) / (R_s * C0 * K); - alpha_c = ( 20.0 * M_PI / log( 10.0 ) ) * m_freq * sqrt( e_r_eff_0 ) / (C0 * Q_c); + 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 { @@ -357,13 +341,12 @@ double MICROSTRIP::dielectric_losses() double e_r, e_r_eff_0; double alpha_d; - e_r = er; + e_r = m_parameters[EPSILONR_PRM]; e_r_eff_0 = er_eff_0; - alpha_d = - ( 20.0 * M_PI / - log( 10.0 ) ) * - (m_freq / C0) * ( e_r / sqrt( e_r_eff_0 ) ) * ( (e_r_eff_0 - 1.0) / (e_r - 1.0) ) * m_tand; + 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; } @@ -374,10 +357,10 @@ double MICROSTRIP::dielectric_losses() */ void MICROSTRIP::attenuation() { - m_skindepth = skin_depth(); + m_parameters[SKIN_DEPTH_PRM] = skin_depth(); - atten_cond = conductor_losses() * l; - atten_dielectric = dielectric_losses() * l; + atten_cond = conductor_losses() * m_parameters[PHYS_LEN_PRM]; + atten_dielectric = dielectric_losses() * m_parameters[PHYS_LEN_PRM]; } @@ -386,7 +369,11 @@ void MICROSTRIP::attenuation() */ void MICROSTRIP::mur_eff_ms() { - mur_eff = (2.0 * mur) / ( (1.0 + mur) + ( (1.0 - mur) * pow( ( 1.0 + (10.0 * h / w) ), -0.5 ) ) ); + 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 ) ) ); } @@ -396,24 +383,25 @@ double MICROSTRIP::synth_width() double e_r, a, b; double w_h, width; - e_r = er; + e_r = m_parameters[EPSILONR_PRM]; - a = ( (Z0 / 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 / ( Z0 * sqrt( e_r ) ); + 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); + 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) ); + 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( h > 0.0 ) - width = w_h * h; + if( m_parameters[H_PRM] > 0.0 ) + width = w_h * m_parameters[H_PRM]; else width = 0; @@ -434,13 +422,13 @@ void MICROSTRIP::line_angle() /* velocity */ v = C0 / sqrt( e_r_eff * mur_eff ); /* wavelength */ - lambda_g = v / m_freq; + lambda_g = v / m_parameters[FREQUENCY_PRM]; /* electrical angles */ - ang_l = 2.0 * M_PI * l / lambda_g; /* in radians */ + m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] / lambda_g; /* in radians */ } -void MICROSTRIP::calc() +void MICROSTRIP::calcAnalyze() { /* effective permeability */ mur_eff_ms(); @@ -455,167 +443,78 @@ void MICROSTRIP::calc() } -/* - * get_microstrip_sub () - get and assign microstrip substrate - * parameters into microstrip structure - */ -void MICROSTRIP::get_microstrip_sub() -{ - er = getProperty( EPSILONR_PRM ); - mur = getProperty( MUR_PRM ); - h = getProperty( H_PRM ); - ht = getProperty( H_T_PRM ); - t = getProperty( T_PRM ); - m_sigma = 1.0 / getProperty( RHO_PRM ); - m_murC = getProperty( MURC_PRM ); - m_tand = getProperty( TAND_PRM ); - rough = getProperty( ROUGH_PRM ); -} - - -/* - * get_microstrip_comp() - get and assign microstrip component - * parameters into microstrip structure - */ -void MICROSTRIP::get_microstrip_comp() -{ - m_freq = getProperty( FREQUENCY_PRM ); -} - - -/* - * get_microstrip_elec() - get and assign microstrip electrical - * parameters into microstrip structure - */ -void MICROSTRIP::get_microstrip_elec() -{ - Z0 = getProperty( Z0_PRM ); - ang_l = getProperty( ANG_L_PRM ); -} - - -/* - * get_microstrip_phys() - get and assign microstrip physical - * parameters into microstrip structure - */ -void MICROSTRIP::get_microstrip_phys() -{ - w = getProperty( PHYS_WIDTH_PRM ); - l = getProperty( PHYS_LEN_PRM ); -} - - void MICROSTRIP::show_results() { - setProperty( Z0_PRM, Z0 ); - setProperty( ANG_L_PRM, ang_l ); + setProperty( Z0_PRM, m_parameters[Z0_PRM] ); + setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] ); setResult( 0, er_eff, "" ); setResult( 1, atten_cond, "dB" ); setResult( 2, atten_dielectric, "dB" ); - setResult( 3, m_skindepth/UNIT_MICRON, "µm" ); + setResult( 3, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); } -/* - * analysis function - */ -void MICROSTRIP::analyze() +void MICROSTRIP::showSynthesize() { - /* Get and assign substrate parameters */ - get_microstrip_sub(); + setProperty( PHYS_WIDTH_PRM, m_parameters[PHYS_WIDTH_PRM] ); + setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); - /* Get and assign component parameters */ - get_microstrip_comp(); + // Check for errors + if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || ( m_parameters[PHYS_LEN_PRM] < 0 ) ) + setErrorLevel( PHYS_LEN_PRM, TRANSLINE_ERROR ); - /* Get and assign physical parameters */ - get_microstrip_phys(); + if( !std::isfinite( m_parameters[PHYS_WIDTH_PRM] ) || ( m_parameters[PHYS_WIDTH_PRM] <= 0 ) ) + setErrorLevel( PHYS_WIDTH_PRM, TRANSLINE_ERROR ); - /* compute microstrip parameters */ - calc(); + // Check for warnings - /* print results in the subwindow */ - show_results(); + 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] ); -#define MAX_ERROR 0.000001 + // 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::synthesize() +void MICROSTRIP::calcSynthesize() { - double Z0_dest, Z0_current, Z0_result, increment, slope, error; - int iteration; - - /* Get and assign substrate parameters */ - get_microstrip_sub(); - - /* Get and assign component parameters */ - get_microstrip_comp(); - - /* Get and assign electrical parameters */ - get_microstrip_elec(); - - /* Get and assign physical parameters */ - /* at present it is required only for getting strips length */ - get_microstrip_phys(); - - + double angl_dest, z0_dest; + z0_dest = m_parameters[Z0_PRM]; + angl_dest = m_parameters[ANG_L_PRM]; /* calculate width and use for initial value in Newton's method */ - w = synth_width(); - - /* required value of Z0 */ - Z0_dest = Z0; - - /* Newton's method */ - iteration = 0; - - /* compute microstrip parameters */ - calc(); - Z0_current = Z0; - - error = fabs( Z0_dest - Z0_current ); - - while( error > MAX_ERROR ) - { - iteration++; - increment = (w / 100.0); - w += increment; - /* compute microstrip parameters */ - calc(); - Z0_result = Z0; - /* 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)) */ - slope = (Z0_result - Z0_current) / increment; - /* printf("%g\n",slope); */ - w += (Z0_dest - Z0_current) / slope - increment; - /* printf("ms->w = %g\n", ms->w); */ - /* find new error */ - /* compute microstrip parameters */ - calc(); - Z0_current = Z0; - error = fabs( Z0_dest - Z0_current ); - - /* printf("Iteration = %d\n",iteration); - * printf("w = %g\t Z0 = %g\n",ms->w, Z0_current); */ - if( iteration > 100 ) - break; - } - - setProperty( PHYS_WIDTH_PRM, w ); - /* calculate physical length */ - ang_l = getProperty( ANG_L_PRM ); - l = C0 / m_freq / sqrt( er_eff * mur_eff ) * ang_l / 2.0 / M_PI; /* in m */ - setProperty( PHYS_LEN_PRM, l ); - - /* compute microstrip parameters */ - calc(); - - /* print results in the subwindow */ - show_results(); + 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; + 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 */ } diff --git a/pcb_calculator/transline/microstrip.h b/pcb_calculator/transline/microstrip.h index ec06936ff6..57eb922900 100644 --- a/pcb_calculator/transline/microstrip.h +++ b/pcb_calculator/transline/microstrip.h @@ -25,36 +25,35 @@ #ifndef __MICROSTRIP_H #define __MICROSTRIP_H +#include + class MICROSTRIP : public TRANSLINE { -public: MICROSTRIP(); +public: + MICROSTRIP(); 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 ang_l; // Electrical length in angle - double er_eff_0; // Static effective dielectric constant - double er_eff; // 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 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 ang_l; // Electrical length in angle + double er_eff_0; // Static effective dielectric constant + double er_eff; // 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) // private params - double Z0_h_1; // homogeneous stripline impedance - -public: - void analyze() override; - void synthesize() override; + double Z0_h_1; // homogeneous stripline impedance private: double er_eff_freq(); @@ -81,12 +80,11 @@ private: void attenuation(); void mur_eff_ms(); void line_angle(); - void calc(); - void get_microstrip_sub(); - void get_microstrip_comp(); - void get_microstrip_elec(); - void get_microstrip_phys(); - void show_results(); + void show_results() override; + void showSynthesize() override; + void showAnalyze() override; + void calcAnalyze() override; + void calcSynthesize() override; }; -#endif // __MICROSTRIP_H +#endif // __MICROSTRIP_H diff --git a/pcb_calculator/transline/rectwaveguide.cpp b/pcb_calculator/transline/rectwaveguide.cpp index c7c589e18a..fe87a1fddf 100644 --- a/pcb_calculator/transline/rectwaveguide.cpp +++ b/pcb_calculator/transline/rectwaveguide.cpp @@ -25,27 +25,13 @@ #include #include -#include -#include #include +#include RECTWAVEGUIDE::RECTWAVEGUIDE() : TRANSLINE() { m_Name = "RectWaveGuide"; - - // Initialize these here variables mainly to avoid warnings from a static analyzer - mur = 0.0; // magnetic permeability of substrate - a = 0.0; // width of waveguide - b = 0.0; // height of waveguide - l = 0.0; // length of waveguide - Z0 = 0.0; // characteristic impedance - Z0EH = 0.0; // characteristic impedance of field quantities*/ - ang_l = 0.0; // Electrical length in angle - er_eff = 0.0; // Effective dielectric constant - mur_eff = 0.0; // Effective mag. permeability - atten_dielectric = 0.0; // Loss in dielectric (dB) - atten_cond = 0.0; // Loss in conductors (dB) - fc10 = 0.0; // Cutoff frequency for TE10 mode + Init(); } @@ -56,7 +42,8 @@ double RECTWAVEGUIDE::kval_square() { double kval; - kval = 2.0* M_PI * m_freq * sqrt( mur * er ) / C0; + kval = 2.0 * M_PI * m_parameters[FREQUENCY_PRM] + * sqrt( m_parameters[MUR_PRM] * m_parameters[EPSILONR_PRM] ) / C0; return kval * kval; } @@ -68,7 +55,8 @@ double RECTWAVEGUIDE::kval_square() */ double RECTWAVEGUIDE::kc_square( int m, int n ) { - return pow( (m * M_PI / a), 2.0 ) + pow( (n * M_PI / b), 2.0 ); + return pow( ( m * M_PI / m_parameters[PHYS_A_PRM] ), 2.0 ) + + pow( ( n * M_PI / m_parameters[PHYS_B_PRM] ), 2.0 ); } @@ -78,7 +66,8 @@ double RECTWAVEGUIDE::kc_square( int m, int n ) */ double RECTWAVEGUIDE::fc( int m, int n ) { - return sqrt( kc_square( m, n ) / mur / er ) * C0 / 2.0 / M_PI; + return sqrt( kc_square( m, n ) / m_parameters[MUR_PRM] / m_parameters[EPSILONR_PRM] ) * C0 / 2.0 + / M_PI; } @@ -88,13 +77,18 @@ double RECTWAVEGUIDE::fc( int m, int n ) */ double RECTWAVEGUIDE::alphac() { - double Rs, f_c; - double ac; - short m, n, mmax, nmax; + double Rs, f_c; + double ac; + short m, n, mmax, nmax; + double* a = &m_parameters[PHYS_A_PRM]; + double* b = &m_parameters[PHYS_B_PRM]; + double* f = &m_parameters[FREQUENCY_PRM]; + double* murc = &m_parameters[MURC_PRM]; + double* sigma = &m_parameters[SIGMA_PRM]; - Rs = sqrt( M_PI * m_freq * m_murC * MU0 / m_sigma ); + Rs = sqrt( M_PI * *f * *murc * MU0 / *sigma ); ac = 0.0; - mmax = (int) floor( m_freq / fc( 1, 0 ) ); + mmax = (int) floor( *f / fc( 1, 0 ) ); nmax = mmax; /* below from Ramo, Whinnery & Van Duzer */ @@ -105,24 +99,24 @@ double RECTWAVEGUIDE::alphac() for( m = 1; m <= mmax; m++ ) { f_c = fc( m, n ); - if( m_freq > f_c ) + if( *f > f_c ) { switch( n ) { case 0: - ac += ( Rs / ( b * ZF0 * sqrt( 1.0 - pow( (f_c / m_freq), 2.0 ) ) ) ) * - ( 1.0 + ( (2 * b / a) * pow( (f_c / m_freq), 2.0 ) ) ); + ac += ( Rs / ( *b * ZF0 * sqrt( 1.0 - pow( ( f_c / *f ), 2.0 ) ) ) ) + * ( 1.0 + ( ( 2 * *b / *a ) * pow( ( f_c / *f ), 2.0 ) ) ); break; default: - ac += ( (2. * Rs) / ( b * ZF0 * sqrt( 1.0 - pow( (f_c / m_freq), 2.0 ) ) ) ) * - ( ( ( 1. + (b / a) ) * pow( (f_c / m_freq), 2.0 ) ) + - ( ( 1. - - pow( (f_c / m_freq), - 2.0 ) ) * - ( ( (b / a) * ( ( (b / a) * pow( m, 2. ) ) + pow( n, 2. ) ) ) / - ( pow( (b * m / a), - 2.0 ) + pow( n, 2.0 ) ) ) ) ); + ac += ( ( 2. * Rs ) / ( *b * ZF0 * sqrt( 1.0 - pow( ( f_c / *f ), 2.0 ) ) ) ) + * ( ( ( 1. + ( *b / *a ) ) * pow( ( f_c / *f ), 2.0 ) ) + + ( ( 1. - pow( ( f_c / *f ), 2.0 ) ) + * ( ( ( *b / *a ) + * ( ( ( *b / *a ) * pow( m, 2. ) ) + + pow( n, 2. ) ) ) + / ( pow( ( *b * m / *a ), 2.0 ) + + pow( n, 2.0 ) ) ) ) ); break; } } @@ -132,14 +126,14 @@ double RECTWAVEGUIDE::alphac() /* TM(m,n) modes */ for( n = 1; n <= nmax; n++ ) { - for( m = 1; m<= mmax; m++ ) + for( m = 1; m <= mmax; m++ ) { f_c = fc( m, n ); - if( m_freq > f_c ) + if( *f > f_c ) { - ac += ( (2. * Rs) / ( b * ZF0 * sqrt( 1.0 - pow( (f_c / m_freq), 2.0 ) ) ) ) * - ( ( ( pow( m, 2.0 ) * pow( (b / a), 3.0 ) ) + pow( n, 2. ) ) / - ( ( pow( (m * b / a), 2. ) ) + pow( n, 2.0 ) ) ); + ac += ( ( 2. * Rs ) / ( *b * ZF0 * sqrt( 1.0 - pow( ( f_c / *f ), 2.0 ) ) ) ) + * ( ( ( pow( m, 2.0 ) * pow( ( *b / *a ), 3.0 ) ) + pow( n, 2. ) ) + / ( ( pow( ( m * *b / *a ), 2. ) ) + pow( n, 2.0 ) ) ); } } } @@ -173,7 +167,7 @@ double RECTWAVEGUIDE::alphad() k_square = kval_square(); beta = sqrt( k_square - kc_square( 1, 0 ) ); - ad = (k_square * m_tand) / (2.0 * beta); + ad = ( k_square * m_parameters[TAND_PRM] ) / ( 2.0 * beta ); ad = ad * 20.0 * log10( exp( 1. ) ); /* convert from Np/m to db/m */ return ad; } @@ -186,11 +180,11 @@ double RECTWAVEGUIDE::alphad() */ void RECTWAVEGUIDE::get_rectwaveguide_sub() { - er = getProperty( EPSILONR_PRM ); - mur = getProperty( MUR_PRM ); - m_murC = getProperty( MURC_PRM ); - m_sigma = 1.0 / getProperty( RHO_PRM ); - m_tand = getProperty( TAND_PRM ); + m_parameters[EPSILONR_PRM] = getProperty( EPSILONR_PRM ); + m_parameters[MUR_PRM] = getProperty( MUR_PRM ); + m_parameters[MURC_PRM] = getProperty( MURC_PRM ); + m_parameters[SIGMA_PRM] = 1.0 / getProperty( RHO_PRM ); + m_parameters[TAND_PRM] = getProperty( TAND_PRM ); } @@ -201,7 +195,7 @@ void RECTWAVEGUIDE::get_rectwaveguide_sub() */ void RECTWAVEGUIDE::get_rectwaveguide_comp() { - m_freq = getProperty( FREQUENCY_PRM ); + m_parameters[FREQUENCY_PRM] = getProperty( FREQUENCY_PRM ); } @@ -212,8 +206,8 @@ void RECTWAVEGUIDE::get_rectwaveguide_comp() */ void RECTWAVEGUIDE::get_rectwaveguide_elec() { - Z0 = getProperty( Z0_PRM ); - ang_l = getProperty( ANG_L_PRM ); + m_parameters[Z0_PRM] = getProperty( Z0_PRM ); + m_parameters[ANG_L_PRM] = getProperty( ANG_L_PRM ); } @@ -224,29 +218,20 @@ void RECTWAVEGUIDE::get_rectwaveguide_elec() */ void RECTWAVEGUIDE::get_rectwaveguide_phys() { - a = getProperty( PHYS_WIDTH_PRM ); - b = getProperty( PHYS_S_PRM ); - l = getProperty( PHYS_LEN_PRM ); + m_parameters[PHYS_A_PRM] = getProperty( PHYS_A_PRM ); + m_parameters[PHYS_B_PRM] = getProperty( PHYS_B_PRM ); + m_parameters[PHYS_LEN_PRM] = getProperty( PHYS_LEN_PRM ); } /* * analyze - analysis function */ -void RECTWAVEGUIDE::analyze() +void RECTWAVEGUIDE::calcAnalyze() { double lambda_g; double k_square; - /* Get and assign substrate parameters */ - get_rectwaveguide_sub(); - - /* Get and assign component parameters */ - get_rectwaveguide_comp(); - - /* Get and assign physical parameters */ - get_rectwaveguide_phys(); - k_square = kval_square(); if( kc_square( 1, 0 ) <= k_square ) @@ -254,92 +239,124 @@ void RECTWAVEGUIDE::analyze() /* propagating modes */ // Z0 definition using fictive voltages and currents - Z0 = 2.0* ZF0* sqrt( mur / er ) * (b / a) / sqrt( 1.0 - pow( (fc( 1, 0 ) / m_freq), 2.0 ) ); + m_parameters[Z0_PRM] = + 2.0 * ZF0 * sqrt( m_parameters[MUR_PRM] / m_parameters[EPSILONR_PRM] ) + * ( m_parameters[PHYS_B_PRM] / m_parameters[PHYS_A_PRM] ) + / sqrt( 1.0 - pow( ( fc( 1, 0 ) / m_parameters[FREQUENCY_PRM] ), 2.0 ) ); /* calculate electrical angle */ - lambda_g = 2.0 * M_PI / sqrt( k_square - kc_square( 1, 0 ) ); - ang_l = 2.0 * M_PI * l / lambda_g; /* in radians */ - atten_cond = alphac() * l; - atten_dielectric = alphad() * l; - er_eff = ( 1.0 - pow( fc( 1, 0 ) / m_freq, 2.0 ) ); + lambda_g = 2.0 * M_PI / sqrt( k_square - kc_square( 1, 0 ) ); + m_parameters[ANG_L_PRM] = + 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] / lambda_g; /* in radians */ + m_parameters[LOSS_CONDUCTOR_PRM] = alphac() * m_parameters[PHYS_LEN_PRM]; + m_parameters[LOSS_DIELECTRIC_PRM] = alphad() * m_parameters[PHYS_LEN_PRM]; + m_parameters[EPSILON_EFF_PRM] = + ( 1.0 - pow( fc( 1, 0 ) / m_parameters[FREQUENCY_PRM], 2.0 ) ); } else { /* evanascent modes */ - Z0 = 0; - ang_l = 0; - er_eff = 0; - atten_dielectric = 0.0; - atten_cond = alphac_cutoff() * l; + m_parameters[Z0_PRM] = 0; + m_parameters[ANG_L_PRM] = 0; + m_parameters[EPSILON_EFF_PRM] = 0; + m_parameters[LOSS_DIELECTRIC_PRM] = 0.0; + m_parameters[LOSS_CONDUCTOR_PRM] = alphac_cutoff() * m_parameters[PHYS_LEN_PRM]; } - - setProperty( Z0_PRM, Z0 ); - setProperty( ANG_L_PRM, ang_l ); - - show_results(); } - /* * synthesize - synthesis function */ -void RECTWAVEGUIDE::synthesize() +void RECTWAVEGUIDE::calcSynthesize() { double lambda_g, k_square, beta; - /* Get and assign substrate parameters */ - get_rectwaveguide_sub(); - - /* Get and assign component parameters */ - get_rectwaveguide_comp(); - - /* Get and assign electrical parameters */ - get_rectwaveguide_elec(); - - /* Get and assign physical parameters */ - get_rectwaveguide_phys(); - - - if( isSelected( PHYS_S_PRM ) ) + if( isSelected( PHYS_B_PRM ) ) { /* solve for b */ - b = Z0 * a * sqrt( 1.0 - pow( fc( 1, 0 ) / m_freq, 2.0 ) ) / ( 2.0 * ZF0 * sqrt( mur / er ) ); - setProperty( PHYS_S_PRM, b ); + m_parameters[PHYS_B_PRM] = + m_parameters[Z0_PRM] * m_parameters[PHYS_A_PRM] + * sqrt( 1.0 - pow( fc( 1, 0 ) / m_parameters[FREQUENCY_PRM], 2.0 ) ) + / ( 2.0 * ZF0 * sqrt( m_parameters[MUR_PRM] / m_parameters[EPSILONR_PRM] ) ); } - else if( isSelected( PHYS_WIDTH_PRM ) ) + else if( isSelected( PHYS_A_PRM ) ) { /* solve for a */ - a = sqrt( pow( 2.0 * ZF0 * b / Z0, 2.0 ) + pow( C0 / (2.0 * m_freq), 2.0 ) ); - setProperty( PHYS_WIDTH_PRM, a ); + m_parameters[PHYS_A_PRM] = + sqrt( pow( 2.0 * ZF0 * m_parameters[PHYS_B_PRM] / m_parameters[Z0_PRM], 2.0 ) + + pow( C0 / ( 2.0 * m_parameters[FREQUENCY_PRM] ), 2.0 ) ); } - k_square = kval_square(); - beta = sqrt( k_square - kc_square( 1, 0 ) ); - lambda_g = 2.0 * M_PI / beta; - l = (ang_l * lambda_g) / (2.0 * M_PI); /* in m */ - - setProperty( PHYS_LEN_PRM, l ); + k_square = kval_square(); + beta = sqrt( k_square - kc_square( 1, 0 ) ); + lambda_g = 2.0 * M_PI / beta; + m_parameters[PHYS_LEN_PRM] = ( m_parameters[ANG_L_PRM] * lambda_g ) / ( 2.0 * M_PI ); /* in m */ if( kc_square( 1, 0 ) <= k_square ) { /*propagating modes */ - beta = sqrt( k_square - kc_square( 1, 0 ) ); - lambda_g = 2.0 * M_PI / beta; - atten_cond = alphac() * l; - atten_dielectric = alphad() * l; - er_eff = ( 1.0 - pow( (fc( 1, 0 ) / m_freq), 2.0 ) ); + beta = sqrt( k_square - kc_square( 1, 0 ) ); + lambda_g = 2.0 * M_PI / beta; + m_parameters[LOSS_CONDUCTOR_PRM] = alphac() * m_parameters[PHYS_LEN_PRM]; + m_parameters[LOSS_DIELECTRIC_PRM] = alphad() * m_parameters[PHYS_LEN_PRM]; + m_parameters[EPSILON_EFF_PRM] = + ( 1.0 - pow( ( fc( 1, 0 ) / m_parameters[FREQUENCY_PRM] ), 2.0 ) ); } else { /*evanascent modes */ - Z0 = 0; - ang_l = 0; - er_eff = 0; - atten_dielectric = 0.0; - atten_cond = alphac_cutoff() * l; + m_parameters[Z0_PRM] = 0; + m_parameters[ANG_L_PRM] = 0; + m_parameters[EPSILON_EFF_PRM] = 0; + m_parameters[LOSS_DIELECTRIC_PRM] = 0.0; + m_parameters[LOSS_CONDUCTOR_PRM] = alphac_cutoff() * m_parameters[PHYS_LEN_PRM]; } +} - show_results(); +void RECTWAVEGUIDE::showSynthesize() +{ + if( isSelected( PHYS_A_PRM ) ) + setProperty( PHYS_A_PRM, m_parameters[PHYS_A_PRM] ); + + if( isSelected( PHYS_B_PRM ) ) + setProperty( PHYS_B_PRM, m_parameters[PHYS_B_PRM] ); + + setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); + + // Check for errors + if( !std::isfinite( m_parameters[PHYS_A_PRM] ) || m_parameters[PHYS_A_PRM] <= 0 ) + setErrorLevel( PHYS_A_PRM, TRANSLINE_ERROR ); + + if( !std::isfinite( m_parameters[PHYS_B_PRM] ) || m_parameters[PHYS_B_PRM] <= 00 ) + setErrorLevel( PHYS_B_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 RECTWAVEGUIDE::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_A_PRM] ) || m_parameters[PHYS_A_PRM] <= 0 ) + setErrorLevel( PHYS_A_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[PHYS_B_PRM] ) || m_parameters[PHYS_B_PRM] <= 00 ) + setErrorLevel( PHYS_B_PRM, TRANSLINE_WARNING ); } @@ -353,12 +370,12 @@ void RECTWAVEGUIDE::show_results() Z0EH = ZF0 * sqrt( kval_square() / ( kval_square() - kc_square( 1, 0 ) ) ); setResult( 0, Z0EH, "Ohm" ); - setResult( 1, er_eff, "" ); - setResult( 2, atten_cond, "dB" ); - setResult( 3, atten_dielectric, "dB" ); + setResult( 1, m_parameters[EPSILON_EFF_PRM], "" ); + setResult( 2, m_parameters[LOSS_CONDUCTOR_PRM], "dB" ); + setResult( 3, m_parameters[LOSS_DIELECTRIC_PRM], "dB" ); // show possible TE modes (H modes) - if( m_freq < fc( 1, 0 ) ) + if( m_parameters[FREQUENCY_PRM] < fc( 1, 0 ) ) strcpy( text, "none" ); else { @@ -367,12 +384,12 @@ void RECTWAVEGUIDE::show_results() { for( n = 0; n <= max; n++ ) { - if( (m == 0) && (n == 0) ) + if( ( m == 0 ) && ( n == 0 ) ) continue; - if( m_freq >= ( fc( m, n ) ) ) + if( m_parameters[FREQUENCY_PRM] >= ( fc( m, n ) ) ) { sprintf( txt, "H(%d,%d) ", m, n ); - if( (strlen( text ) + strlen( txt ) + 5) < MAXSTRLEN ) + if( ( strlen( text ) + strlen( txt ) + 5 ) < MAXSTRLEN ) strcat( text, txt ); else { @@ -386,19 +403,19 @@ void RECTWAVEGUIDE::show_results() setResult( 4, text ); // show possible TM modes (E modes) - if( m_freq < fc( 1, 1 ) ) + if( m_parameters[FREQUENCY_PRM] < fc( 1, 1 ) ) strcpy( text, "none" ); else { strcpy( text, "" ); - for( m = 1; m<= max; m++ ) + for( m = 1; m <= max; m++ ) { - for( n = 1; n<= max; n++ ) + for( n = 1; n <= max; n++ ) { - if( m_freq >= fc( m, n ) ) + if( m_parameters[FREQUENCY_PRM] >= fc( m, n ) ) { sprintf( txt, "E(%d,%d) ", m, n ); - if( (strlen( text ) + strlen( txt ) + 5) < MAXSTRLEN ) + if( ( strlen( text ) + strlen( txt ) + 5 ) < MAXSTRLEN ) strcat( text, txt ); else { diff --git a/pcb_calculator/transline/rectwaveguide.h b/pcb_calculator/transline/rectwaveguide.h index 4e16e4fb9d..6a38d3ff77 100644 --- a/pcb_calculator/transline/rectwaveguide.h +++ b/pcb_calculator/transline/rectwaveguide.h @@ -25,28 +25,32 @@ #ifndef __RECTWAVEGUIDE_H #define __RECTWAVEGUIDE_H +#include + +#define PHYS_A_PRM PHYS_WIDTH_PRM +#define PHYS_B_PRM PHYS_S_PRM + class RECTWAVEGUIDE : public TRANSLINE { -public: RECTWAVEGUIDE(); +public: + RECTWAVEGUIDE(); + private: - double mur; // magnetic permeability of substrate - double a; // width of waveguide - double b; // height of waveguide - double l; // length of waveguide - double Z0; // characteristic impedance - double Z0EH; // characteristic impedance of field quantities*/ - double ang_l; // Electrical length in angle - double er_eff; // Effective dielectric constant - double mur_eff; // Effective mag. permeability - double atten_dielectric; // Loss in dielectric (dB) - double atten_cond; // Loss in conductors (dB) - double fc10; // Cutoff frequency for TE10 mode + double mur; // magnetic permeability of substrate + double a; // width of waveguide + double b; // height of waveguide + double l; // length of waveguide + double Z0; // characteristic impedance + double Z0EH; // characteristic impedance of field quantities*/ + double ang_l; // Electrical length in angle + double er_eff; // Effective dielectric constant + double mur_eff; // Effective mag. permeability + double atten_dielectric; // Loss in dielectric (dB) + double atten_cond; // Loss in conductors (dB) + double fc10; // Cutoff frequency for TE10 mode public: - void analyze() override; - void synthesize() override; - private: double kval_square(); double kc_square( int, int ); @@ -58,7 +62,11 @@ private: void get_rectwaveguide_comp(); void get_rectwaveguide_phys(); void get_rectwaveguide_elec(); - void show_results(); + void show_results() override; + void calcAnalyze() override; + void calcSynthesize() override; + void showAnalyze() override; + void showSynthesize() override; }; -#endif // __RECTWAVEGUIDE_H +#endif // __RECTWAVEGUIDE_H diff --git a/pcb_calculator/transline/stripline.cpp b/pcb_calculator/transline/stripline.cpp index 0074fadff3..8b0ed05e13 100644 --- a/pcb_calculator/transline/stripline.cpp +++ b/pcb_calculator/transline/stripline.cpp @@ -27,44 +27,13 @@ #include #include -#include -#include #include +#include STRIPLINE::STRIPLINE() : TRANSLINE() { m_Name = "StripLine"; - - // Initialize these variables mainly to avoid warnings from a static analyzer - h = 0.0; // height of substrate - a = 0.0; // distance of strip to top metal - t = 0.0; // thickness of top metal - w = 0.0; // width of line - len = 0.0; // length of line - Z0 = 0.0; // characteristic impedance - ang_l = 0.0; // Electrical length in angle - er_eff = 0.0; // effective dielectric constant - atten_dielectric = 0.0; // Loss in dielectric (dB) - atten_cond = 0.0; // Loss in conductors (dB) -} - - -// ------------------------------------------------------------------- -void STRIPLINE::getProperties() -{ - m_freq = getProperty( FREQUENCY_PRM ); - w = getProperty( PHYS_WIDTH_PRM ); - len = getProperty( PHYS_LEN_PRM ); - h = getProperty( H_PRM); - a = getProperty( STRIPLINE_A_PRM ); - t = getProperty( T_PRM ); - - er = getProperty( EPSILONR_PRM ); - m_murC = getProperty( MURC_PRM ); - m_tand = getProperty( TAND_PRM ); - m_sigma = 1.0 / getProperty( RHO_PRM ); - Z0 = getProperty( Z0_PRM ); - ang_l = getProperty( ANG_L_PRM ); + Init(); } @@ -73,33 +42,37 @@ void STRIPLINE::getProperties() double STRIPLINE::lineImpedance( double height, double& ac ) { double ZL; - double hmt = height - t; + double hmt = height - m_parameters[T_PRM]; - ac = sqrt( m_freq / m_sigma / 17.2 ); - if( w / hmt >= 0.35 ) + ac = sqrt( m_parameters[FREQUENCY_PRM] / m_parameters[SIGMA_PRM] / 17.2 ); + if( m_parameters[PHYS_WIDTH_PRM] / hmt >= 0.35 ) { - ZL = w + - ( 2.0 * height * - log( (2.0 * height - t) / hmt ) - t * log( height * height / hmt / hmt - 1.0 ) ) / M_PI; - ZL = ZF0 * hmt / sqrt( er ) / 4.0 / ZL; + 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 * er * ZL / hmt; - ac *= 1.0 + 2.0 * w / hmt + (height + t) / hmt / M_PI* log( 2.0 * height / t - 1.0 ); + 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 = t / w; - if( t / w > 1.0 ) - tdw = w / t; + 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( t / w > 1.0 ) - de *= t / 2.0; + if( m_parameters[T_PRM] / m_parameters[PHYS_WIDTH_PRM] > 1.0 ) + de *= m_parameters[T_PRM] / 2.0; else - de *= w / 2.0; - ZL = ZF0 / 2.0 / M_PI / sqrt( er ) * log( 4.0 * height / M_PI / de ); + 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 ) + 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 ); } @@ -108,103 +81,110 @@ double STRIPLINE::lineImpedance( double height, double& ac ) // ------------------------------------------------------------------- -void STRIPLINE::calc() +void STRIPLINE::calcAnalyze() { - m_skindepth = skin_depth(); + m_parameters[SKIN_DEPTH_PRM] = skin_depth(); - er_eff = er; // no dispersion + m_parameters[EPSILON_EFF_PRM] = m_parameters[EPSILONR_PRM]; // no dispersion double ac1, ac2; - Z0 = 2.0 / - ( 1.0 / lineImpedance( 2.0 * a + t, ac1 ) + 1.0 / lineImpedance( 2.0 * (h - a) - t, 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] * 0.5 * ( ac1 + ac2 ); + m_parameters[LOSS_DIELECTRIC_PRM] = 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] + * ( M_PI / C0 ) * m_parameters[FREQUENCY_PRM] + * sqrt( m_parameters[EPSILONR_PRM] ) + * m_parameters[TAND_PRM]; - atten_cond = len * 0.5 * (ac1 + ac2); - atten_dielectric = 20.0 / log( 10.0 ) * len * (M_PI / C0) * m_freq * sqrt( er ) * m_tand; - - ang_l = 2.0* M_PI* len* sqrt( er ) * m_freq / C0; // in radians + 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 } +void STRIPLINE::showAnalyze() +{ + setProperty( Z0_PRM, m_parameters[Z0_PRM] ); + setProperty( ANG_L_PRM, m_parameters[ANG_L_PRM] ); + + 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 ); + } + + 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() { - setProperty( Z0_PRM, Z0 ); - setProperty( ANG_L_PRM, ang_l ); - setResult( 0, er_eff, "" ); - setResult( 1, atten_cond, "dB" ); - setResult( 2, atten_dielectric, "dB" ); + setResult( 0, m_parameters[EPSILON_EFF_PRM], "" ); + setResult( 1, m_parameters[LOSS_CONDUCTOR_PRM], "dB" ); + setResult( 2, m_parameters[LOSS_DIELECTRIC_PRM], "dB" ); - setResult( 3, m_skindepth / UNIT_MICRON, "µm" ); -} - - -// ------------------------------------------------------------------- -void STRIPLINE::analyze() -{ - getProperties(); - calc(); - show_results(); + setResult( 3, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); } #define MAX_ERROR 0.000001 // ------------------------------------------------------------------- -void STRIPLINE::synthesize() +void STRIPLINE::calcSynthesize() { - double Z0_dest, Z0_current, Z0_result, increment, slope, error; - int iteration; - - getProperties(); - - /* required value of Z0 */ - Z0_dest = Z0; - - /* Newton's method */ - iteration = 0; - - /* compute parameters */ - calc(); - Z0_current = Z0; - - error = fabs( Z0_dest - Z0_current ); - - while( error > MAX_ERROR ) - { - iteration++; - increment = w / 100.0; - w += increment; - /* compute parameters */ - calc(); - Z0_result = Z0; - /* 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)) */ - slope = (Z0_result - Z0_current) / increment; - slope = (Z0_dest - Z0_current) / slope - increment; - w += slope; - if( w <= 0.0 ) - w = increment; - /* find new error */ - /* compute parameters */ - calc(); - Z0_current = Z0; - error = fabs( Z0_dest - Z0_current ); - if( iteration > 100 ) - break; - } - - setProperty( PHYS_WIDTH_PRM, w ); - /* calculate physical length */ - ang_l = getProperty( ANG_L_PRM ); - len = C0 / m_freq / sqrt( er_eff ) * ang_l / 2.0 / M_PI; /* in m */ - setProperty( PHYS_LEN_PRM, len ); - - /* compute parameters */ - calc(); - - /* print results in the subwindow */ - show_results(); + minimizeZ0Error1D( &( m_parameters[PHYS_WIDTH_PRM] ) ); } diff --git a/pcb_calculator/transline/stripline.h b/pcb_calculator/transline/stripline.h index 300885f420..c033776565 100644 --- a/pcb_calculator/transline/stripline.h +++ b/pcb_calculator/transline/stripline.h @@ -24,31 +24,21 @@ #ifndef __STRIPLINE_H #define __STRIPLINE_H + +#include + class STRIPLINE : public TRANSLINE { -public: STRIPLINE(); - -private: - double h; // height of substrate - double a; // distance of strip to top metal - double t; // thickness of top metal - double w; // width of line - double len; // length of line - double Z0; // characteristic impedance - double ang_l; // electrical length in angle - double er_eff; // effective dielectric constant - double atten_dielectric; // loss in dielectric (dB) - double atten_cond; // loss in conductors (dB) - public: - void analyze() override; - void synthesize() override; + STRIPLINE(); private: + void calcAnalyze() override; + void calcSynthesize() override; + void showSynthesize() override; + void showAnalyze() override; double lineImpedance( double, double& ); - void calc(); - void show_results(); - void getProperties(); + void show_results() override; }; #endif diff --git a/pcb_calculator/transline/transline.cpp b/pcb_calculator/transline/transline.cpp index 0d57f7b2ee..3af917c972 100644 --- a/pcb_calculator/transline/transline.cpp +++ b/pcb_calculator/transline/transline.cpp @@ -1,3 +1,4 @@ + /* * TRANSLINE.cpp - base for a transmission line implementation * @@ -33,7 +34,7 @@ #ifndef M_PI_2 -#define M_PI_2 (M_PI/2) +#define M_PI_2 ( M_PI / 2 ) #endif @@ -55,21 +56,22 @@ double GetPropertyInDialog( enum PRMS_ID aPrmId ); // Returns true if the param aPrmId is selected // Has meaning only for params that have a radio button -bool IsSelectedInDialog( enum PRMS_ID aPrmId ); +bool IsSelectedInDialog( enum PRMS_ID aPrmId ); + +/** Function SetPropertyBgColorInDialog + * Set the background color of a parameter + * @param aPrmId = param id to set + * @param aCol = new color + */ +void SetPropertyBgColorInDialog( enum PRMS_ID aPrmId, const KIGFX::COLOR4D* aCol ); /* Constructor creates a transmission line instance. */ TRANSLINE::TRANSLINE() { - m_murC = 1.0; - m_Name = nullptr; - - // Initialize these variables mainly to avoid warnings from a static analyzer - m_freq = 0.0; // Frequency of operation - er = 0.0; // dielectric constant - m_tand = 0.0; // Dielectric Loss Tangent - m_sigma = 0.0; // Conductivity of the metal - m_skindepth = 0.0; // Skin depth + m_parameters[MURC_PRM] = 1.0; + m_Name = nullptr; + Init(); } @@ -79,6 +81,22 @@ TRANSLINE::~TRANSLINE() } +void TRANSLINE::Init( void ) +{ + wxColour wxcol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); + okCol = KIGFX::COLOR4D( wxcol ); + okCol.r = wxcol.Red() / 255.0; + okCol.g = wxcol.Green() / 255.0; + okCol.b = wxcol.Blue() / 255.0; + int i; + // Initialize these variables mainly to avoid warnings from a static analyzer + for( i = 0; i < EXTRA_PRMS_COUNT; ++i ) + { + m_parameters[i] = 0; + } +} + + /* Sets a named property to the given value, access through the * application. */ @@ -87,6 +105,7 @@ void TRANSLINE::setProperty( enum PRMS_ID aPrmId, double value ) SetPropertyInDialog( aPrmId, value ); } + /* *Returns true if the param aPrmId is selected * Has meaning only for params that have a radio button @@ -115,14 +134,101 @@ double TRANSLINE::getProperty( enum PRMS_ID aPrmId ) return GetPropertyInDialog( aPrmId ); } -/* - * skin_depth - calculate skin depth +/** @function getProperties + * + * Get all properties from the UI. Computes some extra ones. + **/ +void TRANSLINE::getProperties( void ) +{ + int i; + for( i = 0; i < DUMMY_PRM; ++i ) + { + m_parameters[i] = getProperty( (PRMS_ID) i ); + setErrorLevel( (PRMS_ID) i, TRANSLINE_OK ); + } + m_parameters[SIGMA_PRM] = 1.0 / getProperty( RHO_PRM ); + m_parameters[EPSILON_EFF_PRM] = 1.0; + m_parameters[SKIN_DEPTH_PRM] = skin_depth(); +} +/** @function checkProperties + * + * Checks the input parameters (ie: negative length). + * Does not check for incompatibility between values as this depends on the line shape. + **/ +void TRANSLINE::checkProperties( void ) +{ + // Do not check for values that are results of anylzing / synthesizing + // Do not check for transline specific incompatibilities ( like " conductor height sould be lesser than dielectric height") + if( !std::isfinite( m_parameters[EPSILONR_PRM] ) || m_parameters[EPSILONR_PRM] <= 0 ) + setErrorLevel( EPSILONR_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[TAND_PRM] ) || m_parameters[TAND_PRM] < 0 ) + setErrorLevel( TAND_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[RHO_PRM] ) || m_parameters[RHO_PRM] < 0 ) + setErrorLevel( RHO_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[H_PRM] ) || m_parameters[H_PRM] < 0 ) + setErrorLevel( H_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[TWISTEDPAIR_TWIST_PRM] ) + || m_parameters[TWISTEDPAIR_TWIST_PRM] < 0 ) + setErrorLevel( TWISTEDPAIR_TWIST_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[STRIPLINE_A_PRM] ) || m_parameters[STRIPLINE_A_PRM] <= 0 ) + setErrorLevel( STRIPLINE_A_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[H_T_PRM] ) || m_parameters[H_T_PRM] <= 0 ) + setErrorLevel( H_T_PRM, TRANSLINE_WARNING ); + + // How can we check ROUGH_PRM ? + + if( !std::isfinite( m_parameters[MUR_PRM] ) || m_parameters[MUR_PRM] < 0 ) + setErrorLevel( MUR_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[TWISTEDPAIR_EPSILONR_ENV_PRM] ) + || m_parameters[TWISTEDPAIR_EPSILONR_ENV_PRM] <= 0 ) + setErrorLevel( TWISTEDPAIR_EPSILONR_ENV_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[MURC_PRM] ) || m_parameters[MURC_PRM] < 0 ) + setErrorLevel( MURC_PRM, TRANSLINE_WARNING ); + + if( !std::isfinite( m_parameters[FREQUENCY_PRM] ) || m_parameters[FREQUENCY_PRM] <= 0 ) + setErrorLevel( FREQUENCY_PRM, TRANSLINE_WARNING ); +} + +void TRANSLINE::analyze() +{ + getProperties(); + checkProperties(); + calcAnalyze(); + showAnalyze(); + show_results(); +} + +void TRANSLINE::synthesize() +{ + getProperties(); + checkProperties(); + calcSynthesize(); + showSynthesize(); + show_results(); +} + + +/** + * @function skin_depth + * calculate skin depth + * + * \f$ \frac{1}{\sqrt{ \pi \cdot f \cdot \mu \cdot \sigma }} \f$ */ #include double TRANSLINE::skin_depth() { double depth; - depth = 1.0 / sqrt( M_PI * m_freq * m_murC * MU0 * m_sigma ); + depth = 1.0 + / sqrt( M_PI * m_parameters[FREQUENCY_PRM] * m_parameters[MURC_PRM] * MU0 + * m_parameters[SIGMA_PRM] ); return depth; } @@ -161,19 +267,19 @@ void TRANSLINE::ellipke( double arg, double& k, double& e ) { fk = 1 / sqrt( 1 - arg ); fe = sqrt( 1 - arg ); - da = -arg / (1 - arg); + da = -arg / ( 1 - arg ); } - a = 1; - b = sqrt( 1 - da ); - c = sqrt( da ); + a = 1; + b = sqrt( 1 - da ); + c = sqrt( da ); fr = 0.5; - s = fr * c * c; + s = fr * c * c; for( i = 0; i < iMax; i++ ) { - t = (a + b) / 2; - c = (a - b) / 2; - b = sqrt( a * b ); - a = t; + 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 ) @@ -182,12 +288,13 @@ void TRANSLINE::ellipke( double arg, double& k, double& e ) if( i >= iMax ) { - k = 0; e = 0; + k = 0; + e = 0; } else { k = M_PI_2 / a; - e = M_PI_2 * (1 - s) / a; + e = M_PI_2 * ( 1 - s ) / a; if( arg < 0 ) { k *= fk; @@ -206,3 +313,122 @@ double TRANSLINE::ellipk( double k ) ellipke( k, r, lost ); return r; } + +#define MAX_ERROR 0.000001 + +/** + * @function minimizeZ0Error1D + * + * Tries to find a parameter that minimizes the error ( on Z0 ). + * This function only works with a single parameter. + * Calls @ref calcAnalyze several times until the error is acceptable. + * While the error is unnacceptable, changes slightly the parameter. + * + * This function does not change Z0 / Angl_L. + * + * @param avar Parameter to synthesize + * @return 'true' if error < MAX_ERROR, else 'false' + */ + + +bool TRANSLINE::minimizeZ0Error1D( double* aVar ) +{ + double Z0_dest, Z0_current, Z0_result, angl_l_dest, increment, slope, error; + int iteration; + + if( !std::isfinite( m_parameters[Z0_PRM] ) ) + { + *aVar = NAN; + return false; + } + + if( ( !std::isfinite( *aVar ) ) || ( *aVar == 0 ) ) + { + *aVar = 0.001; + } + + /* required value of Z0 */ + Z0_dest = m_parameters[Z0_PRM]; + + /* required value of angl_l */ + angl_l_dest = m_parameters[ANG_L_PRM]; + + /* Newton's method */ + iteration = 0; + + /* compute parameters */ + calcAnalyze(); + Z0_current = m_parameters[Z0_PRM]; + + error = fabs( Z0_dest - Z0_current ); + + while( error > MAX_ERROR ) + { + iteration++; + increment = *aVar / 100.0; + *aVar += increment; + /* compute parameters */ + calcAnalyze(); + Z0_result = m_parameters[Z0_PRM]; + /* 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)) */ + slope = ( Z0_result - Z0_current ) / increment; + slope = ( Z0_dest - Z0_current ) / slope - increment; + *aVar += slope; + if( *aVar <= 0.0 ) + *aVar = increment; + /* find new error */ + /* compute parameters */ + calcAnalyze(); + Z0_current = m_parameters[Z0_PRM]; + error = fabs( Z0_dest - Z0_current ); + + if( iteration > 100 ) + break; + } + + /* Compute one last time, but with correct length */ + m_parameters[Z0_PRM] = Z0_dest; + m_parameters[ANG_L_PRM] = angl_l_dest; + m_parameters[PHYS_LEN_PRM] = C0 / m_parameters[FREQUENCY_PRM] + / sqrt( m_parameters[EPSILON_EFF_PRM] ) * m_parameters[ANG_L_PRM] + / 2.0 / M_PI; /* in m */ + calcAnalyze(); + + /* Restore parameters */ + m_parameters[Z0_PRM] = Z0_dest; + m_parameters[ANG_L_PRM] = angl_l_dest; + m_parameters[PHYS_LEN_PRM] = C0 / m_parameters[FREQUENCY_PRM] + / sqrt( m_parameters[EPSILON_EFF_PRM] ) * m_parameters[ANG_L_PRM] + / 2.0 / M_PI; /* in m */ + return error <= MAX_ERROR; +} +/** + * @function setErrorLevel + * + * set an error / warning level for a given parameter. + * + * @see TRANSLINE_OK + * @see TRANSLINE_WARNING + * @see TRANSLINE_ERROR + * + * @param aP parameter + * @param aErrorLevel Error level + */ +void TRANSLINE::setErrorLevel( PRMS_ID aP, char aErrorLevel ) +{ + switch( aErrorLevel ) + { + case( TRANSLINE_WARNING ): + SetPropertyBgColorInDialog( aP, &warnCol ); + break; + case( TRANSLINE_ERROR ): + SetPropertyBgColorInDialog( aP, &errCol ); + break; + default: + SetPropertyBgColorInDialog( aP, &okCol ); + break; + } +} diff --git a/pcb_calculator/transline/transline.h b/pcb_calculator/transline/transline.h index 8b5f7e50f7..e820706682 100644 --- a/pcb_calculator/transline/transline.h +++ b/pcb_calculator/transline/transline.h @@ -24,63 +24,109 @@ #ifndef __TRANSLINE_H #define __TRANSLINE_H +#include +#include + +#define TRANSLINE_OK 0 +#define TRANSLINE_WARNING 1 +#define TRANSLINE_ERROR 2 + // IDs for lines parameters used in calculation: // (Used to retrieve these parameters from UI. // DUMMY_PRM is used to skip a param line in dialogs. It is not really a parameter enum PRMS_ID { - UNKNOWN_ID = 0, - EPSILONR_PRM, - TAND_PRM, - RHO_PRM, - H_PRM, - TWISTEDPAIR_TWIST_PRM, + UNKNOWN_ID = -1, + EPSILONR_PRM, // dielectric constant + TAND_PRM, // Dielectric Loss Tangent + RHO_PRM, // Conductivity of conductor + H_PRM, // height of substrate + TWISTEDPAIR_TWIST_PRM, // Twists per length H_T_PRM, - STRIPLINE_A_PRM, - T_PRM, + STRIPLINE_A_PRM, // Stripline : distance from line to top metal + T_PRM, // thickness of top metal ROUGH_PRM, - MUR_PRM, + MUR_PRM, // magnetic permeability of substrate TWISTEDPAIR_EPSILONR_ENV_PRM, - MURC_PRM, - FREQUENCY_PRM, - Z0_PRM, + MURC_PRM, // magnetic permeability of conductor + FREQUENCY_PRM, // Frequency of operation + Z0_PRM, // characteristic impedance Z0_E_PRM, Z0_O_PRM, - ANG_L_PRM, + ANG_L_PRM, // Electrical length in angle PHYS_WIDTH_PRM, - PHYS_DIAM_IN_PRM, - PHYS_S_PRM, - PHYS_DIAM_OUT_PRM, - PHYS_LEN_PRM, + PHYS_DIAM_IN_PRM, // Inner diameter of cable + PHYS_S_PRM, // width of gap between line and ground + PHYS_DIAM_OUT_PRM, // Outer diameter of cable + PHYS_LEN_PRM, // Length of cable DUMMY_PRM }; + +// IDs for lines parameters used in calculation that are not given by the UI +enum EXTRA_PRMS_ID +{ + EXTRA_PRMS_START = DUMMY_PRM - 1, + SIGMA_PRM, // Conductivity of the metal + SKIN_DEPTH_PRM, // Skin depth + LOSS_DIELECTRIC_PRM, // Loss in dielectric (dB) + LOSS_CONDUCTOR_PRM, // Loss in conductors (dB) + CUTOFF_FREQUENCY_PRM, // Cutoff frequency for higher order modes + EPSILON_EFF_PRM, // Effective dielectric constant + EXTRA_PRMS_COUNT, +}; + class TRANSLINE { -public: TRANSLINE(); +public: + TRANSLINE(); virtual ~TRANSLINE(); - const char *m_Name; - void setProperty( enum PRMS_ID aPrmId, double aValue); - double getProperty( enum PRMS_ID aPrmId ); - void setResult( int, double, const char* ); - void setResult( int, const char* ); - bool isSelected( enum PRMS_ID aPrmId ); + const char* m_Name; + void setProperty( enum PRMS_ID aPrmId, double aValue ); + double getProperty( enum PRMS_ID aPrmId ); - virtual void synthesize() { }; - virtual void analyze() { }; + + void getProperties( void ); + void checkProperties( void ); + void setResult( int, double, const char* ); + void setResult( int, const char* ); + bool isSelected( enum PRMS_ID aPrmId ); + + void Init(); + virtual void synthesize(); + virtual void calc(){}; + /** @brief Computation for analysis + */ + virtual void calcAnalyze(){}; + /** @brief Computation for synthesis + **/ + virtual void calcSynthesize(){}; + /** @brief Shows synthesis results and checks for errors / warnings. + **/ + virtual void showAnalyze(){}; + /** @brief Shows analysis results and checks for errors / warnings. + **/ + virtual void showSynthesize(){}; + /** @brief Shows results + **/ + virtual void show_results(){}; + void analyze(); + KIGFX::COLOR4D errCol = KIGFX::COLOR4D( 1, 0.63, 0.63, 1 ); + KIGFX::COLOR4D warnCol = KIGFX::COLOR4D( 1, 1, 0.57, 1 ); + KIGFX::COLOR4D okCol = KIGFX::COLOR4D( 1, 1, 1, 1 ); protected: - double m_freq; // Frequency of operation - double er; /* dielectric constant */ - double m_tand; // Dielectric Loss Tangent - double m_sigma; // Conductivity of the metal - double m_murC; // magnetic permeability of conductor - double m_skindepth; // Skin depth + double m_parameters[EXTRA_PRMS_COUNT]; + double len; // length of line + double er_eff; // effective dielectric constant + double ang_l; // Electrical length in angle + bool minimizeZ0Error1D( double* ); double skin_depth(); void ellipke( double, double&, double& ); double ellipk( double ); + void setErrorLevel( PRMS_ID, char ); }; #endif /* __TRANSLINE_H */ diff --git a/pcb_calculator/transline/twistedpair.cpp b/pcb_calculator/transline/twistedpair.cpp index b6ab6ee006..4cfc9185c0 100644 --- a/pcb_calculator/transline/twistedpair.cpp +++ b/pcb_calculator/transline/twistedpair.cpp @@ -27,159 +27,181 @@ #include #include -#include -#include #include +#include TWISTEDPAIR::TWISTEDPAIR() : TRANSLINE() { m_Name = "TwistedPair"; - - // Initialize these variables mainly to avoid warnings from a static analyzer - din = 0.0; // Inner diameter of conductor - dout = 0.0; // Outer diameter of insulator - twists = 0.0; // Twists per length - er_env = 0.0; // dielectric constant of environment*/ - len = 0.0; // Length of cable - Z0 = 0.0; // characteristic impedance - ang_l = 0.0; // Electrical length in angle - atten_dielectric = 0.0; // Loss in dielectric (dB) - atten_cond = 0.0; // Loss in conductors (dB) - er_eff = 1.0; // Effective dielectric constant + Init(); } -// ------------------------------------------------------------------- -void TWISTEDPAIR::getProperties() +/** + * \f$ \theta = \arctan\left( T \cdot \pi \cdot D_{out} \right) \f$ + * + * Where : + * - \f$ \theta \f$ : pitch angle + * - \f$ T \f$ : Number of twists per unit length + * - \f$ D_{out} \f$ : Wire diameter with insulation + * + * \f$ e_{eff} = e_{env} \cdot \left( 0.25 + 0.0007 \cdot \theta^2 \right)\cdot\left(e_r-e_{env}\right) \f$ + * + * Where : + * - \f$ e_{env} \f$ : relative dielectric constant of air ( or some other surronding material ), + * - \f$ e_r \f$ : relative dielectric constant of the film insulation, + * - \f$ e_{eff} \f$ : effective relative dielectric constant + * + * \f$ Z_0 = \frac{Z_\mathrm{VACCUM}}{\pi \cdot \sqrt{e_{eff}}}\cosh^{-1}\left(\frac{D_{out}}{D_{in}}\right) \f$ + * + * - \f$ Z_0 \f$ : line impedance + * - \f$ Z_\mathrm{VACCUM} \f$ : vaccum impedance + * - \f$ D_{in} \f$ : Wire diameter without insulation + * + * Reference for above equations : + * + * [1] : P. Lefferson, ``Twisted Magnet Wire Transmission Line,'' + * IEEE Transactions on Parts, Hybrids, and Packaging, vol. PHP-7, no. 4, pp. 148-154, Dec. 1971. + * + * The following URL can be used as reference : http://qucs.sourceforge.net/tech/node93.html + **/ +void TWISTEDPAIR::calcAnalyze() { - m_freq = getProperty( FREQUENCY_PRM ); - din = getProperty( PHYS_DIAM_IN_PRM ); - dout = getProperty( PHYS_DIAM_OUT_PRM ); - len = getProperty( PHYS_LEN_PRM ); - er = getProperty( EPSILONR_PRM ); - m_murC = getProperty( MURC_PRM ); - m_tand = getProperty( TAND_PRM ); - m_sigma = 1.0 / getProperty( RHO_PRM ); - twists = getProperty( TWISTEDPAIR_TWIST_PRM ); - er_env = getProperty( TWISTEDPAIR_EPSILONR_ENV_PRM ); - Z0 = getProperty( Z0_PRM ); - ang_l = getProperty( ANG_L_PRM ); -} + double tw = atan( m_parameters[TWISTEDPAIR_TWIST_PRM] * M_PI + * m_parameters[PHYS_DIAM_OUT_PRM] ); // pitch angle + m_parameters[EPSILON_EFF_PRM] = + m_parameters[TWISTEDPAIR_EPSILONR_ENV_PRM] + + ( 0.25 + 0.0007 * tw * tw ) + * ( m_parameters[EPSILONR_PRM] - m_parameters[TWISTEDPAIR_EPSILONR_ENV_PRM] ); + m_parameters[Z0_PRM] = + ZF0 / M_PI / sqrt( m_parameters[EPSILON_EFF_PRM] ) + * acosh( m_parameters[PHYS_DIAM_OUT_PRM] / m_parameters[PHYS_DIAM_IN_PRM] ); -// ------------------------------------------------------------------- -void TWISTEDPAIR::calc() -{ - m_skindepth = skin_depth(); + m_parameters[LOSS_CONDUCTOR_PRM] = + 10.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] / m_parameters[SKIN_DEPTH_PRM] + / m_parameters[SIGMA_PRM] / M_PI / m_parameters[Z0_PRM] + / ( m_parameters[PHYS_DIAM_IN_PRM] - m_parameters[SKIN_DEPTH_PRM] ); - double tw = atan( twists * M_PI * dout ); // pitch angle - er_eff = er_env + (0.25 + 0.0007 * tw * tw) * (er - er_env); + m_parameters[LOSS_DIELECTRIC_PRM] = 20.0 / log( 10.0 ) * m_parameters[PHYS_LEN_PRM] * M_PI / C0 + * m_parameters[FREQUENCY_PRM] + * sqrt( m_parameters[EPSILON_EFF_PRM] ) + * m_parameters[TAND_PRM]; - Z0 = ZF0 / M_PI / sqrt( er_eff ) * acosh( dout / din ); - - atten_cond = 10.0 / log( 10.0 ) * len / m_skindepth / m_sigma / M_PI / Z0 / (din - m_skindepth); - - atten_dielectric = 20.0 / log( 10.0 ) * len * M_PI / C0* m_freq * sqrt( er_eff ) * m_tand; - - ang_l = 2.0* M_PI* len* sqrt( er_eff ) * m_freq / C0; // in radians + m_parameters[ANG_L_PRM] = 2.0 * M_PI * m_parameters[PHYS_LEN_PRM] + * sqrt( m_parameters[EPSILON_EFF_PRM] ) * m_parameters[FREQUENCY_PRM] + / C0; // in radians } // ------------------------------------------------------------------- void TWISTEDPAIR::show_results() { - setProperty( Z0_PRM, Z0 ); - setProperty( ANG_L_PRM, ang_l ); - - setResult( 0, er_eff, "" ); - setResult( 1, atten_cond, "dB" ); - setResult( 2, atten_dielectric, "dB" ); - - setResult( 3, m_skindepth / UNIT_MICRON, "µm" ); + setResult( 0, m_parameters[EPSILON_EFF_PRM], "" ); + setResult( 1, m_parameters[LOSS_CONDUCTOR_PRM], "dB" ); + setResult( 2, m_parameters[LOSS_DIELECTRIC_PRM], "dB" ); + setResult( 3, m_parameters[SKIN_DEPTH_PRM] / UNIT_MICRON, "µm" ); } - -// ------------------------------------------------------------------- -void TWISTEDPAIR::analyze() +void TWISTEDPAIR::showAnalyze() { - getProperties(); - calc(); - show_results(); + 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 ); + } + + // Find warnings to display - physical parameters + if( !std::isfinite( m_parameters[PHYS_DIAM_IN_PRM] ) || m_parameters[PHYS_DIAM_IN_PRM] <= 0.0 ) + { + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_WARNING ); + } + + if( !std::isfinite( m_parameters[PHYS_DIAM_OUT_PRM] ) + || m_parameters[PHYS_DIAM_OUT_PRM] <= 0.0 ) + { + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_WARNING ); + } + + if( m_parameters[PHYS_DIAM_IN_PRM] > m_parameters[PHYS_DIAM_OUT_PRM] ) + { + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_WARNING ); + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_WARNING ); + } + + if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0.0 ) + { + setErrorLevel( PHYS_LEN_PRM, TRANSLINE_WARNING ); + } +} + +void TWISTEDPAIR::showSynthesize() +{ + if( isSelected( PHYS_DIAM_IN_PRM ) ) + setProperty( PHYS_DIAM_IN_PRM, m_parameters[PHYS_DIAM_IN_PRM] ); + else if( isSelected( PHYS_DIAM_OUT_PRM ) ) + setProperty( PHYS_DIAM_OUT_PRM, m_parameters[PHYS_DIAM_OUT_PRM] ); + setProperty( PHYS_LEN_PRM, m_parameters[PHYS_LEN_PRM] ); + + // Check for errors + if( !std::isfinite( m_parameters[PHYS_DIAM_IN_PRM] ) || m_parameters[PHYS_DIAM_IN_PRM] <= 0.0 ) + { + if( isSelected( PHYS_DIAM_IN_PRM ) ) + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_ERROR ); + else + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_WARNING ); + } + + if( !std::isfinite( m_parameters[PHYS_DIAM_OUT_PRM] ) + || m_parameters[PHYS_DIAM_OUT_PRM] <= 0.0 ) + { + if( isSelected( PHYS_DIAM_OUT_PRM ) ) + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_ERROR ); + else + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_WARNING ); + } + + if( m_parameters[PHYS_DIAM_IN_PRM] > m_parameters[PHYS_DIAM_OUT_PRM] ) + { + if( isSelected( PHYS_DIAM_IN_PRM ) ) + setErrorLevel( PHYS_DIAM_IN_PRM, TRANSLINE_ERROR ); + else if( isSelected( PHYS_DIAM_OUT_PRM ) ) + setErrorLevel( PHYS_DIAM_OUT_PRM, TRANSLINE_ERROR ); + } + + if( !std::isfinite( m_parameters[PHYS_LEN_PRM] ) || m_parameters[PHYS_LEN_PRM] < 0.0 ) + { + setErrorLevel( PHYS_LEN_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 ); + } } #define MAX_ERROR 0.000001 // ------------------------------------------------------------------- -void TWISTEDPAIR::synthesize() +void TWISTEDPAIR::calcSynthesize() { - double Z0_dest, Z0_current, Z0_result, increment, slope, error; - int iteration; - - getProperties(); - - /* required value of Z0 */ - Z0_dest = Z0; - - /* Newton's method */ - iteration = 0; - - /* compute parameters */ - calc(); - Z0_current = Z0; - - error = fabs( Z0_dest - Z0_current ); - - while( error > MAX_ERROR ) - { - iteration++; - if( isSelected( PHYS_DIAM_IN_PRM ) ) - { - increment = din / 100.0; - din += increment; - } - else - { - increment = dout / 100.0; - dout += increment; - } - /* compute parameters */ - calc(); - Z0_result = Z0; - /* 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)) */ - slope = (Z0_result - Z0_current) / increment; - slope = (Z0_dest - Z0_current) / slope - increment; - if( isSelected( PHYS_DIAM_IN_PRM ) ) - din += slope; - else - dout += slope; - if( din <= 0.0 ) - din = increment; - if( dout <= 0.0 ) - dout = increment; - /* find new error */ - /* compute parameters */ - calc(); - Z0_current = Z0; - error = fabs( Z0_dest - Z0_current ); - if( iteration > 100 ) - break; - } - - setProperty( PHYS_DIAM_IN_PRM, din ); - setProperty( PHYS_DIAM_OUT_PRM, dout ); - /* calculate physical length */ - ang_l = getProperty( ANG_L_PRM ); - len = C0 / m_freq / sqrt( er_eff ) * ang_l / 2.0 / M_PI; /* in m */ - setProperty( PHYS_LEN_PRM, len ); - - /* compute parameters */ - calc(); - - /* print results in the subwindow */ - show_results(); + if( isSelected( PHYS_DIAM_IN_PRM ) ) + minimizeZ0Error1D( &( m_parameters[PHYS_DIAM_IN_PRM] ) ); + else + minimizeZ0Error1D( &( m_parameters[PHYS_DIAM_OUT_PRM] ) ); } diff --git a/pcb_calculator/transline/twistedpair.h b/pcb_calculator/transline/twistedpair.h index d41361f334..74e8eec844 100644 --- a/pcb_calculator/transline/twistedpair.h +++ b/pcb_calculator/transline/twistedpair.h @@ -24,30 +24,19 @@ #ifndef __TWISTEDPAIR_H #define __TWISTEDPAIR_H +#include + class TWISTEDPAIR : public TRANSLINE { -public: TWISTEDPAIR(); - -private: - double din; // Inner diameter of conductor - double dout; // Outer diameter of insulator - double twists; // Twists per length - double er_env; // dielectric constant of environment*/ - double len; // Length of cable - double Z0; // characteristic impedance - double ang_l; // Electrical length in angle - double er_eff; // Effective dielectric constant - double atten_dielectric; // Loss in dielectric (dB) - double atten_cond; // Loss in conductors (dB) - public: - void analyze() override; - void synthesize() override; + TWISTEDPAIR(); private: - void calc(); - void show_results(); - void getProperties(); + void calcAnalyze() override; + void calcSynthesize() override; + void showAnalyze() override; + void showSynthesize() override; + void show_results() override; }; #endif diff --git a/pcb_calculator/transline_dlg_funct.cpp b/pcb_calculator/transline_dlg_funct.cpp index 5bb7d9a249..8405a7bc28 100644 --- a/pcb_calculator/transline_dlg_funct.cpp +++ b/pcb_calculator/transline_dlg_funct.cpp @@ -17,8 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ -#include #include +#include +#include #include @@ -316,7 +317,7 @@ void PCB_CALCULATOR_FRAME::TranslineTypeSelection( enum TRANSLINE_TYPE_ID aType } wxASSERT ( data ); data->name->SetToolTip( prm->m_ToolTip ); - data->name->SetLabel( prm->m_Label ); + data->name->SetLabel( prm->m_Label != "" ? prm->m_Label + ':' : "" ); prm->m_ValueCtrl = data->value; if( prm->m_Id != DUMMY_PRM ) { @@ -436,6 +437,25 @@ void PCB_CALCULATOR_FRAME::OnTranslineSelection( wxCommandEvent& event ) // The new size must be taken in account m_panelTransline->GetSizer()->Layout(); m_panelTransline->Refresh(); + // Delete previous warnings / errors + wxColour background = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); + + m_Value_EpsilonR->SetBackgroundColour( background ); + m_Value_TanD->SetBackgroundColour( background ); + m_Value_Rho->SetBackgroundColour( background ); + m_Substrate_prm4_Value->SetBackgroundColour( background ); + m_Substrate_prm5_Value->SetBackgroundColour( background ); + m_Substrate_prm6_Value->SetBackgroundColour( background ); + m_Substrate_prm7_Value->SetBackgroundColour( background ); + m_Substrate_prm8_Value->SetBackgroundColour( background ); + m_Substrate_prm9_Value->SetBackgroundColour( background ); + m_Value_Frequency_Ctrl->SetBackgroundColour( background ); + m_Phys_prm1_Value->SetBackgroundColour( background ); + m_Phys_prm2_Value->SetBackgroundColour( background ); + m_Phys_prm3_Value->SetBackgroundColour( background ); + m_elec_prm1_label->SetBackgroundColour( background ); + m_elec_prm2_label->SetBackgroundColour( background ); + m_elec_prm3_label->SetBackgroundColour( background ); } diff --git a/pcb_calculator/transline_ident.cpp b/pcb_calculator/transline_ident.cpp index f57f29e4bd..3232c3c0e5 100644 --- a/pcb_calculator/transline_ident.cpp +++ b/pcb_calculator/transline_ident.cpp @@ -107,21 +107,21 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) // Add common prms: // Default values are for FR4 AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, EPSILONR_PRM, - _( "Er:" ), _( "Epsilon R: substrate relative dielectric constant" ), + _( "Er" ), _( "Epsilon R: substrate relative dielectric constant" ), 4.6, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, TAND_PRM, - _( "TanD:" ), _( "Tangent delta: dielectric loss factor." ), 2e-2, + _( "TanD" ), _( "Tangent delta: dielectric loss factor." ), 2e-2, false ) ); // Default value is for copper AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, RHO_PRM, - _( "Rho:" ), + _( "Rho" ), _( "Electrical resistivity or specific electrical resistance of conductor (Ohm*meter)" ), 1.72e-8, false ) ); // Default value is in GHz AddPrm( new TRANSLINE_PRM( PRM_TYPE_FREQUENCY, FREQUENCY_PRM, - _( "Frequency:" ), _( "Frequency of the input signal" ), 1.0, true ) ); + _( "Frequency" ), _( "Frequency of the input signal" ), 1.0, true ) ); switch( m_Type ) @@ -136,30 +136,30 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "Skin Depth:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_PRM, - _( "H:" ), _( "Height of Substrate" ), 0.2, true ) ); + _( "H" ), _( "Height of Substrate" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_T_PRM, - _( "H_t:" ), _( "Height of Box Top" ), 1e20, true ) ); + _( "H_t" ), _( "Height of Box Top" ), 1e20, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, T_PRM, - _( "T:" ), _( "Strip Thickness" ), 0.035, true ) ); + _( "T" ), _( "Strip Thickness" ), 0.035, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, ROUGH_PRM, - _( "Rough:" ), _( "Conductor Roughness" ), 0.0, true ) ); + _( "Rough" ), _( "Conductor Roughness" ), 0.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MUR_PRM, - _( "mu Rel S:" ), + _( "mu Rel S" ), _( "Relative Permeability (mu) of Substrate" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_WIDTH_PRM, - _( "W:" ), _( "Line Width" ), 0.2, true ) ); + _( "W" ), _( "Line Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Line Length" ), 50.0, true ) ); + _( "L" ), _( "Line Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_PRM, - _( "Z0:" ), _( "Characteristic Impedance" ), 50.0, true ) ); + _( "Z0" ), _( "Characteristic Impedance" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, DUMMY_PRM ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l:" ), _( "Electrical Length" ), 0.0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; case CPW_TYPE: // coplanar waveguide @@ -173,25 +173,25 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "Skin Depth:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_PRM, - _( "H:" ), _( "Height of Substrate" ), 0.2, true ) ); + _( "H" ), _( "Height of Substrate" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, T_PRM, - _( "T:" ), _( "Strip Thickness" ), 0.035, true ) ); + _( "T" ), _( "Strip Thickness" ), 0.035, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_WIDTH_PRM, - _( "W:" ), _( "Line Width" ), 0.2, true ) ); + _( "W" ), _( "Line Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_S_PRM, - _( "S:" ), _( "Gap Width" ), 0.2, true ) ); + _( "S" ), _( "Gap Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Line Length" ), 50.0, true ) ); + _( "L" ), _( "Line Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_PRM, - _( "Z0:" ), _( "Characteristic Impedance" ), 50.0, true ) ); + _( "Z0" ), _( "Characteristic Impedance" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, DUMMY_PRM ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l:" ), _( "Electrical Length" ), 0.0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; case GROUNDED_CPW_TYPE: // grounded coplanar waveguide @@ -205,25 +205,25 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "Skin Depth:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_PRM, - _( "H:" ), _( "Height of Substrate" ), 0.2, true ) ); + _( "H" ), _( "Height of Substrate" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, T_PRM, - _( "T:" ), _( "Strip Thickness" ), 0.035, true ) ); + _( "T" ), _( "Strip Thickness" ), 0.035, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_WIDTH_PRM, - _( "W:" ), _( "Line Width" ), 0.2, true ) ); + _( "W" ), _( "Line Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_S_PRM, - _( "S:" ), _( "Gap Width" ), 0.2, true ) ); + _( "S" ), _( "Gap Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Line Length" ), 50.0, true ) ); + _( "L" ), _( "Line Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_PRM, - _( "Z0:" ), _( "Characteristic Impedance" ), 50.0, true ) ); + _( "Z0" ), _( "Characteristic Impedance" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, DUMMY_PRM ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l:" ), _( "Electrical Length" ), 0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0, true ) ); break; @@ -240,23 +240,23 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "TM-Modes:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MUR_PRM, - _( "mu Rel I:" ), _( "Relative Permeability (mu) of Insulator" ), 1, false ) ); + _( "mu Rel I" ), _( "Relative Permeability (mu) of Insulator" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_WIDTH_PRM, - _( "a:" ), _( "Width of Waveguide" ), 10.0, true ) ); + _( "a" ), _( "Width of Waveguide" ), 10.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_S_PRM, - _( "b:" ), _( "Height of Waveguide" ), 5.0, true ) ); + _( "b" ), _( "Height of Waveguide" ), 5.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Waveguide Length" ), 50.0, true ) ); + _( "L" ), _( "Waveguide Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_PRM, - _( "Z0:" ), _( "Characteristic Impedance" ), 50.0, true ) ); + _( "Z0" ), _( "Characteristic Impedance" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, DUMMY_PRM ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l:" ), _( "Electrical Length" ), 0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0, true ) ); break; case COAX_TYPE: // coaxial cable @@ -271,23 +271,23 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "TM-Modes:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MUR_PRM, - _( "mu Rel I:" ), _( "Relative Permeability (mu) of Insulator" ), 1, false ) ); + _( "mu Rel I" ), _( "Relative Permeability (mu) of Insulator" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_DIAM_IN_PRM, - _( "Din:" ), _( "Inner Diameter (conductor)" ), 1.0, true ) ); + _( "Din" ), _( "Inner Diameter (conductor)" ), 1.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_DIAM_OUT_PRM, - _( "Dout:" ), _( "Outer Diameter (insulator)" ), 8.0, true ) ); + _( "Dout" ), _( "Outer Diameter (insulator)" ), 8.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Line Length" ), 50.0, true ) ); + _( "L" ), _( "Line Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_PRM, - _( "Z0:" ), _( "Characteristic Impedance" ), 50.0, true ) ); + _( "Z0" ), _( "Characteristic Impedance" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, DUMMY_PRM ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l:" ), _( "Electrical Length" ), 0.0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; case C_MICROSTRIP_TYPE: // coupled microstrip @@ -304,30 +304,30 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "Skin Depth:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_PRM, - _( "H:" ), _( "Height of Substrate" ), 0.2, true ) ); + _( "H" ), _( "Height of Substrate" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_T_PRM, - _( "H_t:" ), _( "Height of Box Top" ), 1e20, true ) ); + _( "H_t" ), _( "Height of Box Top" ), 1e20, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, T_PRM, - _( "T:" ), _( "Strip Thickness" ), 0.035, true ) ); + _( "T" ), _( "Strip Thickness" ), 0.035, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, ROUGH_PRM, - _( "Rough:" ), _( "Conductor Roughness" ), 0.0, true ) ); + _( "Rough" ), _( "Conductor Roughness" ), 0.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_WIDTH_PRM, - _( "W:" ), _( "Line Width" ), 0.2, true ) ); + _( "W" ), _( "Line Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_S_PRM, - _( "S:" ), _( "Gap Width" ), 0.2, true ) ); + _( "S" ), _( "Gap Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Line Length" ), 50.0, true ) ); + _( "L" ), _( "Line Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_E_PRM, - _( "Zeven:" ), _( "Even mode impedance (lines driven by common voltages)" ), 50.0, true ) ); + _( "Zeven" ), _( "Even mode impedance (lines driven by common voltages)" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_O_PRM, - _( "Zodd:" ), _( "Odd mode impedance (lines driven by opposite (differential) voltages)" ), 50.0, true ) ); + _( "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:" ), _( "Electrical Length" ), 0.0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; case STRIPLINE_TYPE: // stripline @@ -340,26 +340,26 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "Skin Depth:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, H_PRM, - _( "H:" ), _( "Height of Substrate" ), 0.2, true ) ); + _( "H" ), _( "Height of Substrate" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, STRIPLINE_A_PRM, - _( "a:" ), _( "distance between strip and top metal" ), 0.2, + _( "a" ), _( "distance between strip and top metal" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, T_PRM, - _( "T:" ), _( "Strip Thickness" ), 0.035, true ) ); + _( "T" ), _( "Strip Thickness" ), 0.035, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_WIDTH_PRM, - _( "W:" ), _( "Line Width" ), 0.2, true ) ); + _( "W" ), _( "Line Width" ), 0.2, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Line Length" ), 50.0, true ) ); + _( "L" ), _( "Line Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_PRM, - _( "Z0:" ), _( "Characteristic Impedance" ), 50, true ) ); + _( "Z0" ), _( "Characteristic Impedance" ), 50, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, DUMMY_PRM ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l:" ), _( "Electrical Length" ), 0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0, true ) ); break; case TWISTEDPAIR_TYPE: // twisted pair @@ -373,25 +373,25 @@ TRANSLINE_IDENT::TRANSLINE_IDENT( enum TRANSLINE_TYPE_ID aType ) m_Messages.Add( _( "Skin Depth:" ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, TWISTEDPAIR_TWIST_PRM, - _( "Twists:" ), _( "Number of Twists per Length" ), 0.0, false ) ); + _( "Twists" ), _( "Number of Twists per Length" ), 0.0, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, MURC_PRM, - _( "mu Rel C:" ), _( "Relative Permeability (mu) of Conductor" ), 1, + _( "mu Rel C" ), _( "Relative Permeability (mu) of Conductor" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_SUBS, TWISTEDPAIR_EPSILONR_ENV_PRM, - _( "ErEnv:" ), _( "Relative Permittivity of Environment" ), 1, + _( "ErEnv" ), _( "Relative Permittivity of Environment" ), 1, false ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_DIAM_IN_PRM, - _( "Din:" ), _( "Inner Diameter (conductor)" ), 1.0, true ) ); + _( "Din" ), _( "Inner Diameter (conductor)" ), 1.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_DIAM_OUT_PRM, - _( "Dout:" ), _( "Outer Diameter (insulator)" ), 8.0, true ) ); + _( "Dout" ), _( "Outer Diameter (insulator)" ), 8.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_PHYS, PHYS_LEN_PRM, - _( "L:" ), _( "Cable Length" ), 50.0, true ) ); + _( "L" ), _( "Cable Length" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, Z0_PRM, - _( "Z0:" ), _( "Characteristic Impedance" ), 50.0, true ) ); + _( "Z0" ), _( "Characteristic Impedance" ), 50.0, true ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, DUMMY_PRM ) ); AddPrm( new TRANSLINE_PRM( PRM_TYPE_ELEC, ANG_L_PRM, - _( "Ang_l:" ), _( "Electrical Length" ), 0.0, true ) ); + _( "Ang_l" ), _( "Electrical Length" ), 0.0, true ) ); break; case END_OF_LIST_TYPE: // Not really used @@ -422,7 +422,7 @@ void TRANSLINE_IDENT::ReadConfig() for( auto& param : m_prms_List ) { - std::string id = std::to_string( param->m_Id ); + std::string id = param->m_Label.ToStdString(); try { @@ -443,7 +443,13 @@ void TRANSLINE_IDENT::WriteConfig() for( auto& param : m_prms_List ) { - std::string id = std::to_string( param->m_Id ); + std::string id = param->m_Label.ToStdString(); + + if( !std::isfinite( param->m_Value ) ) + { + param->m_Value = 0; + } + cfg->m_TransLine.param_values[ name ][ id ] = param->m_Value; cfg->m_TransLine.param_units[ name ][ id ] = param->m_UnitSelection; }