diff --git a/examples/xspice/transmission_lines/cpline_ac.cir b/examples/xspice/transmission_lines/cpline_ac.cir new file mode 100644 index 000000000..f1ca315a3 --- /dev/null +++ b/examples/xspice/transmission_lines/cpline_ac.cir @@ -0,0 +1,18 @@ +* Coupled lines SP + +V1 p1 0 dc 0 ac 1 portnum 1 z0 50 +V2 p2 0 dc 0 ac 1 portnum 2 z0 50 +V3 p3 0 dc 0 ac 1 portnum 3 z0 50 +V4 p4 0 dc 0 ac 1 portnum 4 z0 50 + +A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) CPLINE1 +.MODEL CPLINE1 CPLINE(ze=84.48 zo=53.99 l=25e-3 ere=3.34 ero=2.829 ao=0 ae=0) + +.control + +sp lin 100 0.2e9 4.2e9 + +plot abs(s_1_1) abs(s_3_1) abs(s_2_1) abs(s_4_1) +plot abs(s_2_1) + +.endc diff --git a/examples/xspice/transmission_lines/cpline_tran.cir b/examples/xspice/transmission_lines/cpline_tran.cir new file mode 100644 index 000000000..c577354e3 --- /dev/null +++ b/examples/xspice/transmission_lines/cpline_tran.cir @@ -0,0 +1,23 @@ +* Coupled lines SP + +V1 1 0 PULSE(0 1 1n 10p 10p 980p) + +R2 p1 1 0.1 + +R1 p4 0 50.0 +R3 p3 0 50.0 +R4 p2 0 50.0 + +A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) %vd(p1 0) %vd(p2 0) %vd(p3 0) %vd(p4 0) CPLINE1 +.MODEL CPLINE1 CPLINE(ze=100 zo=50 l=100e-3 ere=1 ero=1 ao=0 ae=0) + +.control + +tran 10p 5n + +let v2 = -v(p2) +let v3 = -v(p3) + +plot v(1) v(p2) v(p3) v(p4) + +.endc diff --git a/examples/xspice/transmission_lines/cpmline_ac.cir b/examples/xspice/transmission_lines/cpmline_ac.cir new file mode 100644 index 000000000..035d17984 --- /dev/null +++ b/examples/xspice/transmission_lines/cpmline_ac.cir @@ -0,0 +1,18 @@ +* Coupled lines SP + +V1 p1 0 dc 0 ac 1 portnum 1 z0 50 +V2 p2 0 dc 0 ac 1 portnum 2 z0 50 +V3 p3 0 dc 0 ac 1 portnum 3 z0 50 +V4 p4 0 dc 0 ac 1 portnum 4 z0 50 + +A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) %vd(p1 0) %vd(p2 0) %vd(p3 0) %vd(p4 0) CPMLIN1 +.MODEL CPMLIN1 CPMLIN(w=1e-3 l=20e-3 s=0.3e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d1=0.15e-6 model=0 disp=0) + +.control + +sp lin 100 0.2e9 4.2e9 + +plot abs(s_1_1) abs(s_3_1) abs(s_2_1) abs(s_4_1) +plot abs(s_3_1) + +.endc diff --git a/examples/xspice/transmission_lines/mlin.cir b/examples/xspice/transmission_lines/mlin.cir new file mode 100644 index 000000000..e57fa5055 --- /dev/null +++ b/examples/xspice/transmission_lines/mlin.cir @@ -0,0 +1,22 @@ +* MLIN test + +V1 1 0 AC 1 DC 1 +R1 in 1 50.0 +R2 out 0 1000.1 +A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) MLIN1 +.MODEL MLIN1 MLIN(w=1e-3 l=10e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d=0.15e-6 model=0 disp=0) + +.control + +op +print all + +ac LIN 200 1e9 12e9 + +let z = v(in)/-i(v1) +let y = imag(z) +let r = real(z) +plot abs(z) ylog +plot y r + +.endc diff --git a/examples/xspice/transmission_lines/mlin_tran.cir b/examples/xspice/transmission_lines/mlin_tran.cir new file mode 100644 index 000000000..8db27d820 --- /dev/null +++ b/examples/xspice/transmission_lines/mlin_tran.cir @@ -0,0 +1,25 @@ +* MLIN test + +V1 1 4 PULSE(0 1 1n 10p 10p 980p) +V3 4 0 DC 1 +R1 out 2 20.0 +V2 2 0 0 +R2 in 1 1m +*R3 in ins 1e12 +*R4 out outs 1e12 +A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) MLIN1 +.MODEL MLIN1 MLIN(w=1e-3 l=50e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d1=0.15e-6 model=0 disp=0 tranmodel=1) +*A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) TLIN1 +*.MODEL TLIN1 TLINE(l=100e-3 z=50.0 a=0.0) + +.control + +*op +*print all + +tran 10p 5n + +plot v(in) v(out) +plot -i(v1) i(V2) + +.endc diff --git a/src/spinit.in b/src/spinit.in index ee3794b65..669f6f444 100644 --- a/src/spinit.in +++ b/src/spinit.in @@ -25,6 +25,7 @@ if $?xspice_enabled @XSPICEINIT@ codemodel @pkglibdir@/xtradev.cm @XSPICEINIT@ codemodel @pkglibdir@/xtraevt.cm @XSPICEINIT@ codemodel @pkglibdir@/table.cm +@XSPICEINIT@ codemodel @pkglibdir@/tlines.cm end diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index e1344da26..d26ed30b8 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -7,11 +7,11 @@ include makedefs # The codemodels to make -CMDIRS = spice2poly digital analog xtradev xtraevt table +CMDIRS = spice2poly digital analog xtradev xtraevt table tlines #Invoke $(MAKE) for each of the CMDDIRS -all: dstring.o # One common dstring object file for all code modules +all: dstring.o msline_common.o tline_common.o# Common object files for all code modules for cm in $(CMDIRS) ; do \ $(MAKE) cm=$$cm $$cm/$$cm.cm \ || exit 1; \ @@ -36,6 +36,8 @@ uninstall: clean: rm -f dstring.o + rm -f msline_common.o + rm -f tline_common.o for cm in $(CMDIRS) ; do \ $(MAKE) cm=$$cm cm-clean \ || exit 1; \ @@ -49,6 +51,12 @@ NGSRCBUILDDIR = $(CURDIR)/../.. dstring.o: $(NGSRCDIR)/misc/dstring.c $(NGSRCDIR)/include/ngspice/dstring.h $(CC) $(CFLAGS) -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $< +msline_common.o: $(srcdir)/../tlines/msline_common.c $(srcdir)/../tlines/msline_common.h + $(CC) $(CFLAGS) -I$(srcdir)/../tlines -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $< + +tline_common.o: $(srcdir)/../tlines/tline_common.c $(srcdir)/../tlines/tline_common.h + $(CC) $(CFLAGS) -I$(srcdir)/../tlines -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $< + ifdef cm ifeq ($(OS),Windows_NT) @@ -70,6 +78,8 @@ cm-gens := \ cm-objs := \ $(cm)/dlmain.o \ dstring.o \ + tline_common.o \ + msline_common.o \ $(modlst:%=$(cm)/%/cfunc.o) \ $(modlst:%=$(cm)/%/ifspec.o) \ $(udnlst:%=$(cm)/%/udnfunc.o) @@ -160,11 +170,11 @@ $(cm)/dlmain.o : $(srcdir)/dlmain.c $(cm-descr) $(do-deps) $(cm)/%/cfunc.o : $(cm)/%/cfunc.c - $(COMPILE) $(gen_pp) -I$(srcdir)/$( +#include +#include +#include +#include + +#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; + +static void cm_cpline_callback(ARGS, Mif_Callback_Reason_t reason); + +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) { + CALLBACK = cm_cpline_callback; + STATIC_VAR(sim_points_data) = NULL; + } + + /* 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); + + void **sim_points = &(STATIC_VAR(sim_points_data)); + + cpline_state_t *last = get_cpline_last_state(*(cpline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + delete_cpline_last_state((cpline_state_t **)sim_points); + } + append_cpline_state((cpline_state_t **)sim_points, t, Vp, Ip, 1.2*delay); + if (t > delay) { + cpline_state_t *pp = find_cpline_state(*(cpline_state_t **)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(); + } + } +} + +static void cm_cpline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_cpline_states((cpline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} diff --git a/src/xspice/icm/tlines/cpline/ifspec.ifs b/src/xspice/icm/tlines/cpline/ifspec.ifs new file mode 100644 index 000000000..03bf014bf --- /dev/null +++ b/src/xspice/icm/tlines/cpline/ifspec.ifs @@ -0,0 +1,191 @@ +/* =========================================================================== + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +/* 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 + + +STATIC_VAR_TABLE: + +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer + diff --git a/src/xspice/icm/tlines/cpmlin/cfunc.mod b/src/xspice/icm/tlines/cpmlin/cfunc.mod new file mode 100644 index 000000000..6d6b0939c --- /dev/null +++ b/src/xspice/icm/tlines/cpmlin/cfunc.mod @@ -0,0 +1,541 @@ +/* =========================================================================== + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#include +#include +#include +#include +#include + + +#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 cm_cpmline_callback(ARGS, Mif_Callback_Reason_t reason); + +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); + 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); + + if(INIT) { + CALLBACK = cm_cpmline_callback; + STATIC_VAR(sim_points_data) = NULL; + } + + + /* 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); + void **sim_points = &(STATIC_VAR(sim_points_data)); + if (TModel == TRAN_FULL) { + cpline_state_t *last = get_cpline_last_state(*(cpline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + delete_cpline_last_state((cpline_state_t **)sim_points); + } + append_cpline_state((cpline_state_t **)sim_points, t, Vp, Ip, 1.2*delay); + } + if (t > delay && TModel == TRAN_FULL) { + cpline_state_t *pp = find_cpline_state(*(cpline_state_t **)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 { + double z = sqrt(ze*zo); + double V2out = Vp[0] + z*Ip[0]; + double V1out = Vp[1] + z*Ip[1]; + OUTPUT(p1) = V1out + Ip[0]*z; + OUTPUT(p2) = V2out + Ip[1]*z; + + double V3out = Vp[3] + z*Ip[3]; + double V4out = Vp[2] + z*Ip[2]; + OUTPUT(p3) = V3out + Ip[2]*z; + OUTPUT(p4) = V4out + Ip[3]*z; + + cm_analog_auto_partial(); + } + } +} + +static void cm_cpmline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_cpline_states((cpline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} diff --git a/src/xspice/icm/tlines/cpmlin/ifspec.ifs b/src/xspice/icm/tlines/cpmlin/ifspec.ifs new file mode 100644 index 000000000..d4a6367c0 --- /dev/null +++ b/src/xspice/icm/tlines/cpmlin/ifspec.ifs @@ -0,0 +1,241 @@ +/* =========================================================================== + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +/* 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 + +PARAMETER_TABLE: +Parameter_Name: tranmodel +Description: "TRAN model DC/FULL" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +STATIC_VAR_TABLE: + +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer + diff --git a/src/xspice/icm/tlines/mlin/cfunc.mod b/src/xspice/icm/tlines/mlin/cfunc.mod new file mode 100644 index 000000000..caa53d2fe --- /dev/null +++ b/src/xspice/icm/tlines/mlin/cfunc.mod @@ -0,0 +1,166 @@ +/* =========================================================================== + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#include +#include +#include + +#include "tline_common.h" + +#include "msline_common.h" + +//static tline_state_t *sim_points = NULL; + +static double zl, alpha, beta, ereff; + +static void cm_mline_callback(ARGS, Mif_Callback_Reason_t reason); + +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; + void **sim_points; + + + /* 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) { + CALLBACK = cm_mline_callback; + STATIC_VAR(sim_points_data) = NULL; + } + + /* 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); + sim_points = &(STATIC_VAR(sim_points_data)); + 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) { + + tline_state_t *last = get_tline_last_state(*(tline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + //fprintf(stderr,"Rollbacki time=%g\n",TIME); + delete_tline_last_state((tline_state_t **)sim_points); + } + append_state((tline_state_t **)sim_points, t, V1, V2, I1, I2, 1.2*delay); + } + if (t > delay && TModel == TRAN_FULL) { + tline_state_t *pp = get_state(*(tline_state_t **)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(); + } + + } +} + +static void cm_mline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_tline_states((tline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} + diff --git a/src/xspice/icm/tlines/mlin/ifspec.ifs b/src/xspice/icm/tlines/mlin/ifspec.ifs new file mode 100644 index 000000000..a0e268116 --- /dev/null +++ b/src/xspice/icm/tlines/mlin/ifspec.ifs @@ -0,0 +1,186 @@ +/* =========================================================================== + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +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: "TRAN model DC/FULL" +Data_Type: int +Default_Value: 0 +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +STATIC_VAR_TABLE: + +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer + diff --git a/src/xspice/icm/tlines/modpath.lst b/src/xspice/icm/tlines/modpath.lst new file mode 100644 index 000000000..c5b11351f --- /dev/null +++ b/src/xspice/icm/tlines/modpath.lst @@ -0,0 +1,5 @@ +mlin +tline +cpline +cpmlin +msopen diff --git a/src/xspice/icm/tlines/msopen/cfunc.mod b/src/xspice/icm/tlines/msopen/cfunc.mod new file mode 100644 index 000000000..c07a36cb0 --- /dev/null +++ b/src/xspice/icm/tlines/msopen/cfunc.mod @@ -0,0 +1,120 @@ +/* =========================================================================== + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + + +#include +#include +#include + + +#include "msline_common.h" +#include "tline_common.h" + + +#define MSOPEN_KIRSCHNING 0 +#define MSOPEN_HAMMERSTAD 1 +#define MSOPEN_ALEXOPOULOS 2 + + +// Returns the microstrip open end capacitance. +static double calcCend (double frequency, double W, + double h, double t, double er, + int SModel, int DModel, + int Model) { + + double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq; + mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff); + mslineAnalyseDispersion (WEff, h, er, ZlEff, ErEff, frequency, DModel, + &ZlEffFreq, &ErEffFreq); + + W /= h; + double dl = 0; + /* Kirschning, Jansen and Koster */ + if (Model == MSOPEN_KIRSCHNING) { + double Q6 = pow (ErEffFreq, 0.81); + double Q7 = pow (W, 0.8544); + double Q1 = 0.434907 * + (Q6 + 0.26) / (Q6 - 0.189) * (Q7 + 0.236) / (Q7 + 0.87); + double Q2 = pow (W, 0.371) / (2.358 * er + 1.0) + 1.0; + double Q3 = atan (0.084 * pow (W, 1.9413 / Q2)) * + 0.5274 / pow (ErEffFreq, 0.9236) + 1.0; + double Q4 = 0.0377 * (6.0 - 5.0 * exp (0.036 * (1.0 - er))) * + atan (0.067 * pow (W, 1.456)) + 1.0; + double Q5 = 1.0 - 0.218 * exp (-7.5 * W); + dl = Q1 * Q3 * Q5 / Q4; + } + /* Hammerstad */ + else if (Model == MSOPEN_HAMMERSTAD) { + dl = 0.102 * (W + 0.106) / (W + 0.264) * + (1.166 + (er + 1) / er * (0.9 + log (W + 2.475))); + } + return dl * h * sqrt (ErEffFreq) / C0 / ZlEffFreq; +} + + +void cm_msopen (ARGS) +{ + Complex_t ac_gain; + + /* how to get properties of this component, e.g. L, W */ + double W = PARAM(w); + int SModel = PARAM(model); + int DModel = PARAM(disp); + int Model = PARAM(msopen_model); + + /* how to get properties of the substrate, e.g. Er, H */ + double er = PARAM(er); + double h = PARAM(h); + double t = PARAM(t); + + + /* Compute the output */ + if(ANALYSIS == AC) { + if (Model == MSOPEN_ALEXOPOULOS) { + double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq; + mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff); + mslineAnalyseDispersion (WEff, h, er, ZlEff, ErEff, RAD_FREQ/(2*M_PI), DModel, + &ZlEffFreq, &ErEffFreq); + + if (fabs (er - 9.9) > 0.2) { + fprintf (stderr, "WARNING: Model for microstrip open end defined " + "for er = 9.9 (er = %g)\n", er); + } + + double c1, c2, l2, r2; + c1 = (1.125 * tanh (1.358 * W / h) - 0.315) * + h / 2.54e-5 / 25 / ZlEffFreq * 1e-12; + c2 = (6.832 * tanh (0.0109 * W / h) + 0.919) * + h / 2.54e-5 / 25 / ZlEffFreq * 1e-12; + l2 = (0.008285 * tanh (0.5665 * W / h) + 0.0103) * + h / 2.54e-5 / 25 * ZlEffFreq * 1e-9; + r2 = (1.024 * tanh (2.025 * W / h)) * ZlEffFreq; + double complex d1 = 0 + I*c1 * RAD_FREQ; + double complex d2 = r2 + I*(l2 * RAD_FREQ - 1.0 / c2 / RAD_FREQ); + double complex y = d1 + 1.0/d2; + + ac_gain.real = creal(y); + ac_gain.imag = cimag(y); + AC_GAIN(p1, p1) = ac_gain; + } else { + double Ce = calcCend(RAD_FREQ/(2*M_PI), W, h, t, er, SModel, DModel, Model); + ac_gain.real = 0.0; + ac_gain.imag = RAD_FREQ * Ce; + AC_GAIN(p1, p1) = ac_gain; + } + } +} + diff --git a/src/xspice/icm/tlines/msopen/ifspec.ifs b/src/xspice/icm/tlines/msopen/ifspec.ifs new file mode 100644 index 000000000..9f1773d4b --- /dev/null +++ b/src/xspice/icm/tlines/msopen/ifspec.ifs @@ -0,0 +1,140 @@ +/* =========================================================================== + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +NAME_TABLE: + +Spice_Model_Name: msopen +C_Function_Name: cm_msopen +Description: "Microstrip open end" + + +PORT_TABLE: + +Port_Name: p1 +Description: "terminals" +Direction: inout +Default_Type: gd +Allowed_Types: [gd] +Vector: no +Vector_Bounds: - +Null_Allowed: no + +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: msopen_model +Description: "MSOpen model" +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 + + + diff --git a/src/xspice/icm/tlines/tline/cfunc.mod b/src/xspice/icm/tlines/tline/cfunc.mod new file mode 100644 index 000000000..207a0ee58 --- /dev/null +++ b/src/xspice/icm/tlines/tline/cfunc.mod @@ -0,0 +1,124 @@ +/* =========================================================================== + FILE cfunc.mod + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#include +#include +#include + +#include "msline_common.h" +#include "tline_common.h" + +//static tline_state_t *sim_points = NULL; + +static void cm_tline_callback(ARGS, Mif_Callback_Reason_t reason); + +void cm_tline (ARGS) +{ + Complex_t z11, z21; + void **sim_points; + + + /* 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) { + CALLBACK = cm_tline_callback; + STATIC_VAR(sim_points_data) = NULL; + } + + /* 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) { + sim_points = &(STATIC_VAR(sim_points_data)); + double t = TIME; + double V1 = INPUT(V1sens); + double V2 = INPUT(V2sens); + double I1 = INPUT(in); + double I2 = INPUT(out); + double delay = l/(C0); + + tline_state_t *last = get_tline_last_state(*(tline_state_t **)sim_points); + double last_time = 0; + if (last != NULL) last_time = last->time; + + if (TIME < last_time) { + //fprintf(stderr,"Rollback time=%g\n",TIME); + delete_tline_last_state((tline_state_t **)sim_points); + } + + append_state((tline_state_t **)sim_points, t, V1, V2, I1, I2, 1.2*delay); + if (t > delay) { + tline_state_t *pp = get_state(*(tline_state_t **)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(); + } + } +} + + +static void cm_tline_callback(ARGS, Mif_Callback_Reason_t reason) +{ + switch (reason) { + case MIF_CB_DESTROY: + delete_tline_states((tline_state_t **)&(STATIC_VAR(sim_points_data))); + break; + default: break; + } +} diff --git a/src/xspice/icm/tlines/tline/ifspec.ifs b/src/xspice/icm/tlines/tline/ifspec.ifs new file mode 100644 index 000000000..5e45685b8 --- /dev/null +++ b/src/xspice/icm/tlines/tline/ifspec.ifs @@ -0,0 +1,100 @@ +/* =========================================================================== + FILE ifspec.ifs + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +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 + +STATIC_VAR_TABLE: + +Static_Var_Name: sim_points_data +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/icm/tlines/udnpath.lst b/src/xspice/icm/tlines/udnpath.lst new file mode 100644 index 000000000..e69de29bb diff --git a/src/xspice/tlines/msline_common.c b/src/xspice/tlines/msline_common.c new file mode 100644 index 000000000..bc52a9367 --- /dev/null +++ b/src/xspice/tlines/msline_common.c @@ -0,0 +1,357 @@ +/* + * msline_common.c - common definitions for microstrip devices + * + * Copyright (C) 2025 Vadim Kuznetsov + * Based on works by Stefan Jahn, Qucsator project + * + * This 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, or (at your option) + * any later version. + * + * This software 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. + * + * $Id$ + * + */ + +#include +#include + +#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; + } +} + diff --git a/src/xspice/tlines/msline_common.h b/src/xspice/tlines/msline_common.h new file mode 100644 index 000000000..55e8966ea --- /dev/null +++ b/src/xspice/tlines/msline_common.h @@ -0,0 +1,80 @@ +/* + * msline_common.h - common definitions for microstrip devices + * + * Copyright (C) 2025 Vadim Kuznetsov + * Based on works by Stefan Jahn, Qucsator project + * + * This 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, or (at your option) + * any later version. + * + * This software 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. + * + * $Id$ + * + */ + + +#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 diff --git a/src/xspice/tlines/tline_common.c b/src/xspice/tlines/tline_common.c new file mode 100644 index 000000000..90f652688 --- /dev/null +++ b/src/xspice/tlines/tline_common.c @@ -0,0 +1,185 @@ +/* tline_common.c + * common definitions for all transmission lines + */ + +/* =========================================================================== + FILE tline_common.c + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#include +#include + +#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; +} + +tline_state_t *get_tline_last_state(tline_state_t *first) +{ + tline_state_t *pp = first; + if (first == NULL) return NULL; + while (pp->next != NULL) { + pp = pp->next; + } + return pp; +} + + +void delete_tline_last_state(tline_state_t **first) +{ + tline_state_t *pn = *first; + if (*first == NULL) return; + + if ((*first)->next == NULL) { + free (*first); + *first = NULL; + return; + } + + while (pn->next->next != NULL) { + pn = pn->next; + } + free(pn->next); + pn->next = NULL; +} + +void delete_tline_states(tline_state_t **first) +{ + if (*first == NULL) return; + tline_state_t *pn; + tline_state_t *pc = *first; + while (pc != NULL) { + pn = pc->next; + free (pc); + pc = pn; + } + *first = NULL; +} + +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; +} + +cpline_state_t *get_cpline_last_state(cpline_state_t *first) +{ + cpline_state_t *pp = first; + if (first == NULL) return NULL; + while (pp->next != NULL) { + pp = pp->next; + } + return pp; +} + + +void delete_cpline_last_state(cpline_state_t **first) +{ + cpline_state_t *pn = *first; + if (*first == NULL) return; + + if ((*first)->next == NULL) { + free (*first); + *first = NULL; + return; + } + + while (pn->next->next != NULL) { + pn = pn->next; + } + free(pn->next); + pn->next = NULL; +} + +void delete_cpline_states(cpline_state_t **first) +{ + if (*first == NULL) return; + cpline_state_t *pn; + cpline_state_t *pc = *first; + while (pc != NULL) { + pn = pc->next; + free (pc); + pc = pn; + } + *first = NULL; +} + + diff --git a/src/xspice/tlines/tline_common.h b/src/xspice/tlines/tline_common.h new file mode 100644 index 000000000..8448d47bb --- /dev/null +++ b/src/xspice/tlines/tline_common.h @@ -0,0 +1,85 @@ +/* tline_common.h + * common definitions for all transmission lines + */ + +/* =========================================================================== + FILE tline_common.h + Copyright 2025 Vadim Kuznetsov + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + + +#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); + +void delete_tline_states(tline_state_t **first); +void delete_tline_last_state(tline_state_t **first); +tline_state_t *get_tline_last_state(tline_state_t *first); + +#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); + + +void delete_cpline_states(cpline_state_t **first); +void delete_cpline_last_state(cpline_state_t **first); +cpline_state_t *get_cpline_last_state(cpline_state_t *first); + +#endif