Merge /u/ra3xdh/ngspice/ branch xspice_tlines_rebased into pre-master-45

https://sourceforge.net/p/ngspice/ngspice/merge-requests/33/
This commit is contained in:
b'Holger Vogt 2025-07-13 13:49:28 +00:00
commit 18f6efe2f6
23 changed files with 2830 additions and 4 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)/$(<D) -o $@ -c $<
$(COMPILE) $(gen_pp) -I$(srcdir)/$(<D) -I$(srcdir)/../tlines -o $@ -c $<
$(do-deps)
$(cm)/%/ifspec.o : $(cm)/%/ifspec.c
$(COMPILE) $(gen_pp) -I$(srcdir)/$(<D) -o $@ -c $<
$(COMPILE) $(gen_pp) -I$(srcdir)/$(<D) -I$(srcdir)/../tlines -o $@ -c $<
$(do-deps)
$(cm)/%/udnfunc.o : $(srcdir)/$(cm)/%/udnfunc.c

View File

@ -0,0 +1,188 @@
/* ===========================================================================
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 <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;
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;
}
}

View File

@ -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

View File

@ -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 <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 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;
}
}

View File

@ -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

View File

@ -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 <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 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;
}
}

View File

@ -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

View File

@ -0,0 +1,5 @@
mlin
tline
cpline
cpmlin
msopen

View File

@ -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 <math.h>
#include <complex.h>
#include <stdio.h>
#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;
}
}
}

View File

@ -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

View File

@ -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 <stdio.h>
#include <math.h>
#include <complex.h>
#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;
}
}

View File

@ -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

View File

View File

@ -0,0 +1,357 @@
/*
* msline_common.c - common definitions for microstrip devices
*
* Copyright (C) 2025 Vadim Kuznetsov <ra3xdh@gmail.com>
* 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 <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;
}
}

View File

@ -0,0 +1,80 @@
/*
* msline_common.h - common definitions for microstrip devices
*
* Copyright (C) 2025 Vadim Kuznetsov <ra3xdh@gmail.com>
* 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

View File

@ -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 <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;
}
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;
}

View File

@ -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