/* * rectwaveguide.cpp - rectangular waveguide class implementation * * Copyright (C) 2001 Gopal Narayanan * Copyright (C) 2005, 2006 Stefan Jahn * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include #include #include #include "rectwaveguide.h" #include "units.h" RECTWAVEGUIDE::RECTWAVEGUIDE() : TRANSLINE(), 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*/ mur_eff( 0.0 ), // Effective mag. permeability atten_dielectric( 0.0 ), // Loss in dielectric (dB) atten_cond( 0.0 ), // Loss in conductors (dB) fc10( 1.0 ) // Cutoff frequency for TE10 mode { m_Name = "RectWaveGuide"; Init(); } /* * returns square of k */ double RECTWAVEGUIDE::kval_square() { double kval; kval = 2.0 * M_PI * m_parameters[FREQUENCY_PRM] * sqrt( m_parameters[MUR_PRM] * m_parameters[EPSILONR_PRM] ) / C0; return kval * kval; } /* * given mode numbers m and n * returns square of cutoff kc value */ double RECTWAVEGUIDE::kc_square( int m, int n ) { return pow( ( m * M_PI / m_parameters[PHYS_A_PRM] ), 2.0 ) + pow( ( n * M_PI / m_parameters[PHYS_B_PRM] ), 2.0 ); } /* * given mode numbers m and n * returns cutoff fc value */ double RECTWAVEGUIDE::fc( int m, int n ) { return sqrt( kc_square( m, n ) / m_parameters[MUR_PRM] / m_parameters[EPSILONR_PRM] ) * C0 / 2.0 / M_PI; } /* * alphac - returns attenuation due to conductor losses for all propagating * modes in the waveguide */ double RECTWAVEGUIDE::alphac() { 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 * *f * *murc * MU0 / *sigma ); ac = 0.0; mmax = (int) floor( *f / fc( 1, 0 ) ); nmax = mmax; /* below from Ramo, Whinnery & Van Duzer */ /* TE(m,n) modes */ for( n = 0; n <= nmax; n++ ) { for( m = 1; m <= mmax; m++ ) { f_c = fc( m, n ); if( *f > f_c ) { switch( n ) { case 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 / *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; } } } } /* TM(m,n) modes */ for( n = 1; n <= nmax; n++ ) { for( m = 1; m <= mmax; m++ ) { f_c = fc( m, n ); if( *f > f_c ) { 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 ) ) ); } } } ac = ac * 20.0 * log10( exp( 1. ) ); /* convert from Np/m to db/m */ return ac; } /* * alphac_cutoff - returns attenuation for a cutoff wg */ double RECTWAVEGUIDE::alphac_cutoff() { double acc; acc = sqrt( kc_square( 1, 0 ) - kval_square() ); acc = 20 * log10( exp( 1.0 ) ) * acc; return acc; } /* * returns attenuation due to dielectric losses */ double RECTWAVEGUIDE::alphad() { double k_square, beta; double ad; k_square = kval_square(); beta = sqrt( k_square - kc_square( 1, 0 ) ); 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; } /* * get_rectwaveguide_sub * get and assign rectwaveguide substrate parameters * into rectwaveguide structure */ void RECTWAVEGUIDE::get_rectwaveguide_sub() { 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 ); } /* * get_rectwaveguide_comp * get and assign rectwaveguide component parameters * into rectwaveguide structure */ void RECTWAVEGUIDE::get_rectwaveguide_comp() { m_parameters[FREQUENCY_PRM] = getProperty( FREQUENCY_PRM ); } /* * get_rectwaveguide_elec * get and assign rectwaveguide electrical parameters * into rectwaveguide structure */ void RECTWAVEGUIDE::get_rectwaveguide_elec() { m_parameters[Z0_PRM] = getProperty( Z0_PRM ); m_parameters[ANG_L_PRM] = getProperty( ANG_L_PRM ); } /* * get_rectwaveguide_phys * get and assign rectwaveguide physical parameters * into rectwaveguide structure */ void RECTWAVEGUIDE::get_rectwaveguide_phys() { 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 * source: https://empossible.net/wp-content/uploads/2018/03/Lecture-5c-Rectangular-waveguide.pdf */ void RECTWAVEGUIDE::calcAnalyze() { double lambda_g; double k_square; k_square = kval_square(); if( kc_square( 1, 0 ) <= k_square ) { /* propagating modes */ // Z0 definition using fictive voltages and currents m_parameters[Z0_PRM] = ZF0 * sqrt( m_parameters[MUR_PRM] / m_parameters[EPSILONR_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 ) ); 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 */ 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]; } } /* * synthesize - synthesis function * source: re-arrangment of calcAnalyze equation * TE10 (via fc(1,0) ) results in the b term not influencing the result, as long as * 1) fc > f * 2) a > b */ void RECTWAVEGUIDE::calcSynthesize() { double lambda_g, k_square, beta; /* solve for a */ m_parameters[PHYS_A_PRM] = C0 / ( sqrt( ( m_parameters[MUR_PRM] * m_parameters[EPSILONR_PRM] ) ) * 2 * m_parameters[FREQUENCY_PRM] * sqrt( 1 - pow( ( ZF0 * sqrt( m_parameters[MUR_PRM] / m_parameters[EPSILONR_PRM] ) ) / m_parameters[Z0_PRM] ,2.0 ) ) ); 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; 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 */ 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]; } } 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 ); } #define MAXSTRLEN 128 void RECTWAVEGUIDE::show_results() { int m, n, max = 6; char text[MAXSTRLEN], txt[32]; // Z0EH = Ey / Hx (definition with field quantities) Z0EH = ZF0 * sqrt( kval_square() / ( kval_square() - kc_square( 1, 0 ) ) ); setResult( 0, Z0EH, "Ohm" ); 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_parameters[FREQUENCY_PRM] < fc( 1, 0 ) ) { strcpy( text, "none" ); } else { strcpy( text, "" ); for( m = 0; m <= max; m++ ) { for( n = 0; n <= max; n++ ) { if( ( m == 0 ) && ( n == 0 ) ) continue; if( m_parameters[FREQUENCY_PRM] >= ( fc( m, n ) ) ) { snprintf( txt, sizeof( txt ), "H(%d,%d) ", m, n ); if( ( strlen( text ) + strlen( txt ) + 5 ) < MAXSTRLEN ) { strcat( text, txt ); } else { strcat( text, "..." ); m = n = max + 1; // print no more modes } } } } } setResult( 4, text ); // show possible TM modes (E modes) if( m_parameters[FREQUENCY_PRM] < fc( 1, 1 ) ) { strcpy( text, "none" ); } else { strcpy( text, "" ); for( m = 1; m <= max; m++ ) { for( n = 1; n <= max; n++ ) { if( m_parameters[FREQUENCY_PRM] >= fc( m, n ) ) { snprintf( txt, sizeof( txt ), "E(%d,%d) ", m, n ); if( ( strlen( text ) + strlen( txt ) + 5 ) < MAXSTRLEN ) { strcat( text, txt ); } else { strcat( text, "..." ); m = n = max + 1; // print no more modes } } } } } setResult( 5, text ); }