kicad/pcb_calculator/transline/rectwaveguide.cpp

401 lines
9.8 KiB
C++

/*
* rectwaveguide.cpp - rectangular waveguide class implementation
*
* Copyright (C) 2001 Gopal Narayanan <gopal@astro.umass.edu>
* Copyright (C) 2005, 2006 Stefan Jahn <stefan@lkcc.org>
*
* 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 <stdio.h>
#include <string.h>
#include <math.h>
#include "units.h"
#include "transline.h"
#include "rectwaveguide.h"
RECTWAVEGUIDE::RECTWAVEGUIDE() : TRANSLINE()
{
m_name = "RectWaveGuide";
}
/*
* returns square of k
*/
double RECTWAVEGUIDE::kval_square()
{
double kval;
kval = 2.0* M_PI* f* sqrt( mur* er ) / 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 / a), 2.0 ) + pow( (n * M_PI / b), 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 ) / mur / er ) * 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;
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 * tand) / (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()
{
er = getProperty( EPSILONR_PRM );
mur = getProperty( MUR_PRM );
murC = getProperty( MURC_PRM );
sigma = 1.0 / getProperty( RHO_PRM );
tand = getProperty( TAND_PRM );
tanm = getProperty( TANM_PRM );
}
/*
* get_rectwaveguide_comp
* get and assign rectwaveguide component parameters
* into rectwaveguide structure
*/
void RECTWAVEGUIDE::get_rectwaveguide_comp()
{
f = getProperty( FREQUENCY_PRM );
}
/*
* get_rectwaveguide_elec
* get and assign rectwaveguide electrical parameters
* into rectwaveguide structure
*/
void RECTWAVEGUIDE::get_rectwaveguide_elec()
{
Z0 = getProperty( Z0_PRM );
ang_l = getProperty( ANG_L_PRM );
}
/*
* get_rectwaveguide_phys
* get and assign rectwaveguide physical parameters
* into rectwaveguide structure
*/
void RECTWAVEGUIDE::get_rectwaveguide_phys()
{
a = getProperty( PHYS_WIDTH_PRM );
b = getProperty( PHYS_S_PRM );
l = getProperty( PHYS_LEN_PRM );
}
/*
* analyze - analysis function
*/
void RECTWAVEGUIDE::analyze()
{
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 )
{
/* 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 ) / f), 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 ) / f, 2.0 ) );
}
else
{
/* evanascent modes */
Z0 = 0;
ang_l = 0;
er_eff = 0;
atten_dielectric = 0.0;
atten_cond = alphac_cutoff() * l;
}
setProperty( Z0_PRM, Z0 );
setProperty( ANG_L_PRM, ang_l );
show_results();
}
/*
* synthesize - synthesis function
*/
void RECTWAVEGUIDE::synthesize()
{
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 ) )
{
/* solve for b */
b = Z0 * a * sqrt( 1.0 - pow( fc( 1, 0 ) / f, 2.0 ) ) / ( 2.0 * ZF0 * sqrt( mur / er ) );
setProperty( PHYS_S_PRM, b );
}
else if( isSelected( PHYS_WIDTH_PRM ) )
{
/* solve for a */
a = sqrt( pow( 2.0 * ZF0 * b / Z0, 2.0 ) + pow( C0 / (2.0 * f), 2.0 ) );
setProperty( PHYS_WIDTH_PRM, a );
}
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 );
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 ) / f), 2.0 ) );
}
else
{
/*evanascent modes */
Z0 = 0;
ang_l = 0;
er_eff = 0;
atten_dielectric = 0.0;
atten_cond = alphac_cutoff() * l;
}
show_results();
}
#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, er_eff, "" );
setResult( 2, atten_cond, "dB" );
setResult( 3, atten_dielectric, "dB" );
// show possible TE modes (H modes)
if( f < 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( f >= ( fc( m, n ) ) )
{
sprintf( txt, "H(%u,%u) ", 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( f < fc( 1, 1 ) )
strcpy( text, "none" );
else
{
strcpy( text, "" );
for( m = 1; m<= max; m++ )
{
for( n = 1; n<= max; n++ )
{
if( f >= fc( m, n ) )
{
sprintf( txt, "E(%u,%u) ", 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 );
}