committed by
Holger Vogt
16 changed files with 2095 additions and 4 deletions
-
1src/spinit.in
-
18src/xspice/icm/GNUmakefile.in
-
158src/xspice/icm/tlines/cpline/cfunc.mod
-
176src/xspice/icm/tlines/cpline/ifspec.ifs
-
496src/xspice/icm/tlines/cpmlin/cfunc.mod
-
216src/xspice/icm/tlines/cpmlin/ifspec.ifs
-
133src/xspice/icm/tlines/mlin/cfunc.mod
-
173src/xspice/icm/tlines/mlin/ifspec.ifs
-
4src/xspice/icm/tlines/modpath.lst
-
91src/xspice/icm/tlines/tline/cfunc.mod
-
87src/xspice/icm/tlines/tline/ifspec.ifs
-
0src/xspice/icm/tlines/udnpath.lst
-
337src/xspice/tlines/msline_common.c
-
60src/xspice/tlines/msline_common.h
-
86src/xspice/tlines/tline_common.c
-
63src/xspice/tlines/tline_common.h
@ -0,0 +1,158 @@ |
|||
/* =========================================================================== |
|||
FILE cfunc.mod |
|||
|
|||
(c) Vadim Kuznetsov 2025 |
|||
|
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <math.h> |
|||
#include <complex.h> |
|||
|
|||
#include "msline_common.h" |
|||
#include "tline_common.h" |
|||
|
|||
|
|||
static void copy_complex(double complex s, Complex_t *d) |
|||
{ |
|||
d->real = creal(s); |
|||
d->imag = cimag(s); |
|||
} |
|||
|
|||
cpline_state_t *sim_points = NULL; |
|||
|
|||
|
|||
void cm_cpline (ARGS) |
|||
{ |
|||
Complex_t z11, z12, z13, z14; |
|||
|
|||
/* how to get properties of this component, e.g. L, W */ |
|||
double l = PARAM(l); |
|||
double ze = PARAM(ze); |
|||
double zo = PARAM(zo); |
|||
double ere = PARAM(ere); |
|||
double ero = PARAM(ero); |
|||
double ae = PARAM(ae); |
|||
double ao = PARAM(ao); |
|||
ae = pow(10, 0.05*ae); |
|||
ao = pow(10, 0.05*ao); |
|||
|
|||
if(INIT) { |
|||
|
|||
} |
|||
|
|||
/* Compute the output */ |
|||
if(ANALYSIS == DC) { |
|||
|
|||
double V1 = INPUT(p1s); |
|||
double V2 = INPUT(p2s); |
|||
double V3 = INPUT(p3s); |
|||
double V4 = INPUT(p4s); |
|||
double I1 = INPUT(p1); |
|||
double I2 = INPUT(p2); |
|||
double I3 = INPUT(p3); |
|||
double I4 = INPUT(p4); |
|||
|
|||
double z = sqrt(ze*zo); |
|||
|
|||
double V2out = V1 + z*I1; |
|||
double V1out = V2 + z*I2; |
|||
OUTPUT(p1) = V1out + I1*z; |
|||
OUTPUT(p2) = V2out + I2*z; |
|||
|
|||
double V3out = V4 + z*I4; |
|||
double V4out = V3 + z*I3; |
|||
OUTPUT(p3) = V3out + I3*z; |
|||
OUTPUT(p4) = V4out + I4*z; |
|||
|
|||
cm_analog_auto_partial(); |
|||
} |
|||
else if(ANALYSIS == AC) { |
|||
double o = RAD_FREQ; |
|||
|
|||
double complex _Z11, _Z12, _Z13, _Z14; |
|||
double complex arg_e = log(ae)*l/2.0 + I*o*l/C0*sqrt(ere); |
|||
double complex arg_o = log(ao)*l/2.0 + I*o*l/C0*sqrt(ero); |
|||
|
|||
_Z11 = zo / (2*ctanh(arg_o)) + ze / (2*ctanh(arg_e)); |
|||
_Z12 = zo / (2*csinh(arg_o)) + ze / (2*csinh(arg_e)); |
|||
_Z13 = ze / (2*csinh(arg_e)) - zo / (2*csinh(arg_o)); |
|||
_Z14 = ze / (2*ctanh(arg_e)) - zo / (2*ctanh(arg_o)); |
|||
|
|||
copy_complex(_Z11,&z11); |
|||
copy_complex(_Z12,&z12); |
|||
copy_complex(_Z13,&z13); |
|||
copy_complex(_Z14,&z14); |
|||
|
|||
AC_GAIN(p1,p1) = z11; AC_GAIN(p2,p2) = z11; |
|||
AC_GAIN(p3,p3) = z11; AC_GAIN(p4,p4) = z11; |
|||
|
|||
AC_GAIN(p1,p2) = z12; AC_GAIN(p2,p1) = z12; |
|||
AC_GAIN(p3,p4) = z12; AC_GAIN(p4,p3) = z12; |
|||
|
|||
AC_GAIN(p1,p3) = z13; AC_GAIN(p3,p1) = z13; |
|||
AC_GAIN(p2,p4) = z13; AC_GAIN(p4,p2) = z13; |
|||
|
|||
AC_GAIN(p1,p4) = z14; AC_GAIN(p4,p1) = z14; |
|||
AC_GAIN(p2,p3) = z14; AC_GAIN(p3,p2) = z14; |
|||
} |
|||
else if(ANALYSIS == TRANSIENT) { |
|||
double t = TIME; |
|||
double Vp[PORT_NUM]; |
|||
double Ip[PORT_NUM]; |
|||
|
|||
Vp[0] = INPUT(p1s); |
|||
Vp[1] = INPUT(p2s); |
|||
Vp[2] = INPUT(p3s); |
|||
Vp[3] = INPUT(p4s); |
|||
Ip[0] = INPUT(p1); |
|||
Ip[1] = INPUT(p2); |
|||
Ip[2] = INPUT(p3); |
|||
Ip[3] = INPUT(p4); |
|||
double delay = l/(C0); |
|||
append_cpline_state(&sim_points, t, Vp, Ip, 1.2*delay); |
|||
if (t > delay) { |
|||
cpline_state_t *pp = find_cpline_state(sim_points, t - delay); |
|||
if (pp != NULL) { |
|||
|
|||
double J1e = 0.5*(Ip[3] + Ip[0]); |
|||
double J1o = 0.5*(Ip[0] - Ip[3]); |
|||
double J2e = 0.5*(Ip[1] + Ip[2]); |
|||
double J2o = 0.5*(Ip[1] - Ip[2]); |
|||
|
|||
|
|||
double J1et = 0.5*(pp->Ip[3] + pp->Ip[0]); |
|||
double J1ot = 0.5*(pp->Ip[0] - pp->Ip[3]); |
|||
double J2et = 0.5*(pp->Ip[1] + pp->Ip[2]); |
|||
double J2ot = 0.5*(pp->Ip[1] - pp->Ip[2]); |
|||
|
|||
|
|||
double V1et = 0.5*(pp->Vp[3] + pp->Vp[0]); |
|||
double V1ot = 0.5*(pp->Vp[0] - pp->Vp[3]); |
|||
double V2et = 0.5*(pp->Vp[1] + pp->Vp[2]); |
|||
double V2ot = 0.5*(pp->Vp[1] - pp->Vp[2]); |
|||
|
|||
double V1e = ze*J1e + V2et + ze*J2et; |
|||
double V1o = zo*J1o + V2ot + zo*J2ot; |
|||
double V2e = ze*J2e + V1et + ze*J1et; |
|||
double V2o = zo*J2o + V1ot + zo*J1ot; |
|||
|
|||
double V1 = V1o + V1e; |
|||
double V2 = V2o + V2e; |
|||
double V3 = V2e - V2o; |
|||
double V4 = V1e - V1o; |
|||
|
|||
OUTPUT(p1) = V1; |
|||
OUTPUT(p2) = V2; |
|||
OUTPUT(p3) = V3; |
|||
OUTPUT(p4) = V4; |
|||
} |
|||
cm_analog_auto_partial(); |
|||
} else { |
|||
cm_analog_auto_partial(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,176 @@ |
|||
/* =========================================================================== |
|||
FILE ifspec.ifs |
|||
|
|||
(c) vadim Kuznetsov 2025 |
|||
|
|||
=========================================================================== */ |
|||
|
|||
/* Ports connection |
|||
4 --||||||-- 3 |
|||
|
|||
1 --||||||-- 2 |
|||
*/ |
|||
|
|||
NAME_TABLE: |
|||
|
|||
Spice_Model_Name: cpline |
|||
C_Function_Name: cm_cpline |
|||
Description: "Generic transmission line" |
|||
|
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p1 |
|||
Description: "Terminals Line1" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p2 |
|||
Description: "Terminals Line1" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p3 |
|||
Description: "Terminals Line2" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p4 |
|||
Description: "Terminals Line2" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p1s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p2s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p3s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p4s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: l |
|||
Description: "length" |
|||
Data_Type: real |
|||
Default_Value: 1.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: ze |
|||
Description: "characteristic impedance of even mode" |
|||
Data_Type: real |
|||
Default_Value: 50.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: zo |
|||
Description: "characteristic impedance of odd mode" |
|||
Data_Type: real |
|||
Default_Value: 50.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: ae |
|||
Description: "attenuation per length (dB) even mode" |
|||
Data_Type: real |
|||
Default_Value: 0.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: ao |
|||
Description: "attenuation per length (dB) odd mode" |
|||
Data_Type: real |
|||
Default_Value: 0.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: ere |
|||
Description: "dielectric constant even mode" |
|||
Data_Type: real |
|||
Default_Value: 1.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: ero |
|||
Description: "dielectric constant odd mode" |
|||
Data_Type: real |
|||
Default_Value: 1.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
@ -0,0 +1,496 @@ |
|||
/* =========================================================================== |
|||
FILE cfunc.mod |
|||
|
|||
(c) Vadim Kuznetsov 2025 |
|||
|
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <math.h> |
|||
#include <complex.h> |
|||
|
|||
|
|||
#include "msline_common.h" |
|||
#include "tline_common.h" |
|||
|
|||
static double ae, ao, be, bo, ze, zo, ee, eo; |
|||
|
|||
static void copy_complex(double complex s, Complex_t *d) |
|||
{ |
|||
d->real = creal(s); |
|||
d->imag = cimag(s); |
|||
} |
|||
|
|||
|
|||
static cpline_state_t *state = NULL; |
|||
|
|||
static void analyseQuasiStatic (double W, double h, double s, |
|||
double t, double er, |
|||
int SModel, double* Zle, |
|||
double* Zlo, double* ErEffe, |
|||
double* ErEffo); |
|||
|
|||
static void analyseDispersion (double W, double h, double s, |
|||
double t, double er, double Zle, |
|||
double Zlo, double ErEffe, |
|||
double ErEffo, double frequency, |
|||
int DModel, double *ZleFreq, |
|||
double *ZloFreq, |
|||
double *ErEffeFreq, |
|||
double *ErEffoFreq); |
|||
|
|||
static void calcPropagation (double W, double s, |
|||
double er, double h, double t, double tand, double rho, double D, |
|||
int SModel, int DModel, double frequency) |
|||
{ |
|||
|
|||
// quasi-static analysis |
|||
double Zle, ErEffe, Zlo, ErEffo; |
|||
analyseQuasiStatic (W, h, s, t, er, SModel, &Zle, &Zlo, &ErEffe, &ErEffo); |
|||
|
|||
// analyse dispersion of Zl and Er |
|||
double ZleFreq, ErEffeFreq, ZloFreq, ErEffoFreq; |
|||
analyseDispersion (W, h, s, t, er, Zle, Zlo, ErEffe, ErEffo, frequency, DModel, |
|||
&ZleFreq, &ZloFreq, &ErEffeFreq, &ErEffoFreq); |
|||
|
|||
// analyse losses of line |
|||
double ace, aco, ade, ado; |
|||
analyseLoss (W, t, er, rho, D, tand, Zle, Zlo, ErEffe, |
|||
frequency, HAMMERSTAD, &ace, &ade); |
|||
analyseLoss (W, t, er, rho, D, tand, Zlo, Zle, ErEffo, |
|||
frequency, HAMMERSTAD, &aco, &ado); |
|||
|
|||
// compute propagation constants for even and odd mode |
|||
double k0 = 2 * M_PI * frequency / C0; |
|||
ae = ace + ade; |
|||
ao = aco + ado; |
|||
be = sqrt (ErEffeFreq) * k0; |
|||
bo = sqrt (ErEffoFreq) * k0; |
|||
ze = ZleFreq; |
|||
zo = ZloFreq; |
|||
ee = ErEffeFreq; |
|||
eo = ErEffoFreq; |
|||
} |
|||
|
|||
|
|||
|
|||
/* The function calculates the quasi-static dielectric constants and |
|||
characteristic impedances for the even and odd mode based upon the |
|||
given line and substrate properties for parallel coupled microstrip |
|||
lines. */ |
|||
static void analyseQuasiStatic (double W, double h, double s, |
|||
double t, double er, |
|||
int SModel, double* Zle, |
|||
double* Zlo, double* ErEffe, |
|||
double* ErEffo) { |
|||
// initialize default return values |
|||
*ErEffe = er; *ErEffo = er; |
|||
*Zlo = 42.2; *Zle = 55.7; |
|||
|
|||
// normalized width and gap |
|||
double u = W / h; |
|||
double g = s / h; |
|||
|
|||
// HAMMERSTAD and JENSEN |
|||
if (SModel == HAMMERSTAD) { |
|||
double Zl1, Fe, Fo, a, b, fo, Mu, Alpha, Beta, ErEff; |
|||
double Pe, Po, r, fo1, q, p, n, Psi, Phi, m, Theta; |
|||
|
|||
// modifying equations for even mode |
|||
m = 0.2175 + pow (4.113 + pow (20.36 / g, 6.), -0.251) + |
|||
log (pow (g, 10.) / (1 + pow (g / 13.8, 10.))) / 323; |
|||
Alpha = 0.5 * exp (-g); |
|||
Psi = 1 + g / 1.45 + pow (g, 2.09) / 3.95; |
|||
Phi = 0.8645 * pow (u, 0.172); |
|||
Pe = Phi / (Psi * (Alpha * pow (u, m) + (1 - Alpha) * pow (u, -m))); |
|||
// TODO: is this ... Psi * (Alpha ... or ... Psi / (Alpha ... ? |
|||
|
|||
// modifying equations for odd mode |
|||
n = (1 / 17.7 + exp (-6.424 - 0.76 * log (g) - pow (g / 0.23, 5.))) * |
|||
log ((10 + 68.3 * sqr (g)) / (1 + 32.5 * pow (g, 3.093))); |
|||
Beta = 0.2306 + log (pow (g, 10.) / (1 + pow (g / 3.73, 10.))) / 301.8 + |
|||
log (1 + 0.646 * pow (g, 1.175)) / 5.3; |
|||
Theta = 1.729 + 1.175 * log (1 + 0.627 / (g + 0.327 * pow (g, 2.17))); |
|||
Po = Pe - Theta / Psi * exp (Beta * pow (u, -n) * log (u)); |
|||
|
|||
// further modifying equations |
|||
r = 1 + 0.15 * (1 - exp (1 - sqr (er - 1) / 8.2) / (1 + pow (g, -6.))); |
|||
fo1 = 1 - exp (-0.179 * pow (g, 0.15) - |
|||
0.328 * pow (g, r) / log (M_E + pow (g / 7, 2.8))); |
|||
q = exp (-1.366 - g); |
|||
p = exp (-0.745 * pow (g, 0.295)) / cosh (pow (g, 0.68)); |
|||
fo = fo1 * exp (p * log (u) + q * sin (M_PI * log10 (u))); |
|||
|
|||
Mu = g * exp (-g) + u * (20 + sqr (g)) / (10 + sqr (g)); |
|||
Hammerstad_ab (Mu, er, &a, &b); |
|||
Fe = pow (1 + 10 / Mu, -a * b); |
|||
Hammerstad_ab (u, er, &a, &b); |
|||
Fo = fo * pow (1 + 10 / u, -a * b); |
|||
|
|||
// finally compute effective dielectric constants and impedances |
|||
*ErEffe = (er + 1) / 2 + (er - 1) / 2 * Fe; |
|||
*ErEffo = (er + 1) / 2 + (er - 1) / 2 * Fo; |
|||
|
|||
Hammerstad_er (u, er, a, b, &ErEff); // single microstrip |
|||
|
|||
// first variant |
|||
Zl1 = Z0 / (u + 1.98 * pow (u, 0.172)); |
|||
Zl1 /= sqrt (ErEff); |
|||
|
|||
// second variant |
|||
Hammerstad_zl (u, &Zl1); |
|||
Zl1 /= sqrt (ErEff); |
|||
|
|||
*Zle = Zl1 / (1 - Zl1 * Pe / Z0); |
|||
*Zlo = Zl1 / (1 - Zl1 * Po / Z0); |
|||
} |
|||
// KIRSCHNING and JANSEN |
|||
else if (SModel == KIRSCHING) { |
|||
double a, b, ae, be, ao, bo, v, co, d, ErEff, Zl1; |
|||
double q1, q2, q3, q4, q5, q6, q7, q8, q9, q10; |
|||
|
|||
// consider effect of finite strip thickness (JANSEN only) |
|||
double ue = u; |
|||
double uo = u; |
|||
if (t != 0 && s > 10 * (2 * t)) { |
|||
double dW = 0; |
|||
// SCHNEIDER, referred by JANSEN |
|||
if (u >= M_1_PI / 2 && M_1_PI / 2 > 2 * t / h) |
|||
dW = t * (1 + log (2 * h / t)) / M_PI; |
|||
else if (W > 2 * t) |
|||
dW = t * (1 + log (4 * M_PI * W / t)) / M_PI; |
|||
// JANSEN |
|||
double dt = 2 * t * h / s / er; |
|||
double We = W + dW * (1 - 0.5 * exp (-0.69 * dW / dt)); |
|||
double Wo = We + dt; |
|||
ue = We / h; |
|||
uo = Wo / h; |
|||
} |
|||
|
|||
// even relative dielectric constant |
|||
v = ue * (20 + sqr (g)) / (10 + sqr (g)) + g * exp (-g); |
|||
Hammerstad_ab (v, er, &ae, &be); |
|||
Hammerstad_er (v, er, ae, be, ErEffe); |
|||
|
|||
// odd relative dielectric constant |
|||
Hammerstad_ab (uo, er, &a, &b); |
|||
Hammerstad_er (uo, er, a, b, &ErEff); |
|||
d = 0.593 + 0.694 * exp (-0.562 * uo); |
|||
bo = 0.747 * er / (0.15 + er); |
|||
co = bo - (bo - 0.207) * exp (-0.414 * uo); |
|||
ao = 0.7287 * (ErEff - (er + 1) / 2) * (1 - exp (-0.179 * uo)); |
|||
*ErEffo = ((er + 1) / 2 + ao - ErEff) * exp (-co * pow (g, d)) + ErEff; |
|||
|
|||
// characteristic impedance of single line |
|||
Hammerstad_zl (u, &Zl1); |
|||
Zl1 /= sqrt (ErEff); |
|||
|
|||
// even characteristic impedance |
|||
q1 = 0.8695 * pow (ue, 0.194); |
|||
q2 = 1 + 0.7519 * g + 0.189 * pow (g, 2.31); |
|||
q3 = 0.1975 + pow (16.6 + pow (8.4 / g, 6.), -0.387) + |
|||
log (pow (g, 10.) / (1 + pow (g / 3.4, 10.))) / 241; |
|||
q4 = q1 / q2 * 2 / |
|||
(exp (-g) * pow (ue, q3) + (2 - exp (-g)) * pow (ue, -q3)); |
|||
*Zle = sqrt (ErEff / *ErEffe) * Zl1 / (1 - Zl1 * sqrt (ErEff) * q4 / Z0); |
|||
|
|||
// odd characteristic impedance |
|||
q5 = 1.794 + 1.14 * log (1 + 0.638 / (g + 0.517 * pow (g, 2.43))); |
|||
q6 = 0.2305 + log (pow (g, 10.) / (1 + pow (g / 5.8, 10.))) / 281.3 + |
|||
log (1 + 0.598 * pow (g, 1.154)) / 5.1; |
|||
q7 = (10 + 190 * sqr (g)) / (1 + 82.3 * cubic (g)); |
|||
q8 = exp (-6.5 - 0.95 * log (g) - pow (g / 0.15, 5.)); |
|||
q9 = log (q7) * (q8 + 1 / 16.5); |
|||
q10 = (q2 * q4 - q5 * exp (log (uo) * q6 * pow (uo, -q9))) / q2; |
|||
*Zlo = sqrt (ErEff / *ErEffo) * Zl1 / (1 - Zl1 * sqrt (ErEff) * q10 / Z0); |
|||
} |
|||
} |
|||
|
|||
/* The function computes the dispersion effects on the dielectric |
|||
constants and characteristic impedances for the even and odd mode |
|||
of parallel coupled microstrip lines. */ |
|||
static void analyseDispersion (double W, double h, double s, |
|||
double t, double er, double Zle, |
|||
double Zlo, double ErEffe, |
|||
double ErEffo, double frequency, |
|||
int DModel, double *ZleFreq, |
|||
double *ZloFreq, |
|||
double *ErEffeFreq, |
|||
double *ErEffoFreq) { |
|||
|
|||
// initialize default return values |
|||
*ZleFreq = Zle; |
|||
*ErEffeFreq = ErEffe; |
|||
*ZloFreq = Zlo; |
|||
*ErEffoFreq = ErEffo; |
|||
|
|||
// normalized width and gap |
|||
double u = W / h; |
|||
double g = s / h; |
|||
double ue, uo; |
|||
double B, dW, dt; |
|||
|
|||
// compute u_odd, u_even |
|||
if (t > 0.0) { |
|||
if (u < 0.1592) { |
|||
B = 2 * M_PI * W; |
|||
} else { |
|||
B = h; |
|||
} |
|||
dW = t * (1.0 + log(2 * B / t)) / M_PI; |
|||
dt = t / (er * g); |
|||
ue = (W + dW * (1.0 - 0.5 * exp( -0.69 * dW / dt ))) / h; |
|||
uo = ue + dt / h; |
|||
} else { |
|||
ue = u; |
|||
uo = u; |
|||
} |
|||
|
|||
// GETSINGER |
|||
if (DModel == GETSINGER) { |
|||
// even mode dispersion |
|||
Getsinger_disp (h, er, ErEffe, Zle / 2, |
|||
frequency, ErEffeFreq, ZleFreq); |
|||
*ZleFreq *= 2; |
|||
// odd mode dispersion |
|||
Getsinger_disp (h, er, ErEffo, Zlo * 2, |
|||
frequency, ErEffoFreq, ZloFreq); |
|||
*ZloFreq /= 2; |
|||
} |
|||
// KIRSCHNING and JANSEN |
|||
else if (DModel == DISP_KIRSCHING) { |
|||
double p1, p2, p3, p4, p5, p6, p7, Fe; |
|||
double fn = frequency * h * 1e-6; |
|||
|
|||
// even relative dielectric constant dispersion |
|||
p1 = 0.27488 * (0.6315 + 0.525 / pow (1 + 0.0157 * fn, 20.)) * ue - |
|||
0.065683 * exp (-8.7513 * ue); |
|||
p2 = 0.33622 * (1 - exp (-0.03442 * er)); |
|||
p3 = 0.0363 * exp (-4.6 * ue) * (1 - exp (- pow (fn / 38.7, 4.97))); |
|||
p4 = 1 + 2.751 * (1 - exp (- pow (er / 15.916, 8.))); |
|||
p5 = 0.334 * exp (-3.3 * cubic (er / 15)) + 0.746; |
|||
p6 = p5 * exp (- pow (fn / 18, 0.368)); |
|||
p7 = 1 + 4.069 * p6 * pow (g, 0.479) * |
|||
exp (-1.347 * pow (g, 0.595) - 0.17 * pow (g, 2.5)); |
|||
Fe = p1 * p2 * pow ((p3 * p4 + 0.1844 * p7) * fn, 1.5763); |
|||
*ErEffeFreq = er - (er - ErEffe) / (1 + Fe); |
|||
|
|||
// odd relative dielectric constant dispersion |
|||
double p8, p9, p10, p11, p12, p13, p14, p15, Fo; |
|||
p1 = 0.27488 * (0.6315 + 0.525 / pow (1 + 0.0157 * fn, 20.)) * uo - |
|||
0.065683 * exp (-8.7513 * uo); |
|||
p3 = 0.0363 * exp (-4.6 * uo) * (1 - exp (- pow (fn / 38.7, 4.97))); |
|||
p8 = 0.7168 * (1 + 1.076 / (1 + 0.0576 * (er - 1))); |
|||
p9 = p8 - 0.7913 * (1 - exp (- pow (fn / 20, 1.424))) * |
|||
atan (2.481 * pow (er / 8, 0.946)); |
|||
p10 = 0.242 * pow (er - 1, 0.55); |
|||
p11 = 0.6366 * (exp (-0.3401 * fn) - 1) * |
|||
atan (1.263 * pow (uo / 3, 1.629)); |
|||
p12 = p9 + (1 - p9) / (1 + 1.183 * pow (uo, 1.376)); |
|||
p13 = 1.695 * p10 / (0.414 + 1.605 * p10); |
|||
p14 = 0.8928 + 0.1072 * (1 - exp (-0.42 * pow (fn / 20, 3.215))); |
|||
p15 = fabs (1 - 0.8928 * (1 + p11) * |
|||
exp (-p13 * pow (g, 1.092)) * p12 / p14); |
|||
Fo = p1 * p2 * pow ((p3 * p4 + 0.1844) * fn * p15, 1.5763); |
|||
*ErEffoFreq = er - (er - ErEffo) / (1 + Fo); |
|||
|
|||
// dispersion of even characteristic impedance |
|||
double t, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21; |
|||
q11 = 0.893 * (1 - 0.3 / (1 + 0.7 * (er - 1))); |
|||
t = pow (fn / 20, 4.91); |
|||
q12 = 2.121 * t / (1 + q11 * t) * exp (-2.87 * g) * pow (g, 0.902); |
|||
q13 = 1 + 0.038 * pow (er / 8, 5.1); |
|||
t = quadr (er / 15); |
|||
q14 = 1 + 1.203 * t / (1 + t); |
|||
q15 = 1.887 * exp (-1.5 * pow (g, 0.84)) * pow (g, q14) / |
|||
(1 + 0.41 * pow (fn / 15, 3.) * |
|||
pow (u, 2 / q13) / (0.125 + pow (u, 1.626 / q13))); |
|||
q16 = q15 * (1 + 9 / (1 + 0.403 * sqr (er - 1))); |
|||
q17 = 0.394 * (1 - exp (-1.47 * pow (u / 7, 0.672))) * |
|||
(1 - exp (-4.25 * pow (fn / 20, 1.87))); |
|||
q18 = 0.61 * (1 - exp (-2.31 * pow (u / 8, 1.593))) / |
|||
(1 + 6.544 * pow (g, 4.17)); |
|||
q19 = 0.21 * quadr (g) / (1 + 0.18 * pow (g, 4.9)) / (1 + 0.1 * sqr (u)) / |
|||
(1 + pow (fn / 24, 3.)); |
|||
q20 = q19 * (0.09 + 1 / (1 + 0.1 * pow (er - 1, 2.7))); |
|||
t = pow (u, 2.5); |
|||
q21 = fabs (1 - 42.54 * pow (g, 0.133) * exp (-0.812 * g) * t / |
|||
(1 + 0.033 * t)); |
|||
|
|||
double re, qe, pe, de, Ce, q0, ZlFreq, ErEffFreq; |
|||
Kirschning_er (u, fn, er, ErEffe, &ErEffFreq); |
|||
Kirschning_zl (u, fn, er, ErEffe, ErEffFreq, Zle, &q0, &ZlFreq); |
|||
re = pow (fn / 28.843, 12.); |
|||
qe = 0.016 + pow (0.0514 * er * q21, 4.524); |
|||
pe = 4.766 * exp (-3.228 * pow (u, 0.641)); |
|||
t = pow (er - 1, 6.); |
|||
de = 5.086 * qe * re / (0.3838 + 0.386 * qe) * |
|||
exp (-22.2 * pow (u, 1.92)) / (1 + 1.2992 * re) * t / (1 + 10 * t); |
|||
Ce = 1 + 1.275 * (1 - exp (-0.004625 * pe * pow (er, 1.674) * |
|||
pow (fn / 18.365, 2.745))) - q12 + q16 - q17 + q18 + q20; |
|||
*ZleFreq = Zle * pow ((0.9408 * pow (ErEffFreq, Ce) - 0.9603) / |
|||
((0.9408 - de) * pow (ErEffe, Ce) - 0.9603), q0); |
|||
|
|||
// dispersion of odd characteristic impedance |
|||
double q22, q23, q24, q25, q26, q27, q28, q29; |
|||
Kirschning_er (u, fn, er, ErEffo, &ErEffFreq); |
|||
Kirschning_zl (u, fn, er, ErEffo, ErEffFreq, Zlo, &q0, &ZlFreq); |
|||
q29 = 15.16 / (1 + 0.196 * sqr (er - 1)); |
|||
t = sqr (er - 1); |
|||
q25 = 0.3 * sqr (fn) / (10 + sqr (fn)) * (1 + 2.333 * t / (5 + t)); |
|||
t = pow ((er - 1) / 13, 12.); |
|||
q26 = 30 - 22.2 * t / (1 + 3 * t) - q29; |
|||
t = pow (er - 1, 1.5); |
|||
q27 = 0.4 * pow (g, 0.84) * (1 + 2.5 * t / (5 + t)); |
|||
t = pow (er - 1, 3.); |
|||
q28 = 0.149 * t / (94.5 + 0.038 * t); |
|||
q22 = 0.925 * pow (fn / q26, 1.536) / (1 + 0.3 * pow (fn / 30, 1.536)); |
|||
q23 = 1 + 0.005 * fn * q27 / (1 + 0.812 * pow (fn / 15, 1.9)) / |
|||
(1 + 0.025 * sqr (u)); |
|||
t = pow (u, 0.894); |
|||
q24 = 2.506 * q28 * t / (3.575 + t) * |
|||
pow ((1 + 1.3 * u) * fn / 99.25, 4.29); |
|||
*ZloFreq = ZlFreq + (Zlo * pow (*ErEffoFreq / ErEffo, q22) - ZlFreq * q23) / |
|||
(1 + q24 + pow (0.46 * g, 2.2) * q25); |
|||
|
|||
} |
|||
} |
|||
|
|||
void cm_cpmline (ARGS) |
|||
{ |
|||
Complex_t z11, z12, z13, z14; |
|||
|
|||
/* how to get properties of this component, e.g. L, W */ |
|||
double W = PARAM(w); |
|||
double l = PARAM(l); |
|||
double s = PARAM(s); |
|||
int SModel = PARAM(model); |
|||
int DModel = PARAM(disp); |
|||
|
|||
/* how to get properties of the substrate, e.g. Er, H */ |
|||
double er = PARAM(er); |
|||
double h = PARAM(h); |
|||
double t = PARAM(t); |
|||
double tand = PARAM(tand); |
|||
double rho = PARAM(rho); |
|||
double D = PARAM(d); |
|||
|
|||
|
|||
|
|||
/* Compute the output */ |
|||
if(ANALYSIS == DC) { |
|||
calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel,0); |
|||
|
|||
double V1 = INPUT(p1s); |
|||
double V2 = INPUT(p2s); |
|||
double V3 = INPUT(p3s); |
|||
double V4 = INPUT(p4s); |
|||
double I1 = INPUT(p1); |
|||
double I2 = INPUT(p2); |
|||
double I3 = INPUT(p3); |
|||
double I4 = INPUT(p4); |
|||
|
|||
double z = sqrt(ze*zo); |
|||
|
|||
double V2out = V1 + z*I1; |
|||
double V1out = V2 + z*I2; |
|||
OUTPUT(p1) = V1out + I1*z; |
|||
OUTPUT(p2) = V2out + I2*z; |
|||
|
|||
double V3out = V4 + z*I4; |
|||
double V4out = V3 + z*I3; |
|||
OUTPUT(p3) = V3out + I3*z; |
|||
OUTPUT(p4) = V4out + I4*z; |
|||
|
|||
cm_analog_auto_partial(); |
|||
} |
|||
else if(ANALYSIS == AC) { |
|||
double o = RAD_FREQ; |
|||
calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel, o/(2*M_PI)); |
|||
double complex _Z11, _Z12, _Z13, _Z14; |
|||
double complex ge = ae + I*be; |
|||
double complex go = ao + I*bo; |
|||
|
|||
_Z11 = zo / (2*ctanh(go*l)) + ze / (2*ctanh(ge*l)); |
|||
_Z12 = zo / (2*csinh(go*l)) + ze / (2*csinh(ge*l)); |
|||
_Z13 = ze / (2*csinh(ge*l)) - zo / (2*csinh(go*l)); |
|||
_Z14 = ze / (2*ctanh(ge*l)) - zo / (2*ctanh(go*l)); |
|||
|
|||
copy_complex(_Z11,&z11); |
|||
copy_complex(_Z12,&z12); |
|||
copy_complex(_Z13,&z13); |
|||
copy_complex(_Z14,&z14); |
|||
|
|||
AC_GAIN(p1,p1) = z11; AC_GAIN(p2,p2) = z11; |
|||
AC_GAIN(p3,p3) = z11; AC_GAIN(p4,p4) = z11; |
|||
|
|||
AC_GAIN(p1,p2) = z12; AC_GAIN(p2,p1) = z12; |
|||
AC_GAIN(p3,p4) = z12; AC_GAIN(p4,p3) = z12; |
|||
|
|||
AC_GAIN(p1,p3) = z13; AC_GAIN(p3,p1) = z13; |
|||
AC_GAIN(p2,p4) = z13; AC_GAIN(p4,p2) = z13; |
|||
|
|||
AC_GAIN(p1,p4) = z14; AC_GAIN(p4,p1) = z14; |
|||
AC_GAIN(p2,p3) = z14; AC_GAIN(p3,p2) = z14; |
|||
} |
|||
else if(ANALYSIS == TRANSIENT) { |
|||
calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel,0); |
|||
double t = TIME; |
|||
double Vp[PORT_NUM]; |
|||
double Ip[PORT_NUM]; |
|||
double Vnew[PORT_NUM]; |
|||
Vp[0] = INPUT(p1s); |
|||
Vp[1] = INPUT(p2s); |
|||
Vp[2] = INPUT(p3s); |
|||
Vp[3] = INPUT(p4s); |
|||
Ip[0] = INPUT(p1); |
|||
Ip[1] = INPUT(p2); |
|||
Ip[2] = INPUT(p3); |
|||
Ip[3] = INPUT(p4); |
|||
double delay = l/(C0); |
|||
append_cpline_state(&state, t, Vp, Ip, 1.2*delay); |
|||
if (t > delay) { |
|||
cpline_state_t *pp = find_cpline_state(state, t - delay); |
|||
if (pp != NULL) { |
|||
|
|||
double J1e = 0.5*(Ip[3] + Ip[0]); |
|||
double J1o = 0.5*(Ip[0] - Ip[3]); |
|||
double J2e = 0.5*(Ip[1] + Ip[2]); |
|||
double J2o = 0.5*(Ip[1] - Ip[2]); |
|||
|
|||
|
|||
double J1et = 0.5*(pp->Ip[3] + pp->Ip[0]); |
|||
double J1ot = 0.5*(pp->Ip[0] - pp->Ip[3]); |
|||
double J2et = 0.5*(pp->Ip[1] + pp->Ip[2]); |
|||
double J2ot = 0.5*(pp->Ip[1] - pp->Ip[2]); |
|||
|
|||
|
|||
double V1et = 0.5*(pp->Vp[3] + pp->Vp[0]); |
|||
double V1ot = 0.5*(pp->Vp[0] - pp->Vp[3]); |
|||
double V2et = 0.5*(pp->Vp[1] + pp->Vp[2]); |
|||
double V2ot = 0.5*(pp->Vp[1] - pp->Vp[2]); |
|||
|
|||
double V1e = ze*J1e + V2et + ze*J2et; |
|||
double V1o = zo*J1o + V2ot + zo*J2ot; |
|||
double V2e = ze*J2e + V1et + ze*J1et; |
|||
double V2o = zo*J2o + V1ot + zo*J1ot; |
|||
|
|||
double V1 = V1o + V1e; |
|||
double V2 = V2o + V2e; |
|||
double V3 = V2e - V2o; |
|||
double V4 = V1e - V1o; |
|||
|
|||
OUTPUT(p1) = V1; |
|||
OUTPUT(p2) = V2; |
|||
OUTPUT(p3) = V3; |
|||
OUTPUT(p4) = V4; |
|||
} |
|||
cm_analog_auto_partial(); |
|||
} else { |
|||
cm_analog_auto_partial(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,216 @@ |
|||
/* =========================================================================== |
|||
FILE ifspec.ifs |
|||
|
|||
(c) vadim Kuznetsov 2025 |
|||
|
|||
=========================================================================== */ |
|||
|
|||
/* Ports connection |
|||
4 --||||||-- 3 |
|||
|
|||
1 --||||||-- 2 |
|||
*/ |
|||
|
|||
NAME_TABLE: |
|||
|
|||
Spice_Model_Name: cpmlin |
|||
C_Function_Name: cm_cpmline |
|||
Description: "Generic transmission line" |
|||
|
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p1 |
|||
Description: "Terminals Line1" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p2 |
|||
Description: "Terminals Line1" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p3 |
|||
Description: "Terminals Line2" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p4 |
|||
Description: "Terminals Line2" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p1s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p2s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p3s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: p4s |
|||
Description: "Sensing terminals line 1" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: l |
|||
Description: "length" |
|||
Data_Type: real |
|||
Default_Value: 1.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: w |
|||
Description: "width" |
|||
Data_Type: real |
|||
Default_Value: 1e-3 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: s |
|||
Description: "gap" |
|||
Data_Type: real |
|||
Default_Value: 1e-3 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: model |
|||
Description: "Model type" |
|||
Data_Type: int |
|||
Default_Value: 0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: disp |
|||
Description: "Dispersion type" |
|||
Data_Type: int |
|||
Default_Value: 0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: er |
|||
Description: "Substrate dielectric permittivity" |
|||
Data_Type: real |
|||
Default_Value: 9.8 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: h |
|||
Description: "Substrate thickness" |
|||
Data_Type: real |
|||
Default_Value: 1e-3 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: t |
|||
Description: "Metal strip thickness" |
|||
Data_Type: real |
|||
Default_Value: 35e-6 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: tand |
|||
Description: "Substrate dielectric loss" |
|||
Data_Type: real |
|||
Default_Value: 2e-4 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: rho |
|||
Description: "Metal resistance" |
|||
Data_Type: real |
|||
Default_Value: 0.022e-6 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: d |
|||
Description: "RMS Substrate roughness" |
|||
Data_Type: real |
|||
Default_Value: 0.15e-6 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
@ -0,0 +1,133 @@ |
|||
/* =========================================================================== |
|||
FILE cfunc.mod |
|||
|
|||
(c) Vadim Kuznetsov 2025 |
|||
|
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
#include <math.h> |
|||
#include <complex.h> |
|||
|
|||
#include "tline_common.h" |
|||
|
|||
#include "msline_common.h" |
|||
|
|||
static tline_state_t *sim_points = NULL; |
|||
|
|||
static double zl, alpha, beta, ereff; |
|||
|
|||
static void calcPropagation (double W, int SModel, int DModel, |
|||
double er, double h, double t, double tand, double rho, double D, |
|||
double frequency) { |
|||
|
|||
/* local variables */ |
|||
double ac, ad; |
|||
double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq; |
|||
|
|||
// quasi-static effective dielectric constant of substrate + line and |
|||
// the impedance of the microstrip line |
|||
mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff); |
|||
|
|||
// analyse dispersion of Zl and Er (use WEff here?) |
|||
mslineAnalyseDispersion (W, h, er, ZlEff, ErEff, frequency, DModel, |
|||
&ZlEffFreq, &ErEffFreq); |
|||
|
|||
// analyse losses of line |
|||
analyseLoss (W, t, er, rho, D, tand, ZlEff, ZlEff, ErEff, |
|||
frequency, HAMMERSTAD, &ac, &ad); |
|||
|
|||
// calculate propagation constants and reference impedance |
|||
zl = ZlEffFreq; |
|||
ereff = ErEffFreq; |
|||
alpha = ac + ad; |
|||
beta = sqrt (ErEffFreq) * 2 * M_PI * frequency / C0; |
|||
} |
|||
|
|||
void cm_mlin (ARGS) |
|||
{ |
|||
Complex_t z11, z21; |
|||
|
|||
|
|||
/* how to get properties of this component, e.g. L, W */ |
|||
double W = PARAM(w); |
|||
double l = PARAM(l); |
|||
int SModel = PARAM(model); |
|||
int DModel = PARAM(disp); |
|||
int TModel = PARAM(tranmodel); |
|||
|
|||
/* how to get properties of the substrate, e.g. Er, H */ |
|||
double er = PARAM(er); |
|||
double h = PARAM(h); |
|||
double t = PARAM(t); |
|||
double tand = PARAM(tand); |
|||
double rho = PARAM(rho); |
|||
double D = PARAM(d); |
|||
|
|||
|
|||
|
|||
/* Initialize/access instance specific storage for capacitor voltage */ |
|||
if(INIT) { |
|||
|
|||
} |
|||
|
|||
/* Compute the output */ |
|||
if(ANALYSIS == DC) { |
|||
|
|||
calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,0); |
|||
double V1 = INPUT(V1sens); |
|||
double V2 = INPUT(V2sens); |
|||
double I1 = INPUT(port1); |
|||
double I2 = INPUT(port2); |
|||
double V2out = V1 + zl*I1; |
|||
double V1out = V2 + zl*I2; |
|||
OUTPUT(port1) = V1out + I1*zl; |
|||
OUTPUT(port2) = V2out + I2*zl; |
|||
|
|||
cm_analog_auto_partial(); |
|||
} |
|||
else if(ANALYSIS == AC) { |
|||
double frequency = RAD_FREQ/(2.0*M_PI); |
|||
calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,frequency); |
|||
|
|||
double complex g = alpha + beta*I; |
|||
double complex _Z11 = zl / ctanh(g*l); |
|||
double complex _Z21 = zl / csinh(g*l); |
|||
|
|||
z11.real = creal(_Z11); z11.imag = cimag(_Z11); |
|||
z21.real = creal(_Z21); z21.imag = cimag(_Z21); |
|||
|
|||
AC_GAIN(port1,port1) = z11; AC_GAIN(port2,port2) = z11; |
|||
AC_GAIN(port1,port2) = z21; AC_GAIN(port2,port1) = z21; |
|||
} |
|||
else if(ANALYSIS == TRANSIENT) { |
|||
calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,0); |
|||
double t = TIME; |
|||
double V1 = INPUT(V1sens); |
|||
double V2 = INPUT(V2sens); |
|||
double I1 = INPUT(port1); |
|||
double I2 = INPUT(port2); |
|||
double delay = l/(C0) * sqrt(ereff); |
|||
if (TModel == TRAN_FULL) { |
|||
append_state(&sim_points, t, V1, V2, I1, I2, 1.2*delay); |
|||
} |
|||
if (t > delay && TModel == TRAN_FULL) { |
|||
tline_state_t *pp = get_state(sim_points, t - delay); |
|||
if (pp != NULL) { |
|||
double V2out = pp->V1 + zl*(pp->I1); |
|||
double V1out = pp->V2 + zl*(pp->I2); |
|||
OUTPUT(port1) = V1out + I1*zl; |
|||
OUTPUT(port2) = V2out + I2*zl; |
|||
} |
|||
cm_analog_auto_partial(); |
|||
} else { |
|||
double V2out = V1 + zl*I1; |
|||
double V1out = V2 + zl*I2; |
|||
OUTPUT(port1) = V1out + I1*zl; |
|||
OUTPUT(port2) = V2out + I2*zl; |
|||
cm_analog_auto_partial(); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,173 @@ |
|||
/* =========================================================================== |
|||
FILE ifspec.ifs |
|||
|
|||
(c) vadim Kuznetsov 2025 |
|||
|
|||
=========================================================================== */ |
|||
|
|||
NAME_TABLE: |
|||
|
|||
Spice_Model_Name: mlin |
|||
C_Function_Name: cm_mlin |
|||
Description: "Microstrip line" |
|||
|
|||
|
|||
PORT_TABLE: |
|||
Port_Name: port1 |
|||
Description: "Microstrip terminals" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: port2 |
|||
Description: "Microstrip terminals" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: V1sens |
|||
Description: "Sensing terminals" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: V2sens |
|||
Description: "Sensisng terminals" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: l |
|||
Description: "length" |
|||
Data_Type: real |
|||
Default_Value: 1e-2 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: w |
|||
Description: "width" |
|||
Data_Type: real |
|||
Default_Value: 1e-3 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: model |
|||
Description: "Model type" |
|||
Data_Type: int |
|||
Default_Value: 0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: disp |
|||
Description: "Dispersion type" |
|||
Data_Type: int |
|||
Default_Value: 0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: er |
|||
Description: "Substrate dielectric permittivity" |
|||
Data_Type: real |
|||
Default_Value: 9.8 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: h |
|||
Description: "Substrate thickness" |
|||
Data_Type: real |
|||
Default_Value: 1e-3 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: t |
|||
Description: "Metal strip thickness" |
|||
Data_Type: real |
|||
Default_Value: 35e-6 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: tand |
|||
Description: "Substrate dielectric loss" |
|||
Data_Type: real |
|||
Default_Value: 2e-4 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: rho |
|||
Description: "Metal resistance" |
|||
Data_Type: real |
|||
Default_Value: 0.022e-6 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: d |
|||
Description: "RMS Substrate roughness" |
|||
Data_Type: real |
|||
Default_Value: 0.15e-6 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: tranmodel |
|||
Description: "RMS Substrate roughness" |
|||
Data_Type: int |
|||
Default_Value: 0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
|
|||
|
|||
@ -0,0 +1,4 @@ |
|||
mlin |
|||
tline |
|||
cpline |
|||
cpmlin |
|||
@ -0,0 +1,91 @@ |
|||
/* =========================================================================== |
|||
FILE cfunc.mod |
|||
|
|||
(c) Vadim Kuznetsov 2025 |
|||
|
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
#include <math.h> |
|||
#include <complex.h> |
|||
|
|||
#include "msline_common.h" |
|||
#include "tline_common.h" |
|||
|
|||
static tline_state_t *sim_points = NULL; |
|||
|
|||
|
|||
void cm_tline (ARGS) |
|||
{ |
|||
Complex_t z11, z21; |
|||
|
|||
|
|||
/* how to get properties of this component, e.g. L, W */ |
|||
double z = PARAM(z); |
|||
double l = PARAM(l); |
|||
double a = PARAM(a); |
|||
|
|||
double alpha = pow(10,0.05*a); |
|||
alpha = log(alpha)/2.0; |
|||
|
|||
/* Initialize/access instance specific storage for capacitor voltage */ |
|||
if(INIT) { |
|||
|
|||
} |
|||
|
|||
/* Compute the output */ |
|||
if(ANALYSIS == DC) { |
|||
|
|||
double V1 = INPUT(V1sens); |
|||
double V2 = INPUT(V2sens); |
|||
double I1 = INPUT(in); |
|||
double I2 = INPUT(out); |
|||
double V2out = V1 + z*I1; |
|||
double V1out = V2 + z*I2; |
|||
OUTPUT(in) = V1out + I1*z; |
|||
OUTPUT(out) = V2out + I2*z; |
|||
|
|||
cm_analog_auto_partial(); |
|||
} |
|||
else if(ANALYSIS == AC) { |
|||
double beta = RAD_FREQ/C0; |
|||
double complex g = alpha + beta*I; |
|||
double complex _Z11 = z / ctanh(g*l); |
|||
double complex _Z21 = z / csinh (g*l); |
|||
|
|||
z11.real = creal(_Z11); |
|||
z11.imag = cimag(_Z11); |
|||
z21.real = creal(_Z21); |
|||
z21.imag = cimag(_Z21); |
|||
|
|||
|
|||
AC_GAIN(in, in) = z11; AC_GAIN(out,out) = z11; |
|||
AC_GAIN(in,out) = z21; AC_GAIN(out,in) = z21; |
|||
} |
|||
else if(ANALYSIS == TRANSIENT) { |
|||
double t = TIME; |
|||
double V1 = INPUT(V1sens); |
|||
double V2 = INPUT(V2sens); |
|||
double I1 = INPUT(in); |
|||
double I2 = INPUT(out); |
|||
double delay = l/(C0); |
|||
append_state(&sim_points, t, V1, V2, I1, I2, 1.2*delay); |
|||
if (t > delay) { |
|||
tline_state_t *pp = get_state(sim_points, t - delay); |
|||
if (pp != NULL) { |
|||
double V2out = pp->V1 + z*(pp->I1); |
|||
double V1out = pp->V2 + z*(pp->I2); |
|||
OUTPUT(in) = V1out + I1*z; |
|||
OUTPUT(out) = V2out + I2*z; |
|||
} |
|||
cm_analog_auto_partial(); |
|||
} else { |
|||
double V2out = V1 + z*I1; |
|||
double V1out = V2 + z*I2; |
|||
OUTPUT(in) = V1out + I1*z; |
|||
OUTPUT(out) = V2out + I2*z; |
|||
cm_analog_auto_partial(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,87 @@ |
|||
/* =========================================================================== |
|||
FILE ifspec.ifs |
|||
|
|||
(c) vadim Kuznetsov 2025 |
|||
|
|||
=========================================================================== */ |
|||
|
|||
NAME_TABLE: |
|||
|
|||
Spice_Model_Name: tline |
|||
C_Function_Name: cm_tline |
|||
Description: "Generic transmission line" |
|||
|
|||
|
|||
PORT_TABLE: |
|||
Port_Name: in |
|||
Description: "Terminals" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: out |
|||
Description: "Terminals" |
|||
Direction: inout |
|||
Default_Type: hd |
|||
Allowed_Types: [hd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: V1sens |
|||
Description: "Sensing terminals" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
PORT_TABLE: |
|||
Port_Name: V2sens |
|||
Description: "Sensisng terminals" |
|||
Direction: in |
|||
Default_Type: vd |
|||
Allowed_Types: [vd] |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: no |
|||
|
|||
|
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: l |
|||
Description: "length" |
|||
Data_Type: real |
|||
Default_Value: 1.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: z |
|||
Description: "characteristic impedance" |
|||
Data_Type: real |
|||
Default_Value: 50.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
PARAMETER_TABLE: |
|||
Parameter_Name: a |
|||
Description: "attenuation per length (dB)" |
|||
Data_Type: real |
|||
Default_Value: 0.0 |
|||
Limits: - |
|||
Vector: no |
|||
Vector_Bounds: - |
|||
Null_Allowed: yes |
|||
|
|||
|
|||
@ -0,0 +1,337 @@ |
|||
/* msline_common.c |
|||
* common definitions for microstrip devices |
|||
* (c) Vadim Kuznetsov 2025 |
|||
*/ |
|||
|
|||
#include <stdio.h> |
|||
#include <math.h> |
|||
|
|||
#include "tline_common.h" |
|||
#include "msline_common.h" |
|||
|
|||
/* This function calculates the quasi-static impedance of a microstrip |
|||
* line, the value of the effective dielectric constant and the |
|||
* effective width due to the finite conductor thickness for the given |
|||
* microstrip line and substrate properties. */ |
|||
void mslineAnalyseQuasiStatic (double W, double h, double t, |
|||
double er, int Model, |
|||
double *ZlEff, double *ErEff, |
|||
double *WEff) { |
|||
|
|||
double z, e; |
|||
|
|||
// default values |
|||
e = er; |
|||
z = z0; |
|||
*WEff = W; |
|||
|
|||
// WHEELER |
|||
if (Model == WHEELER) { |
|||
double a, b, c, d, x, dW1, dWr, Wr; |
|||
|
|||
// compute strip thickness effect |
|||
if (t != 0) { |
|||
dW1 = t / M_PI * log (4 * M_E / sqrt (sqr (t / h) + |
|||
sqr (M_1_PI / (W / t + 1.10)))); |
|||
} |
|||
else dW1 = 0; |
|||
dWr = (1 + 1 / er) / 2 * dW1; |
|||
Wr = W + dWr; *WEff =Wr; |
|||
|
|||
// compute characteristic impedance |
|||
if (W / h < 3.3) { |
|||
c = log (4 * h / Wr + sqrt (sqr (4 * h / Wr) + 2)); |
|||
b = (er - 1) / (er + 1) / 2 * (log (M_PI_2) + log (2 * M_2_PI) / er); |
|||
z = (c - b) * Z0 / M_PI / sqrt (2 * (er + 1)); |
|||
} |
|||
else { |
|||
c = 1 + log (M_PI_2) + log (Wr / h / 2 + 0.94); |
|||
d = M_1_PI / 2 * (1 + log (sqr (M_PI) / 16)) * (er - 1) / sqr (er); |
|||
x = 2 * M_LN2 / M_PI + Wr / h / 2 + (er + 1) / 2 / M_PI / er * c + d; |
|||
z = Z0 / 2 / x / sqrt (er); |
|||
} |
|||
|
|||
// compute effective dielectric constant |
|||
if (W / h < 1.3) { |
|||
a = log (8 * h / Wr) + sqr (Wr / h) / 32; |
|||
b = (er - 1) / (er + 1) / 2 * (log (M_PI_2) + log (2 * M_2_PI) / er); |
|||
e = (er + 1) / 2 * sqr (a / (a - b)); |
|||
} |
|||
else { |
|||
a = (er - 1) / 2 / M_PI / er * (log (2.1349 * Wr / h + 4.0137) - |
|||
0.5169 / er); |
|||
b = Wr / h / 2 + M_1_PI * log (8.5397 * Wr / h + 16.0547); |
|||
e = er * sqr ((b - a) / b); |
|||
} |
|||
} |
|||
// SCHNEIDER |
|||
else if (Model == SCHNEIDER) { |
|||
|
|||
double dW = 0, u = W / h; |
|||
|
|||
// consider strip thickness equations |
|||
if (t != 0 && t < W / 2) { |
|||
double arg = (u < M_1_PI / 2) ? 2 * M_PI * W / t : h / t; |
|||
dW = t / M_PI * (1 + log (2 * arg)); |
|||
if (t / dW >= 0.75) dW = 0; |
|||
} |
|||
*WEff = W + dW; u = *WEff / h; |
|||
|
|||
// effective dielectric constant |
|||
e = (er + 1) / 2 + (er - 1) / 2 / sqrt (1 + 10 / u); |
|||
|
|||
// characteristic impedance |
|||
if (u < 1.0) { |
|||
z = M_1_PI / 2 * log (8 / u + u / 4); |
|||
} |
|||
else { |
|||
z = 1 / (u + 2.42 - 0.44 / u + pow ((1. - 1. / u), 6.)); |
|||
} |
|||
z = Z0 * z / sqrt (e); |
|||
} |
|||
// HAMMERSTAD and JENSEN |
|||
else if (Model == HAMMERSTAD) { |
|||
double a, b, du1, du, u, ur, u1, zr, z1; |
|||
|
|||
u = W / h; // normalized width |
|||
t = t / h; // normalized thickness |
|||
|
|||
// compute strip thickness effect |
|||
if (t != 0) { |
|||
du1 = t / M_PI * log (1 + 4 * M_E / t / sqr (coth (sqrt (6.517 * u)))); |
|||
} |
|||
else du1 = 0; |
|||
du = du1 * (1 + sech (sqrt (er - 1))) / 2; |
|||
u1 = u + du1; |
|||
ur = u + du; |
|||
*WEff = ur * h; |
|||
|
|||
// compute impedances for homogeneous medium |
|||
Hammerstad_zl (ur, &zr); |
|||
Hammerstad_zl (u1, &z1); |
|||
|
|||
// compute effective dielectric constant |
|||
Hammerstad_ab (ur, er, &a, &b); |
|||
Hammerstad_er (ur, er, a, b, &e); |
|||
|
|||
// compute final characteristic impedance and dielectric constant |
|||
// including strip thickness effects |
|||
z = zr / sqrt (e); |
|||
e = e * sqr (z1 / zr); |
|||
} |
|||
|
|||
*ZlEff = z; |
|||
*ErEff = e; |
|||
} |
|||
|
|||
/* This function calculates the frequency dependent value of the |
|||
* effective dielectric constant and the microstrip line impedance for |
|||
* the given frequency. */ |
|||
void mslineAnalyseDispersion (double W, double h, double er, |
|||
double ZlEff, double ErEff, |
|||
double frequency, int Model, |
|||
double* ZlEffFreq, |
|||
double* ErEffFreq) { |
|||
|
|||
double e, z; |
|||
|
|||
// default values |
|||
z = *ZlEffFreq = ZlEff; |
|||
e = *ErEffFreq = ErEff; |
|||
|
|||
// GETSINGER |
|||
if (Model == GETSINGER) { |
|||
Getsinger_disp (h, er, ErEff, ZlEff, frequency, &e, &z); |
|||
} |
|||
// SCHNEIDER |
|||
else if (Model == DISP_SCHNEIDER) { |
|||
double k, f; |
|||
k = sqrt (ErEff / er); |
|||
f = 4 * h * frequency / C0 * sqrt (er - 1); |
|||
f = sqr (f); |
|||
e = ErEff * sqr ((1 + f) / (1 + k * f)); |
|||
z = ZlEff * sqrt (ErEff / e); |
|||
} |
|||
// YAMASHITA |
|||
else if (Model == YAMASHITA) { |
|||
double k, f; |
|||
k = sqrt (er / ErEff); |
|||
f = 4 * h * frequency / C0 * sqrt (er - 1) * |
|||
(0.5 + sqr (1 + 2 * log10 (1 + W / h))); |
|||
e = ErEff * sqr ((1 + k * pow (f, 1.5) / 4) / (1 + pow (f, 1.5) / 4)); |
|||
} |
|||
// KOBAYASHI |
|||
else if (Model == KOBAYASHI) { |
|||
double n, no, nc, fh, fk; |
|||
fk = C0 * atan (er * sqrt ((ErEff - 1) / (er - ErEff))) / |
|||
(2 * M_PI * h * sqrt (er - ErEff)); |
|||
fh = fk / (0.75 + (0.75 - 0.332 / pow (er, 1.73)) * W / h); |
|||
no = 1 + 1 / (1 + sqrt (W / h)) + 0.32 * cubic (1 / (1 + sqrt (W / h))); |
|||
if (W / h < 0.7) { |
|||
nc = 1 + 1.4 / (1 + W / h) * (0.15 - 0.235 * |
|||
exp (-0.45 * frequency / fh)); |
|||
} |
|||
else nc = 1; |
|||
n = no * nc < 2.32 ? no * nc : 2.32; |
|||
e = er - (er - ErEff) / (1 + pow (frequency / fh, n)); |
|||
} |
|||
// PRAMANICK and BHARTIA |
|||
else if (Model == PRAMANICK) { |
|||
double Weff, We, f; |
|||
f = 2 * MU0 * h * frequency * sqrt (ErEff / er) / ZlEff; |
|||
e = er - (er - ErEff) / (1 + sqr (f)); |
|||
Weff = Z0 * h / ZlEff / sqrt (ErEff); |
|||
We = W + (Weff - W) / (1 + sqr (f)); |
|||
z = Z0 * h / We / sqrt (e); |
|||
} |
|||
// HAMMERSTAD and JENSEN |
|||
else if (Model == DISP_HAMMERSTAD) { |
|||
double f, g; |
|||
g = sqr (M_PI) / 12 * (er - 1) / ErEff * sqrt (2 * M_PI * ZlEff / Z0); |
|||
f = 2 * MU0 * h * frequency / ZlEff; |
|||
e = er - (er - ErEff) / (1 + g * sqr (f)); |
|||
z = ZlEff * sqrt (ErEff / e) * (e - 1) / (ErEff - 1); |
|||
} |
|||
// KIRSCHNING and JANSEN |
|||
else if (Model == DISP_KIRSCHING) { |
|||
double r17, u = W / h, fn = frequency * h / 1e6; |
|||
|
|||
// dispersion of dielectric constant |
|||
Kirschning_er (u, fn, er, ErEff, &e); |
|||
|
|||
// dispersion of characteristic impedance |
|||
Kirschning_zl (u, fn, er, ErEff, e, ZlEff, &r17, &z); |
|||
} |
|||
|
|||
*ZlEffFreq = z; |
|||
*ErEffFreq = e; |
|||
} |
|||
|
|||
|
|||
/* Computes the exponent factors a(u) and b(er) used within the |
|||
* effective relative dielectric constant calculations for single and |
|||
* coupled microstrip lines by Hammerstad and Jensen. */ |
|||
void Hammerstad_ab (double u, double er, double *a, |
|||
double *b) { |
|||
*a = 1 + log ((quadr (u) + sqr (u / 52)) / (quadr (u) + 0.432)) / 49 + |
|||
log (1 + cubic (u / 18.1)) / 18.7; |
|||
*b = 0.564 * pow ((er - 0.9) / (er + 3), 0.053); |
|||
} |
|||
|
|||
/* The function computes the effective dielectric constant of a single |
|||
* microstrip. The equation is used in single and coupled microstrip |
|||
* calculations. */ |
|||
void Hammerstad_er (double u, double er, double a, |
|||
double b, double* e) { |
|||
*e = (er + 1) / 2 + (er - 1) / 2 * pow (1 + 10 / u, -a * b); |
|||
} |
|||
|
|||
/* This function computes the characteristic impedance of single |
|||
* microstrip line based upon the given width-height ratio. The |
|||
* equation is used in single and coupled microstrip calculations as |
|||
* well. */ |
|||
void Hammerstad_zl (double u, double *zl) { |
|||
double fu = 6 + (2 * M_PI - 6) * exp (- pow (30.666 / u, 0.7528)); |
|||
*zl = Z0 / 2 / M_PI * log (fu / u + sqrt (1 + sqr (2 / u))); |
|||
} |
|||
|
|||
/* Calculates dispersion effects for effective dielectric constant and |
|||
* characteristic impedance as defined by Getsinger (for single and |
|||
* coupled microstrips). */ |
|||
void Getsinger_disp (double h, double er, double ErEff, |
|||
double ZlEff, double frequency, |
|||
double *e, double *z) { |
|||
double g, f, d; |
|||
g = 0.6 + 0.009 * ZlEff; |
|||
f = frequency * 2 * MU0 * h / ZlEff; |
|||
*e = er - (er - ErEff) / (1 + g * sqr (f)); |
|||
d = (er - *e) * (*e - ErEff) / *e / (er - ErEff); |
|||
*z = ZlEff * sqrt (*e / ErEff) / (1 + d); // group delay model |
|||
} |
|||
|
|||
/* This function computes the dispersion of the effective dielectric |
|||
* constant of a single microstrip line. It is defined in a separate |
|||
* function because it is used within the coupled microstrip lines as |
|||
* well. */ |
|||
void Kirschning_er (double u, double fn, double er, |
|||
double ErEff, double* ErEffFreq) { |
|||
double p, p1, p2, p3, p4; |
|||
p1 = 0.27488 + (0.6315 + 0.525 / pow (1. + 0.0157 * fn, 20.)) * u - |
|||
0.065683 * exp (-8.7513 * u); |
|||
p2 = 0.33622 * (1 - exp (-0.03442 * er)); |
|||
p3 = 0.0363 * exp (-4.6 * u) * (1 - exp (- pow (fn / 38.7, 4.97))); |
|||
p4 = 1 + 2.751 * (1 - exp (- pow (er / 15.916, 8.))); |
|||
p = p1 * p2 * pow ((0.1844 + p3 * p4) * fn, 1.5763); |
|||
*ErEffFreq = er - (er - ErEff) / (1 + p); |
|||
} |
|||
|
|||
/* Computes dispersion effects of characteristic impedance of a single |
|||
* microstrip line according to Kirschning and Jansen. Also used in |
|||
* coupled microstrip lines calculations. */ |
|||
void Kirschning_zl (double u, double fn, double er, |
|||
double ErEff, double ErEffFreq, |
|||
double ZlEff, double* r17, |
|||
double* ZlEffFreq) { |
|||
double r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; |
|||
double r11, r12, r13, r14, r15, r16; |
|||
r1 = 0.03891 * pow (er, 1.4); |
|||
r2 = 0.267 * pow (u, 7.); |
|||
r3 = 4.766 * exp (-3.228 * pow (u, 0.641)); |
|||
r4 = 0.016 + pow (0.0514 * er, 4.524); |
|||
r5 = pow (fn / 28.843, 12.); |
|||
r6 = 22.20 * pow (u, 1.92); |
|||
r7 = 1.206 - 0.3144 * exp (-r1) * (1 - exp (-r2)); |
|||
r8 = 1 + 1.275 * (1 - exp (-0.004625 * r3 * |
|||
pow (er, 1.674) * pow (fn / 18.365, 2.745))); |
|||
r9 = 5.086 * r4 * r5 / (0.3838 + 0.386 * r4) * |
|||
exp (-r6) / (1 + 1.2992 * r5) * |
|||
pow (er - 1., 6.) / (1 + 10 * pow (er - 1., 6.)); |
|||
r10 = 0.00044 * pow (er, 2.136) + 0.0184; |
|||
r11 = pow (fn / 19.47, 6.) / (1 + 0.0962 * pow (fn / 19.47, 6.)); |
|||
r12 = 1 / (1 + 0.00245 * sqr (u)); |
|||
r13 = 0.9408 * pow (ErEffFreq, r8) - 0.9603; |
|||
r14 = (0.9408 - r9) * pow (ErEff, r8) - 0.9603; |
|||
r15 = 0.707 * r10 * pow (fn / 12.3, 1.097); |
|||
r16 = 1 + 0.0503 * sqr (er) * r11 * (1 - exp (- pow (u / 15., 6.))); |
|||
*r17 = r7 * (1 - 1.1241 * r12 / r16 * |
|||
exp (-0.026 * pow (fn, 1.15656) - r15)); |
|||
*ZlEffFreq = ZlEff * pow (r13 / r14, *r17); |
|||
} |
|||
|
|||
/* The function calculates the conductor and dielectric losses of a |
|||
* single microstrip line. */ |
|||
void analyseLoss (double W, double t, double er, |
|||
double rho, double D, double tand, |
|||
double ZlEff1, double ZlEff2, |
|||
double ErEff, |
|||
double frequency, int Model, |
|||
double* ac, double* ad) { |
|||
*ac = *ad = 0; |
|||
|
|||
// HAMMERSTAD and JENSEN |
|||
if (Model == HAMMERSTAD) { |
|||
double Rs, ds, l0, Kr, Ki; |
|||
|
|||
// conductor losses |
|||
if (t != 0.0) { |
|||
Rs = sqrt (M_PI * frequency * MU0 * rho); // skin resistance |
|||
ds = rho / Rs; // skin depth |
|||
// valid for t > 3 * ds |
|||
if (t < 3 * ds && frequency != 0) { |
|||
fprintf (stderr, |
|||
"WARNING: conductor loss calculation invalid for line " |
|||
"height t (%g) < 3 * skin depth (%g)\n", t, 3 * ds); |
|||
} |
|||
// current distribution factor |
|||
Ki = exp (-1.2 * pow ((ZlEff1 + ZlEff2) / 2 / Z0, 0.7)); |
|||
// D is RMS surface roughness |
|||
Kr = 1 + M_2_PI * atan (1.4 * sqr (D / ds)); |
|||
*ac = Rs / (ZlEff1 * W) * Ki * Kr; |
|||
} |
|||
|
|||
// dielectric losses |
|||
l0 = C0 / frequency; |
|||
*ad = M_PI * er / (er - 1) * (ErEff - 1) / sqrt (ErEff) * tand / l0; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,60 @@ |
|||
/* msline_common.h |
|||
* common definitions for microstrip devices |
|||
* (c) Vadim Kuznetsov 2025 |
|||
*/ |
|||
|
|||
|
|||
#ifndef MSLINE_COMMON_H |
|||
#define MSLINE_COMMON_H |
|||
|
|||
//TRAN model |
|||
#define TRAN_DC 0 |
|||
#define TRAN_FULL 1 |
|||
|
|||
// MS line model |
|||
#define HAMMERSTAD 0 |
|||
#define KIRSCHING 1 |
|||
#define WHEELER 2 |
|||
#define SCHNEIDER 3 |
|||
|
|||
|
|||
// Dispersion model |
|||
#define DISP_KIRSCHING 0 |
|||
#define KOBAYASHI 1 |
|||
#define YAMASHITA 2 |
|||
#define DISP_HAMMERSTAD 3 |
|||
#define GETSINGER 4 |
|||
#define DISP_SCHNEIDER 5 |
|||
#define PRAMANICK 6 |
|||
|
|||
void Hammerstad_ab (double, double, |
|||
double*, double*); |
|||
void Hammerstad_er (double, double, double, |
|||
double, double*); |
|||
void Hammerstad_zl (double, double*); |
|||
void Getsinger_disp (double, double, double, |
|||
double, double, |
|||
double*, double*); |
|||
void Kirschning_er (double, double, double, |
|||
double, double*); |
|||
void Kirschning_zl (double, double, double, |
|||
double, double, double, |
|||
double*, double*); |
|||
|
|||
void mslineAnalyseQuasiStatic (double W, double h, double t, |
|||
double er, int Model, |
|||
double *ZlEff, double *ErEff, |
|||
double *WEff); |
|||
|
|||
void mslineAnalyseDispersion (double W, double h, double er, |
|||
double ZlEff, double ErEff, |
|||
double frequency, int Model, |
|||
double* ZlEffFreq, |
|||
double* ErEffFreq); |
|||
|
|||
void analyseLoss (double, double, double, double, |
|||
double, double, double, double, |
|||
double, double, int, |
|||
double*, double*); |
|||
|
|||
#endif |
|||
@ -0,0 +1,86 @@ |
|||
/* tline_common.c |
|||
* common definitions for all transmission lines |
|||
* (c) Vadim Kuznetsov 2025 |
|||
*/ |
|||
|
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
#include "tline_common.h" |
|||
|
|||
void append_state(tline_state_t **first, double time, double V1, double V2, |
|||
double I1, double I2, double tmax) |
|||
{ |
|||
tline_state_t *pp = (tline_state_t *) malloc(sizeof(tline_state_t)); |
|||
|
|||
pp->next = NULL; |
|||
pp->time = time; |
|||
pp->V1 = V1; pp->I1 = I1; |
|||
pp->V2 = V2; pp->I2 = I2; |
|||
|
|||
if (*first == NULL) { |
|||
*first = pp; |
|||
} else { |
|||
tline_state_t *pn = *first; |
|||
while (pn->next != NULL) { |
|||
pn = pn->next; |
|||
} |
|||
pn->next = pp; |
|||
|
|||
double t0 = (*first)->time; |
|||
|
|||
if ((time - t0) > tmax) { |
|||
tline_state_t *new_first = (*first)->next; |
|||
free(*first); |
|||
*first = new_first; |
|||
} |
|||
} |
|||
} |
|||
|
|||
tline_state_t *get_state(tline_state_t *first, double time) |
|||
{ |
|||
tline_state_t *pp = first; |
|||
while (pp != NULL && pp->time < time) { |
|||
pp = pp->next; |
|||
} |
|||
return pp; |
|||
} |
|||
|
|||
|
|||
void append_cpline_state(cpline_state_t **first, double time, double *Vp, double *Ip, double tmax) |
|||
{ |
|||
cpline_state_t *pp = (cpline_state_t *) malloc(sizeof(cpline_state_t)); |
|||
|
|||
pp->next = NULL; |
|||
pp->time = time; |
|||
memcpy(pp->Vp, Vp, PORT_NUM*sizeof(double)); |
|||
memcpy(pp->Ip, Ip, PORT_NUM*sizeof(double)); |
|||
|
|||
if (*first == NULL) { |
|||
*first = pp; |
|||
} else { |
|||
cpline_state_t *pn = *first; |
|||
while (pn->next != NULL) { |
|||
pn = pn->next; |
|||
} |
|||
pn->next = pp; |
|||
|
|||
double t0 = (*first)->time; |
|||
|
|||
if ((time - t0) > tmax) { |
|||
cpline_state_t *new_first = (*first)->next; |
|||
free(*first); |
|||
*first = new_first; |
|||
} |
|||
} |
|||
} |
|||
|
|||
cpline_state_t *find_cpline_state(cpline_state_t *first, double time) |
|||
{ |
|||
cpline_state_t *pp = first; |
|||
while (pp != NULL && pp->time < time) { |
|||
pp = pp->next; |
|||
} |
|||
return pp; |
|||
} |
|||
|
|||
@ -0,0 +1,63 @@ |
|||
/* tline_common.h |
|||
* common definitions for all transmission lines |
|||
* (c) Vadim Kuznetsov 2025 |
|||
*/ |
|||
|
|||
|
|||
#ifndef TLINE_COMMON_H |
|||
#define TLINE_COMMON_H |
|||
|
|||
// Constants |
|||
#define Z0 (120*M_PI) |
|||
#define z0 50.0 |
|||
#define MU0 (4*M_PI*1e-7) |
|||
|
|||
#define C0 299792458.0 |
|||
|
|||
#define GMIN 1e-12 |
|||
|
|||
|
|||
// Functions |
|||
#define sqr(x) (x*x) |
|||
#define cubic(x) (x*x*x) |
|||
#define quadr(x) (x*x*x*x) |
|||
|
|||
#define coth(x) (1.0/tanh(x)) |
|||
#define sech(x) (1.0/cosh(x)) |
|||
#define cosech(x) (1.0/sinh(x)) |
|||
|
|||
// Data structures to hold transient state |
|||
|
|||
typedef struct tline_state { |
|||
double time; |
|||
double I1; |
|||
double I2; |
|||
double V1; |
|||
double V2; |
|||
|
|||
struct tline_state *next; |
|||
} tline_state_t; |
|||
|
|||
// Functions to retrieve previous transient state |
|||
void append_state(tline_state_t **first, double time, double V1, double V2, |
|||
double I1, double I2, double tmax); |
|||
|
|||
tline_state_t *get_state(tline_state_t *first, double time); |
|||
|
|||
#define PORT_NUM 4 |
|||
|
|||
typedef struct cpline_state { |
|||
double time; |
|||
double Ip[PORT_NUM]; |
|||
double Vp[PORT_NUM]; |
|||
|
|||
struct cpline_state *next; |
|||
} cpline_state_t; |
|||
|
|||
void append_cpline_state(cpline_state_t **first, double time, double *Vp, double *Ip, double tmax); |
|||
|
|||
cpline_state_t *find_cpline_state(cpline_state_t *first, double time); |
|||
|
|||
|
|||
|
|||
#endif |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue