copyright: (C) 2010 by Michael Margraf
***************************************************************************/
* *
* 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. *
* *
***************************************************************************/
#include "tl_filter.h"
#define MAX_ERROR 1e-7
TL_Filter::TL_Filter()
{
}
void TL_Filter::calcMicrostrip(tSubstrate *substrate,
double width, double freq, double& er_eff, double& zl)
{
double a, b;
double h = substrate->height;
double t = substrate->thickness;
double er = substrate->er;
double Wh = width / h;
t /= h;
double w1 = Wh;
if(t > 1e-100) {
a = coth(sqrt(6.517*Wh));
b = t / pi * log(1.0 + 10.873127 / t / a / a);
w1 += b;
Wh += 0.5 * b * (1.0 + sech(sqrt(er - 1.0)));
}
a = Wh * Wh;
b = a * a;
er_eff = -0.564 * pow((er-0.9) / (er+3.0), 0.053);
er_eff *= 1.0 + log((b + a/2704.0) / (b + 0.432)) / 49.0 + log(1.0 + a*Wh/5929.741) / 18.7;
er_eff = (er+1.0) / 2.0 + (er-1.0) / 2.0 * pow(1.0 + 10.0/Wh, er_eff);
zl = 6.0 + 0.2831853 * exp(-pow(30.666/Wh, 0.7528));
zl = Z_FIELD / 2.0/pi * log(zl/Wh + sqrt(1.0 + 4.0/Wh/Wh));
a = 6.0 + 0.2831853 * exp(-pow(30.666/w1, 0.7528));
a = Z_FIELD / 2.0/pi * log(a/w1 + sqrt(1.0 + 4.0/w1/w1));
a /= zl;
zl /= sqrt(er_eff);
er_eff *= a * a;
freq *= h / 1e6;
a = 0.0363 * exp(-4.6*Wh) * (1.0 - exp(-pow(freq/38.7, 4.97)));
a *= 1.0 + 2.751 * (1.0 - exp(-pow(er/15.916, 8.0)));
a = pow((0.1844 + a) * freq, 1.5763);
a *= 0.27488 + Wh*(0.6315 + 0.525 / pow(1.0+0.0157*freq, 20.0)) - 0.065683*exp(-8.7513*Wh);
a *= 0.33622 * (1.0 - exp(-0.03442*er));
double er_freq = er - (er - er_eff) / (1.0 + a);
a = -0.03891 * pow(er, 1.4);
b = -0.267 * pow (Wh, 7.0);
double R7 = 1.206 - 0.3144*exp(a) * (1.0 - exp(b));
a = 0.016 + pow(0.0514*er, 4.524);
b = pow(freq/28.843, 12.0);
a = 5.086 * a * b / (0.3838 + 0.386*a) / (1.0 + 1.2992*b);
b = -22.2 * pow(Wh, 1.92);
a *= exp(b);
b = pow(er - 1.0, 6.0);
double R9 = a*b / (1.0 + 10.0*b);
a = 4.766 * exp(-3.228 * pow(Wh, 0.641));
a = 1.0 + 1.275
* (1.0 - exp(-0.004625*a*pow(er, 1.674) * pow(freq/18.365, 2.745)));
b = 0.9408 * pow(er_freq, a) - 0.9603;
b /= (0.9408 - R9) * pow(er_eff, a) - 0.9603;
R9 = b;
a = 0.00044 * pow(er, 2.136) + 0.0184;
a *= 0.707 * pow(freq/12.3, 1.097);
a = exp(-0.026*pow(freq, 1.15656) - a);
b = pow(freq/19.47, 6.0);
b /= 1.0 + 0.0962 * b;
b = 1.0 + 0.0503 *er*er* b * (1.0 - exp(-pow(Wh/15, 6.0)));
R7 *= (1.0 - 1.1241 * a / b / (1.0 + 0.00245*Wh*Wh));
zl *= pow(R9, R7);
er_eff = er_freq;
}
void TL_Filter::getMicrostrip(double Z0, double freq, tSubstrate *substrate,
double &width, double &er_eff)
{
int iteration = 0;
double Z0_current, Z0_result, increment;
width = 1e-3;
do {
calcMicrostrip(substrate, width, freq, er_eff, Z0_current);
if(fabs(Z0 - Z0_current) < MAX_ERROR)
break;
increment = width / 100.0;
width += increment;
calcMicrostrip(substrate, width, freq, er_eff, Z0_result);
width -= (Z0_current - Z0) / (Z0_result - Z0_current) * increment;
if(width <= 0.0)
width = increment;
iteration++;
} while(iteration < 150);
}
double TL_Filter::getMicrostripOpen(double Wh, double er, double er_eff)
{
double Q1, Q3, Q4, Q5;
Q4 = pow(er_eff, 0.81);
Q5 = pow(Wh, 0.8544);
Q1 = 0.434907 * (Q4+0.26) / (Q4-0.189) * (Q5+0.236) / (Q5+0.87);
Q3 = 1.0 + pow(Wh, 0.371) / (2.358*er + 1.0);
Q3 = 1.0 + 0.5274 / pow(er_eff, 0.9236) * atan(0.084 * pow(Wh, 1.9413/Q3));
Q4 = 1.0 + 0.0377 * (6.0 - 5.0*exp(0.036*(1.0-er))) * atan(0.067*pow(Wh, 1.456));
Q5 = 1.0 - 0.218 * exp(-7.5*Wh);
return Q1 * Q3 * Q5 / Q4;
}
void TL_Filter::sythesizeCoupledMicrostrip
(double zl_e, double zl_o, double freq, tSubstrate *substrate,
double& width, double& gap, double& er_eff)
{
double a, er, Wh_e, Wh_o, ce, co, j11, j12, j21, j22, dw, dg;
double zl_e_current, zl_e_result1, zl_e_result2;
double zl_o_current, zl_o_result1, zl_o_result2;
er = substrate->er;
a = exp(zl_e * sqrt(er + 1.0) / 84.8) - 1.0;
Wh_e = 8.0 * sqrt(a * ((7.0 + 4.0 / er) / 11.0) + ((1.0 + 1.0 / er) / 0.81)) / a;
a = exp(zl_o * sqrt(er + 1.0) / 84.8) - 1.0;
Wh_o = 8.0 * sqrt(a * ((7.0 + 4.0 / er) / 11.0) + ((1.0 + 1.0 / er) / 0.81)) / a;
ce = cosh(0.5 * pi * Wh_e);
co = cosh(0.5 * pi * Wh_o);
gap = (2.0 / pi) * acosh((ce + co - 2.0) / (co - ce)) * substrate->height;
width = acosh((ce * co - 1.0) / (co - ce)) / pi - gap / 2.0;
width *= substrate->height;
int iteration = 0;
do {
getCoupledMicrostrip
(width, gap, freq, substrate, zl_e_current, zl_o_current, ce, co);
if(fabs(zl_e - zl_e_current) < MAX_ERROR)
if(fabs(zl_o - zl_o_current) < MAX_ERROR)
break;
dw = width / 100.0;
getCoupledMicrostrip
(width+dw, gap, freq, substrate, zl_e_result1, zl_o_result1, ce, co);
dg = gap / 100.0;
getCoupledMicrostrip
(width, gap+dg, freq, substrate, zl_e_result2, zl_o_result2, ce, co);
j11 = (zl_e_result1 - zl_e_current) / dw;
j12 = (zl_e_result2 - zl_e_current) / dg;
j21 = (zl_o_result1 - zl_o_current) / dw;
j22 = (zl_o_result2 - zl_o_current) / dg;
a = j11 * j22 - j12 * j21;
j22 = j22 * (zl_e_current - zl_e) - j12 * (zl_o_current - zl_o);
j11 = j11 * (zl_o_current - zl_o) - j21 * (zl_e_current - zl_e);
width -= j22 / a;
gap -= j11 / a;
if(width <= 0.0)
width = dw;
if(gap <= 0.0)
gap = dg;
iteration++;
} while(iteration < 200);
er_eff = 0.5 * (ce + co);
if(iteration >= 200)
width = gap = er_eff = -1.0;
}
double TL_Filter::dispersionKirschning
(double er, double Wh, double freq, double& er_eff, double& zl)
{
double a, b;
a = 0.0363 * exp(-4.6*Wh) * (1.0 - exp(-pow(freq/38.7, 4.97)));
a *= 1.0 + 2.751 * (1.0 - exp(-pow(er/15.916, 8.0)));
a = pow((0.1844 + a) * freq, 1.5763);
a *= 0.27488 + Wh*(0.6315 + 0.525 / pow(1.0+0.0157*freq, 20.0))
- 0.065683*exp(-8.7513*Wh);
a *= 0.33622 * (1.0 - exp(-0.03442*er));
double er_freq = er - (er - er_eff) / (1.0 + a);
a = -0.03891 * pow(er, 1.4);
b = -0.267 * pow (Wh, 7.0);
double R7 = 1.206 - 0.3144*exp(a) * (1.0 - exp(b));
a = 0.016 + pow(0.0514*er, 4.524);
b = pow(freq/28.843, 12.0);
a = 5.086 * a * b / (0.3838 + 0.386*a) / (1.0 + 1.2992*b);
b = -22.2 * pow(Wh, 1.92);
a *= exp(b);
b = pow(er - 1.0, 6.0);
double R9 = a*b / (1.0 + 10.0*b);
a = 4.766 * exp(-3.228 * pow(Wh, 0.641));
a = 1.0 + 1.275
* (1.0 - exp(-0.004625*a*pow(er, 1.674) * pow(freq/18.365, 2.745)));
b = 0.9408 * pow(er_freq, a) - 0.9603;
b /= (0.9408 - R9) * pow(er_eff, a) - 0.9603;
R9 = b;
a = 0.00044 * pow(er, 2.136) + 0.0184;
a *= 0.707 * pow(freq/12.3, 1.097);
a = exp(-0.026*pow(freq, 1.15656) - a);
b = pow(freq/19.47, 6.0);
b /= 1.0 + 0.0962 * b;
b = 1.0 + 0.0503 *er*er* b * (1.0 - exp(-pow(Wh/15, 6.0)));
R7 *= (1.0 - 1.1241 * a / b / (1.0 + 0.00245*Wh*Wh));
zl *= pow(R9, R7);
er_eff = er_freq;
return R7;
}
void TL_Filter::getCoupledMicrostrip
(double ms_width, double g, double freq, tSubstrate *substrate,
double& zl_e, double& zl_o, double& er_eff_e, double& er_eff_o)
{
double Wh_o, a, b, c, d;
double Wh_e = ms_width;
double h = substrate->height;
double t = substrate->thickness;
double er = substrate->er;
a = 1.0;
if(t > 1e-20) {
if(Wh_e > (h/2.0/pi)) {
if(h > (t*4.0*pi))
a = t / pi * (1.0 + log(2.0*h/t));
}
else {
if(Wh_e > (t*2.0))
a = t / pi * (1.0 + log(4.0*pi*Wh_e/t));
}
}
if(g > 20.0*t) {
b = 2.0 * t / g / er;
a *= 1.0 - 0.5*exp(-0.69*a/b);
}
else
a = b = 0.0;
Wh_e = (Wh_e + a) / h;
Wh_o = Wh_e + b;
g /= h;
double fn = freq / 1e6 * h;
double er_e, er_o;
a = Wh_e * Wh_e;
b = a * a;
er_e = -0.564 * pow((er-0.9) / (er+3.0), 0.053);
er_e *= 1.0 + log((b + a/2704.0) / (b + 0.432)) / 49.0 + log(1.0 + a*Wh_e/5929.741) / 18.7;
er_e = (er+1.0) / 2.0 + (er-1.0) / 2.0 * pow(1.0 + 10.0/Wh_e, er_e);
a = Wh_o * Wh_o;
b = a * a;
er_o = -0.564 * pow((er-0.9) / (er+3.0), 0.053);
er_o *= 1.0 + log((b + a/2704.0) / (b + 0.432)) / 49.0 + log(1.0 + a*Wh_o/5929.741) / 18.7;
er_o = (er+1.0) / 2.0 + (er-1.0) / 2.0 * pow(1.0 + 10.0/Wh_o, er_o);
er_eff_e = 0.5 * (er + 1.0);
b = Wh_e * (20.0 + g*g) / (10.0 + g*g) + g*exp(-g);
a = -0.564 * pow((er-0.9) / (er+3.0), 0.053);
a *= 1.0 + log(b*b * (b*b + 3.698e-4) / (b*b*b*b + 0.432)) / 49.0
+ log(1.0 + pow(b/18.1, 3.0)) / 18.7;
er_eff_e += 0.5 * (er - 1.0) * pow(1.0 + 10.0/b, a);
b = 0.747 * er / (0.15 + er);
b -= (b - 0.207) * exp(-0.414 * Wh_o);
b *= pow(g, 0.593 + 0.694 * exp(-0.562 * Wh_o));
a = 0.7287 * (er_o - 0.5*(er+1.0)) * (1.0 - exp(-0.179*Wh_o));
er_eff_o = er_o + (0.5 * (er + 1.0) + a - er_o) * exp(-b);
zl_e = 6.0 + 0.2831853 * exp(-pow(30.666/Wh_e, 0.7528));
zl_e = Z_FIELD/sqrt(er_e) / 2.0/pi * log(zl_e/Wh_e + sqrt(1.0 + 4.0/Wh_e/Wh_e));
b = 1.0 + 0.7519 * g + 0.189 * pow(g, 2.31);
c = 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;
a = b * (exp(-g) * pow(Wh_e, c)
+ (2.0 - exp(-g)) * pow(Wh_e, -c));
a = 1.739 * pow(Wh_e, 0.194) / a;
zl_e *= sqrt(er_e / er_eff_e) / (1.0 - zl_e / Z_FIELD * sqrt(er_e) * a);
zl_o = 6.0 + 0.2831853 * exp(-pow(30.666/Wh_o, 0.7528));
zl_o = Z_FIELD/sqrt(er_o) / 2.0/pi * log(zl_o/Wh_o + sqrt(1.0 + 4.0/Wh_o/Wh_o));
a = exp(-6.5 - 0.95 * log(g) - pow(g / 0.15, 5.0));
a = a + 1.0 / 16.5;
a *= log((10.0 + 190.0 * g * g) / (1.0 + 82.3 * g * g * g));
a = pow(Wh_o, -a);
a *= 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;
a = exp(log(Wh_o) * a);
a *= 1.794 + 1.14 * log(1.0 + 0.638 / (g + 0.517 * pow(g, 2.43)));
a /= b;
a = 1.739 * pow(Wh_o, 0.194) / b
/ (exp(-g) * pow(Wh_o, c) + (2.0 - exp(-g)) * pow(Wh_o, -c)) - a;
zl_o *= sqrt(er_o / er_eff_o) / (1.0 - zl_o / Z_FIELD * sqrt(er_o) * a);
er_e = er_eff_e;
er_o = er_eff_o;
a = 0.0363 * exp(-4.6 * Wh_e) * (1.0 - exp(-pow(fn / 38.7, 4.97)));
d = 1.0 + 2.751 * (1.0 - exp(-pow(er / 15.916, 8.0)));
a *= d;
b = 0.334 * exp(-3.3 * pow(er / 15.0, 3.0)) + 0.746;
b *= exp(-pow(fn / 18.0, 0.368));
b = 1.0 + 4.069 * b * pow(g, 0.479)
* exp(-1.347 * pow(g, 0.595) - 0.17 * pow(g, 2.5));
a = pow((a + 0.1844 * b) * fn, 1.5763);
a *= 0.27488 + (0.6315 + 0.525 / pow(1.0 + 0.0157 * fn, 20.0)) * Wh_e
- 0.065683 * exp(-8.7513 * Wh_e);
c = 0.33622 * (1.0 - exp(-0.03442 * er));
er_eff_e = er - (er - er_eff_e) / (1.0 + a*c);
a = 0.7168 * (1.0 + 1.076 / (1.0 + 0.0576 * (er - 1.0)));
a -= 0.7913 * (1.0 - exp(-pow(fn / 20.0, 1.424)))
* atan(2.481 * pow(er / 8.0, 0.946));
a += (1.0 - a) / (1.0 + 1.183 * pow(Wh_o, 1.376));
b = 0.242 * pow(er - 1.0, 0.55);
b = -1.695 * b / (0.414 + 1.605 * b);
a *= exp(b * pow(g, 1.092));
a /= 0.8928 + 0.1072 * (1.0 - exp(-0.42 * pow(fn / 20.0, 3.215)));
b = 0.6366 * (exp(-0.3401 * fn) - 1.0)
* atan(1.263 * pow(Wh_o / 3.0, 1.629));
b = fabs(1.0 - 0.8928 * (1.0 + b) * a);
a = 0.0363 * exp(-4.6 * Wh_o) * (1.0 - exp(-pow(fn / 38.7, 4.97)));
a = pow((a*d + 0.1844) * fn * b, 1.5763);
a *= 0.27488 + (0.6315 + 0.525 / pow(1.0 + 0.0157 * fn, 20.0)) * Wh_o
- 0.065683 * exp(-8.7513 * Wh_o);
er_eff_o = er - (er - er_eff_o) / (1.0 + a*c);
a = 0.893 * (1.0 - 0.3 / (1.0 + 0.7 * (er - 1.0)));
a = -2.121 * (pow(fn / 20.0, 4.91) / (1.0 + a * pow(fn / 20.0, 4.91)))
* exp(-2.87 * g) * pow(g, 0.902);
b = 1.0 + 0.038 * pow(er / 8.0, 5.1);
c = 1.0 + 1.203 * pow(er / 15.0, 4.0) / (1.0 + pow(er / 15.0, 4.0));
b = 1.887 * exp(-1.5 * pow(g, 0.84)) * pow(g, c)
/ (1.0 + 0.41 * pow(fn / 15.0, 3.0)
* pow(Wh_e, 2.0 / b) / (0.125 + pow(Wh_e, 1.626 / b)));
a += b * (1.0 + 9.0 / (1.0 + 0.403 * pow(er - 1.0, 2)));
a -= 0.394 * (1.0 - exp(-1.47 * pow(Wh_e / 7.0, 0.672)))
* (1.0 - exp(-4.25 * pow(fn / 20.0, 1.87)));
a += 0.61 * (1.0 - exp(-2.13 * pow(Wh_e / 8.0, 1.593)))
/ (1.0 + 6.544 * pow(g, 4.17));
b = 0.21 * g * g * g * g / ((1.0 + 0.18 * pow(g, 4.9))
* (1.0 + 0.1*Wh_e*Wh_e) * (1.0 + pow(fn / 24.0, 3.0)));
a += b * (0.09 + 1.0 / (1.0 + 0.1 * pow(er - 1, 2.7)));
b = 4.766 * exp(-3.228 * pow(Wh_e, 0.641));
a += 1.275 * (1.0 - exp(-0.004625 * b * pow(er, 1.674) * pow(fn / 18.365, 2.745)))
+ 1.0;
b = fabs(1.0 - 42.54 * pow(g, 0.133) * exp(-0.812 * g)
* pow(Wh_e, 2.5) / (1.0 + 0.033 * pow(Wh_e, 2.5)));
b = 0.016 + pow(0.0514 * er * b, 4.524);
c = pow(fn / 28.843, 12);
b = 5.086 * b * c / (0.3838 + 0.386 * b)
* (exp(-22.2 * pow(Wh_e, 1.92)) / (1.0 + 1.2992 * c))
* (pow(er - 1.0, 6.0) / (1.0 + 10.0 * pow(er - 1.0, 6.0)));
d = 1;
c = er_e;
d = dispersionKirschning(er, Wh_e, fn, c, d);
a = (0.9408 * pow(c, a) - 0.9603) / ((0.9408 - b) * pow(er_e, a) - 0.9603);
zl_e *= pow(a, d);
d = zl_o;
c = er_o;
dispersionKirschning(er, Wh_o, fn, c, d);
a = pow((er - 1.0) / 13.0, 12.0);
a = 30.0 - 22.2 * a / (1.0 + 3.0 * a);
a -= 15.16 / (1.0 + 0.196 * pow(er - 1.0, 2.0));
a = 0.925 * pow(fn / a, 1.536) / (1.0 + 0.3 * pow(fn / 30.0, 1.536));
zl_o *= pow(er_eff_o / er_o, a);
a = pow(er - 1.0, 1.5);
a = 0.4 * pow(g, 0.84) * (1.0 + 2.5 * a / (5.0 + a));
a = 1.0 + 0.005 * fn * a
/ ((1.0 + 0.812 * pow(fn/15.0, 1.9)) * (1.0 + 0.025*Wh_o*Wh_o));
zl_o -= d * a;
a = (er - 1.0) * (er - 1.0);
a = (0.3 * fn * fn / (10.0 + fn * fn)) * (1.0 + 2.333 * a / (5.0 + a));
b = pow(er - 1.0, 3.0);
b = 0.149 * b / (94.5 + 0.038 * b);
c = pow(Wh_o, 0.894);
b *= 2.506 * c * pow((1.0 + 1.3 * Wh_o) * fn / 99.25, 4.29) / (3.575 + c);
zl_o = d + zl_o / (1.0 + b + pow(0.46 * g, 2.2) * a);
}