"""
MLine (:mod:`skrf.media.MLine`)
========================================
.. autosummary::
:toctree: generated/
MLine
"""
from __future__ import annotations
import warnings
from typing import TYPE_CHECKING
import numpy as np
from numpy import arctan, cosh, exp, imag, log, log10, ones, real, sqrt, tanh, zeros
from scipy.constants import c, epsilon_0, mu_0, pi
from ..constants import NumberLike
from ..tlineFunctions import skin_depth, surface_resistivity
from .media import Media
if TYPE_CHECKING:
from ..frequency import Frequency
[docs]
class MLine(Media):
r"""
A microstripline transmission line defined in terms of width, thickness
and height on a given relative permittivity substrate. The line has a
conductor resistivity and a tangential loss factor.
This class is highly inspired from the technical documentation [#]_
and sources provided by the qucs project [#]_ .
In addition, Djordjevic [#]_ /Svensson [#]_ wideband debye dielectric
model is considered to provide more realistic modelling of broadband
microstrip with as causal time domain response.
A compatibility mode is provided to mimic the behaviour of QUCS or of
Keysight ADS. There is known differences in the output of these
simulators.
The quasi-static models of chercteristic impedance and effective
permittivity give the value at zero frequency. The dispersion models
compute a frequency-dependant values of these variables.
* Quasi-static characteristic impedance and effective permittivity models:
+ Hammerstad and Jensen (default)
+ Schneider
+ Wheeler
* Frequency dispersion of impedance and effective permittivity models:
+ Hammerstad and Jensen
+ Kirschning and Jansen (default)
+ Kobayashi
+ Schneider
+ Yamashita
+ (No dispersion)
* Strip thickness correction model:
+ all quasi-static models add a certain amount to W to accound for
non-zero thickness of the strip. Computation with zero thickness is
possible.
Parameters
----------
frequency : :class:`~skrf.frequency.Frequency` object
frequency band of the media
z0_port : number, array-like, or None
`z0_port` is the port impedance for networks generated by the media.
If `z0_port` is not None, the networks generated by the media are
renormalized (or in other words embedded) from the characteristic
impedance z0 of the media to `z0_port`.
Else if `z0_port` is None, the networks port impedances will be the raw
characteristic impedance z0 of the media.
(Default is None)
z0_override : number, array-like, or None
`z0_override` override the characteristic impedance for the media.
If `z0_override` is not None, the networks generated by the media have
their characteristic impedance `z0` overrided by `z0_override`.
(Default is None)
z0 : number, array-like, or None
deprecated parameter, alias to `z0_override` if `z0_override` is None.
Emmit a deprecation warning.
w : number, or array-like
width of conductor, in m
h : number, or array-like
height of substrate between ground plane and conductor, in m
t : number, or array-like or None, optional
conductor thickness, in m. Default is None (no width correction
to account strip thickness).
ep_r : number, or array-like
relative permittivity of dielectric at frequency f_epr_tand, no unit
mu_r : number, array-like
relative permeability mof dielectric, no unit
model : str
microstripline quasi-static impedance and dielectric model in:
* 'hammerstadjensen' (default)
* 'schneider'
* 'wheeler'
disp : str
microstripline impedance and dielectric frequency dispersion model in:
* 'hammerstadjensen'
* 'kirschningjansen' (default)
* 'kobayashi'
* 'schneider'
* 'yamashita'
* 'none'
diel : str
dielectric frequency dispersion model in:
* 'djordjevicsvensson' (default)
* 'frequencyinvariant'
rho: number, or array-like, optional
resistivity of conductor, ohm / m
tand : number, or array-like
dielectric loss factor at frequency f_epr_tand
rough : number, or array-like
RMS roughness of conductor in m
f_low : number, or array-like
lower frequency for wideband Debye Djordjevic/Svensson dielectric
model, in Hz
f_high : number, or array-like
higher frequency for wideband Debye Djordjevic/Svensson dielectric
model, in Hz
f_epr_tand : number, or array-like
measurement frequency for ep_r and tand of dielectric, in Hz
compatibility_mode: str or None (default)
If set to 'qucs', following behavious happens :
* Characteristic impedance will be real (no imaginary part due to tand)
* Quasi-static relative permittivity and impedance will by used for
loss computation instead of frequency-dispersed values
* Kobayashi and Yamashita models will disperse permittivity but keep
quasi-static impedance values
\*args, \*\*kwargs : arguments, keyword arguments
passed to :class:`~skrf.media.media.Media`'s constructor
(:func:`~skrf.media.media.Media.__init__`
Note
----
In the case dispersion model only include effective permittivity, no
dispersion is used for impedance in QUCS mode and Kirschning Jansen is
used in ADS mode. QUCS mode is the default.
When the thickness of the strip is smaller than 3 skin depth, the losses
model gives over-optimistic results and the media will issue a warning.
At DC, the losses of the line could be smaller than its conductor
resistance, which is not physical.
References
----------
.. [#] http://qucs.sourceforge.net/docs/technical.pdf
.. [#] https://github.com/Qucs/qucsator/blob/develop/src/components/microstrip/msline.cpp
.. [#] E. Hammerstad and Ø. Jensen,
"Accurate Models for Microstrip Computer-Aided Design",
Symposium on Microwave Theory and Techniques, pp. 407-409, June 1980.
.. [#] M. Kirschning and R. H. Jansen,
"Accurate Model for Effective Dielectric Constant of Microstrip with
Validity up to Millimeter-Wave Frequencies", Electronics Letters,
vol. 8, no. 6, pp. 272-273, Mar. 1982.
.. [#] R. H. Jansen and M. Kirschning,
"Arguments and an accurate Model for the Power-Current Formulation of
Microstrip Characteristic Impedance",
Archiv für Elektronik und Übertragungstechnik (AEÜ), vol. 37,
pp. 108-112, 1983.
.. [#] M. Kobayashi,
"A Dispersion Formula Satisfying Recent Requirements in Microstrip
CAD", IEEE Trans. on Microwave Theory and Techniques, vol. 36, no. 8,
pp. 1246-1250, Aug. 1988.
.. [#] M. V. Schneider,
"Microstrip Lines for Microwave Integrated Circuits",
The Bell System Technical Journal, vol. 48, pp. 1421-1444, May 1969.
.. [#] M. V. Schneider, "Microstrip Dispersion", Proceedings of the IEEE,
Letters, vol. 60, Jan. 1972, pp. 144-146.
.. [#] H. A. Wheeler,
"Transmission-Line Properties of a Strip on a Dielectric Sheet on a
Plane, IEEE Trans. on Microwave Theory and Techniques, vol. 25, no. 8,
pp. 631-647, Aug. 1977.
.. [#] H. A. Wheeler, "Formulas for the Skin Effect,"
Proceedings of the IRE, vol. 30, no. 9, pp. 412-424, Sept. 1942.
.. [#] E. Yamashita, K. Atsuki, and T. Ueda,
"An Approximate Dispersion Formula of Microstrip Lines for Computer
Aided Design of Microwave Integrated Circuits", IEEE Trans. on
Microwave Theory and Techniques, vol. 27, pp. 1036-1038, Dec. 1979.
.. [#] C. Svensson, G.E. Dermer,
Time domain modeling of lossy interconnects,
IEEE Trans. on Advanced Packaging, May 2001, N2, Vol. 24, pp.191-196.
.. [#] Djordjevic, R.M. Biljic, V.D. Likar-Smiljanic, T.K. Sarkar,
Wideband frequency-domain characterization of FR-4 and time-domain
causality,
IEEE Trans. on EMC, vol. 43, N4, 2001, p. 662-667.
"""
[docs]
def __init__(self, frequency: Frequency | None = None,
z0_port: NumberLike | None = None,
z0_override: NumberLike | None = None,
z0: NumberLike | None = None,
w: NumberLike = 3, h: NumberLike = 1.6,
t: NumberLike | None = None,
ep_r: NumberLike = 4.5,
mu_r: NumberLike = 1.0,
model: str = 'hammerstadjensen',
disp: str = 'kirschningjansen',
diel: str = 'djordjevicsvensson',
rho: NumberLike = 1.68e-8, tand: NumberLike = 0,
rough: NumberLike = 0.15e-6,
f_low: NumberLike = 1e3, f_high: NumberLike = 1e12,
f_epr_tand: NumberLike = 1e9,
compatibility_mode: str | None = None,
*args, **kwargs):
Media.__init__(self, frequency = frequency,
z0_port = z0_port, z0_override = z0_override, z0 = z0)
self.w, self.h, self.t = w, h, t
self.ep_r, self.mu_r = ep_r, mu_r
self.model, self.disp, self.diel = model, disp, diel
self.rho, self.tand, self.rough, self.disp = rho, tand, rough, disp
self.f_low, self.f_high, self.f_epr_tand = f_low, f_high, f_epr_tand
self.compatibility_mode = compatibility_mode
# variation ofeffective permittivity with frequency
# Not implemented on QUCS but implemented on ADS.
# 'frequencyinvariant' will give a constant complex value whith a real
# part compatible with qucs and an imaginary part due to tand
self.ep_r_f, self.tand_f = self.analyse_dielectric(
self.ep_r, self.tand,
self.f_low, self.f_high, self.f_epr_tand, self.frequency.f,
self.diel)
# quasi-static effective permittivity of substrate + line and
# the impedance of the microstrip line
# qucs use real-valued ep_r giving real-valued impedance
if compatibility_mode == 'qucs':
self.zl_eff, self.ep_reff, self.w_eff = self.analyse_quasi_static(
real(self.ep_r_f), self.w, self.h, self.t, self.model)
# ads use complex permittivity giving complex impedance and
# effective permittivity
else:
self.zl_eff, self.ep_reff, self.w_eff = self.analyse_quasi_static(
self.ep_r_f, self.w, self.h, self.t, self.model)
# analyse dispersion of impedance and relatice permittivity
# qucs use w here, but w_eff seems better
if compatibility_mode == 'qucs':
self._z_characteristic, self.ep_reff_f = self.analyse_dispersion(
self.zl_eff, self.ep_reff, real(self.ep_r_f),
self.w, self.w_eff, self.h, self.t,
self.frequency.f, self.disp)
else:
self._z_characteristic, self.ep_reff_f = self.analyse_dispersion(
self.zl_eff, self.ep_reff, self.ep_r_f,
self.w_eff, self.w_eff, self.h, self.t,
self.frequency.f, self.disp)
# analyse losses of line
# qucs use quasi-static values here, leading to a difference
# against ads
if compatibility_mode == 'qucs':
self.alpha_conductor, self.alpha_dielectric = self.analyse_loss(
real(self.ep_r_f), real(self.ep_reff), self.tand_f,
self.rho, self.mu_r,
real(self.zl_eff), real(self.zl_eff),
self.frequency.f, self.w, self.t, self.rough)
else:
self.alpha_conductor, self.alpha_dielectric = self.analyse_loss(
real(self.ep_r_f), real(self.ep_reff_f), self.tand_f,
self.rho, self.mu_r,
real(self._z_characteristic), real(self._z_characteristic),
self.frequency.f, self.w, self.t, self.rough)
def __str__(self) -> str:
f=self.frequency
output = (
f'Microstripline Media. {f.f_scaled[0]}-{f.f_scaled[-1]} {f.unit}. {f.npoints} points'
f'\n W= {self.w:.2e}m, H= {self.h:.2e}m')
return output
def __repr__(self) -> str:
return self.__str__()
@property
def gamma(self):
"""
Propagation constant.
Returns
-------
gamma : :class:`numpy.ndarray`
"""
ep_reff, f = real(self.ep_reff_f), self.frequency.f
alpha = self.alpha_dielectric.copy()
if self.rho is not None:
alpha += self.alpha_conductor
beta = 2 * pi * f* sqrt(ep_reff) / c
return alpha + 1j*beta
@property
def z0_characteristic(self) -> np.ndarray:
"""
Characteristic Impedance, :math:`z_0`
Returns
-------
z0_characteristic : np.ndarray
Characteristic Impedance in units of ohms
"""
if self.z0_override is None:
return self._z_characteristic
else:
return self.z0_override
@property
def Z0_f(self) -> np.ndarray:
"""
Alias fos Characteristic Impedance for backward compatibility.
Deprecated, do not use.
Returns
-------
z0 : :class:`numpy.ndarray`
"""
warnings.warn(
"`Z0_f` is deprecated, use `Z0` instead",
DeprecationWarning, stacklevel = 2
)
return self._z_characteristic
[docs]
def analyse_dielectric(self, ep_r: NumberLike, tand: NumberLike,
f_low: NumberLike, f_high: NumberLike,
f_epr_tand: NumberLike, f: NumberLike,
diel: str):
"""
This function calculate the frequency dependent relative permittivity
of dielectric and and tangeantial loss factor.
References
----------
.. [#] C. Svensson, G.E. Dermer,
Time domain modeling of lossy interconnects,
IEEE Trans. on Advanced Packaging, May 2001, N2, Vol. 24, pp.191-196.
.. [#] Djordjevic, R.M. Biljic, V.D. Likar-Smiljanic, T.K. Sarkar,
Wideband frequency-domain characterization of FR-4 and time-domain
causality,
IEEE Trans. on EMC, vol. 43, N4, 2001, p. 662-667.
Returns
-------
ep_r_f : :class:`numpy.ndarray`
tand_f : :class:`numpy.ndarray`
"""
if diel == 'djordjevicsvensson':
# compute the slope for a log frequency scale, tanD dependent.
k = log((f_high + 1j * f_epr_tand) / (f_low + 1j * f_epr_tand))
fd = log((f_high + 1j * f) / (f_low + 1j * f))
ep_d = -tand * ep_r / imag(k)
# value for frequency above f_high
ep_inf = ep_r * (1. + tand * real(k) / imag(k))
# compute complex permitivity
ep_r_f = ep_inf + ep_d * fd
# get tand
tand_f = -imag(ep_r_f) / real(ep_r_f)
elif diel == 'frequencyinvariant':
ep_r_f = ep_r - 1j * ep_r * tand
tand_f = tand
else:
raise ValueError('Unknown dielectric dispersion model')
return ep_r_f, tand_f
[docs]
def analyse_quasi_static(self, ep_r: NumberLike,
w: NumberLike, h: NumberLike, t: NumberLike,
model: str):
"""
This function calculates the quasi-static impedance of a microstrip
line, the value of the effective permittivity as per filling factor
and the effective width due to the finite conductor thickness for the
given microstrip line and substrate properties.
References
----------
.. [#] E. Hammerstad and Ø. Jensen,
"Accurate Models for Microstrip Computer-Aided Design", Symposium
on Microwave Theory and Techniques, pp. 407-409, June 1980.
.. [#] H. A. Wheeler,
"Transmission-Line Properties of a Strip on a Dielectric Sheet on a
Plane, IEEE Trans. on Microwave Theory and Techniques, vol. 25,
no. 8, pp. 631-647, Aug. 1977.
.. [#] M. V. Schneider,
"Microstrip Lines for Microwave Integrated Circuits",
The Bell System Technical Journal, vol. 48, pp. 1421-1444, May 1969.
Returns
-------
zl_eff : :class:`numpy.ndarray`
ep_reff : :class:`numpy.ndarray`
"""
Z0 = sqrt(mu_0 / epsilon_0)
zl_eff = Z0
ep_reff = ep_r
w_eff = w
if model == 'wheeler':
# compute strip thickness effect
dw1 = 0
if t is not None and t > 0:
dw1 = t / pi * log(4. * exp(1.) / sqrt((t / h)**2) + \
(1. / pi / (w / t + 1.1))**2)
dwr = (1. + 1. / ep_r) / 2. * dw1
wr = w + dwr
w_eff = wr
# compute characteristic impedance
if (w / h) < 3.3:
cp = log(4. * h / wr + sqrt((4 * h / wr)**2 + 2))
b = (ep_r - 1.) / (ep_r + 1.) / \
2 * (log(pi / 2.) + log(4. / pi) / ep_r)
zl_eff = (cp - b) * Z0 / pi / sqrt(2 * (ep_r + 1.))
else:
cp = 1 + log(pi / 2.) + log(wr / h / 2. + 0.94)
d = 1. / pi / 2. * (1. + log(pi**2 / 16.)) * (ep_r - 1.) \
/ ep_r**2
x = 2. * log(2.) / pi + wr / h / 2. + (ep_r + 1.) / 2 / pi / \
ep_r * cp + d
zl_eff = Z0 / 2 / x / sqrt(ep_r)
# compute effective dielectric constant
if (w / h) < 1.3:
a = log(8 * h / wr) + (wr / h)**2 / 32
b = (ep_r - 1.) / (ep_r + 1.) / \
2 * (log(pi / 2.) + log(4. / pi) / ep_r)
ep_reff = (ep_r + 1.) / 2. * (a / (a - b))**2
else:
# qucsator is 4.0137 but doc 0.94 * 2 = 1.88
d = (ep_r - 1.) / 2. / pi / ep_r * \
(log(2.1349 * wr / h + 4.0137) - 0.5169 / ep_r)
e = wr / h / 2 + 1. / pi * log(8.5397 * wr / h + 16.0547)
ep_reff = ep_r * ((e - d) / e)**2
elif model == 'schneider':
u = w / h
dw = 0
# consider strip thickness equations
if t is not None and t > 0:
if t < (w / 2):
if u < (1. / pi / 2):
arg = 2 * pi * w / t
else:
arg = h / t
dw = t / pi * (1. + log(2 * arg))
if (t / dw) >= 0.75:
dw = 0
w_eff = w + dw
u = w_eff / h
# effective dielectric constant
ep_reff = (ep_r + 1.) / 2. + (ep_r - 1.) / 2. / sqrt (1. + 10. / u)
# characteristic impedance
if u < 1.:
z = 1. / pi / 2. * log(8. / u + u / 4)
else:
z = 1. / (u + 2.42 - 0.44 / u + (1. - 1. / u)**6)
zl_eff = Z0 * z / sqrt(ep_reff)
elif model == 'hammerstadjensen':
u = w / h
if t is not None:
t = t/h
du1 = 0.
# compute strip thickness effect
if t is not None and t > 0:
# Qucs formula 11.22 is wrong, normalized w has to be used instead (see Hammerstad and Jensen Article)
# Normalized w is named u and is actually used in qucsator source code
# coth(alpha) = 1/tanh(alpha)
du1 = t / pi * log(1. + 4. * exp(1.) / t * tanh(sqrt(6.517 * u))**2)
# sech(alpha) = 1/cosh(alpha)
dur = du1 * (1. + 1. / cosh(sqrt(ep_r - 1.))) / 2.
u1 = u + du1
ur = u + dur
w_eff = ur * h
# compute impedances for homogeneous medium
zr = hammerstad_zl(ur)
z1 = hammerstad_zl(u1)
# compute effective dielectric constant
a, b = hammerstad_ab(ur, ep_r)
e = hammerstad_er(ur, ep_r, a, b)
# compute final characteristic impedance and dielectric constant
#including strip thickness effects
zl_eff = zr / sqrt(e)
ep_reff = e * (z1 / zr)**2
else:
raise ValueError('Unknown microstripline quasi-static model')
return zl_eff, ep_reff, w_eff
[docs]
def analyse_dispersion(self, zl_eff: NumberLike, ep_reff: NumberLike,
ep_r: NumberLike, wr: NumberLike, w_eff: NumberLike,
h: NumberLike, t: NumberLike, f: NumberLike,
disp: str):
"""
This function compute the frequency dependent characteristic
impedance and effective permittivity accounting for microstripline
frequency dispersion.
References
----------
.. [#] M. Kobayashi,
"A Dispersion Formula Satisfying Recent Requirements in Microstrip
CAD", IEEE Trans. on Microwave Theory and Techniques, vol. 36,
no. 8, pp. 1246-1250, Aug. 1988.
.. [#] M. V. Schneider, "Microstrip Dispersion", Proceedings of the
IEEE, Letters, vol. 60, Jan. 1972, pp. 144-146.
.. [#] M. Kirschning and R. H. Jansen,
"Accurate Model for Effective Dielectric Constant of Microstrip
with Validity up to Millimeter-Wave Frequencies", Electronics
Letters, vol. 8, no. 6, pp. 272-273, Mar. 1982.
.. [#] R. H. Jansen and M. Kirschning,
"Arguments and an accurate Model for the Power-Current Formulation of
Microstrip Characteristic Impedance",
Archiv für Elektronik und Übertragungstechnik (AEÜ), vol. 37,
pp. 108-112, 1983.
.. [#] E. Yamashita, K. Atsuki, and T. Ueda,
"An Approximate Dispersion Formula of Microstrip Lines for
Computer Aided Design of Microwave Integrated Circuits",
IEEE Trans. on Microwave Theory and Techniques, vol. 27,
pp. 1036-1038, Dec. 1979.
Returns
-------
z : :class:`numpy.ndarray`
e : :class:`numpy.ndarray`
"""
u = wr/h
if disp == 'schneider':
k = sqrt(ep_reff / ep_r)
fn = 4. * h * f / c * sqrt(ep_r - 1.)
fn2 = fn**2
e = ep_reff * ((1. + fn2) / (1. + k * fn2))**2
z = zl_eff * sqrt(ep_reff / e)
elif disp == 'hammerstadjensen':
Z0 = sqrt(mu_0 / epsilon_0)
g = pi**2 / 12 * (ep_r - 1) / ep_reff * sqrt(2 * pi * zl_eff / Z0)
fp = (2 * mu_0 * h * f) / zl_eff
e = ep_r - (ep_r - ep_reff) / (1 + g * fp**2)
z = zl_eff * sqrt(ep_reff / e) * (e - 1) / (ep_reff - 1)
elif disp == 'kirschningjansen':
fn = f * h * 1e-6
e = kirsching_er(u, fn, ep_r, ep_reff)
z, _ = kirsching_zl(u, fn, ep_r, ep_reff, e, zl_eff)
elif disp == 'yamashita':
k = sqrt(ep_r / ep_reff)
fp = 4 * h * f / c * sqrt(ep_r - 1) * \
(0.5 + (1 + 2 * log10(1 + u))**2)
e = ep_reff * ((1 + k * fp**1.5 / 4) / (1 + fp**1.5 / 4))**2
# qucs keep quasi-static impedance here
if self.compatibility_mode == 'qucs':
z = np.ones(f.shape) * zl_eff
# use Kirschning Jansen for impedance dispersion by default
else:
fn = f * h * 1e-6
z, _ = kirsching_zl(wr / h, fn, ep_r, ep_reff, e, zl_eff)
elif disp == 'kobayashi':
fk = c * arctan(ep_r * sqrt((ep_reff - 1) / (ep_r - ep_reff)))/ \
(2 * pi * h * sqrt(ep_r - ep_reff))
fh = fk / (0.75 + (0.75 - 0.332 / (ep_r**1.73)) * u)
no = 1 + 1 / (1 + sqrt(u)) + 0.32 * (1 / (1 + sqrt(u)))**3
nc = np.where(u < 0.7,
1 + 1.4 / (1 + u) * (0.15 - 0.235 * exp(-0.45 * f / fh)),
1)
n = np.where(no * nc < 2.32, no * nc, 2.32)
e = ep_r - (ep_r - ep_reff) / (1 + (f / fh)**n)
# qucs keep quasi-static impedance here
if self.compatibility_mode == 'qucs':
z = np.ones(f.shape) * zl_eff
# use Kirschning Jansen for impedance dispersion by default
else:
fn = f * h * 1e-6
z, _ = kirsching_zl(wr / h, fn, ep_r, ep_reff, e, zl_eff)
elif disp == 'none':
e = ones(f.shape) * ep_reff
z = ones(f.shape) * zl_eff
else:
raise ValueError('Unknown microstripline dispersion model')
return z, e
[docs]
def analyse_loss(self, ep_r: NumberLike, ep_reff: NumberLike,
tand: NumberLike, rho: NumberLike, mu_r: NumberLike,
zl_eff_f1: NumberLike, zl_eff_f2: NumberLike,
f: NumberLike, w: NumberLike, t: NumberLike,
D: NumberLike):
"""
The function calculates the conductor and dielectric losses of a
single microstrip line using wheeler's incremental inductance rule.
References
----------
.. [#] H. A. Wheeler, "Formulas for the Skin Effect,"
Proceedings of the IRE, vol. 30, no. 9, pp. 412-424, Sept. 1942.
Returns
-------
a_conductor : :class:`numpy.ndarray`
a_dielectric : :class:`numpy.ndarray`
"""
# limited to only Hammerstad and Jensen model
Z0 = np.sqrt(mu_0/epsilon_0)
# conductor losses
if t is not None and t > 0:
if rho is None:
raise(AttributeError('must provide resistivity rho. '
'see initializer help'))
else:
Rs = surface_resistivity(f=f, rho=rho, mu_r=1)
ds = skin_depth(f, rho, mu_r)
if(np.any(t < 3 * ds)):
warnings.warn(
'Conductor loss calculation invalid for line'
f'height t ({t}) < 3 * skin depth ({ds[0]})',
RuntimeWarning, stacklevel=2
)
# current distribution factor
Ki = exp(-1.2 * ((zl_eff_f1 + zl_eff_f2) / 2 / Z0)**0.7)
# D is RMS surface roughness
Kr = 1 + 2 / pi * arctan(1.4 * (D/ds)**2)
a_conductor = Rs / (zl_eff_f1 * w) * Ki * Kr
else:
a_conductor = zeros(f.shape)
# dielectric losses
l0 = c / f
a_dielectric = pi * ep_r / (ep_r - 1) * (ep_reff - 1) / \
sqrt(ep_reff) * tand / l0
return a_conductor, a_dielectric
def hammerstad_ab(u: NumberLike, ep_r: NumberLike) -> NumberLike:
"""
Hammerstad parameters for relative permittivity dispersion.
"""
a = 1. + log((u**4 + (u / 52.)**2) / (u**4 + 0.432)) / 49. \
+ log(1 + (u / 18.1)**3) / 18.7
b = 0.564 * ((ep_r - 0.9) / (ep_r + 3.))**0.053
return a, b
def hammerstad_zl(u: NumberLike) -> NumberLike:
"""
Hammerstad quasi-static impedance.
"""
fu = 6 + (2 * pi - 6) * exp(-(30.666 / u)**0.7528)
Z0 = sqrt(mu_0/epsilon_0)
return Z0 / 2. / pi * log(fu / u + sqrt(1. + (2. / u)**2))
def hammerstad_er(u: NumberLike, ep_r: NumberLike, a: NumberLike,
b: NumberLike) -> NumberLike:
"""
Hammerstad quasi-static relative permittivity.
"""
return (ep_r + 1) / 2 + (ep_r - 1) / 2 * (1. + 10. / u)**(-a * b)
def kirsching_zl(u: NumberLike, fn: NumberLike,
ep_r: NumberLike, ep_reff: NumberLike, ep_reff_f: NumberLike,
zl_eff: NumberLike):
"""
Kirschning Jansen impedance dispersion.
"""
#fn = f * h * 1e-6 # GHz-mm
R1 = np.minimum(0.03891 * ep_r**1.4, 20.)
R2 = np.minimum(0.2671 * u**7, 20.)
R3 = 4.766 * exp(-3.228 * u**0.641)
R4 = 0.016 + (0.0514 * ep_r)**4.524
R5 = (fn / 28.843)**12
R6 = np.minimum(22.20 * u **1.92, 20.)
R7 = 1.206 - 0.3144 * exp(-R1) * (1 - exp(-R2))
R8 = 1 + 1.275 * (1 - exp(-0.004625 * R3 * ep_r**1.674 \
* (fn / 18.365)**2.745))
R9 = 5.086 * R4 * R5/(0.3838 + 0.386 * R4) \
* exp(-R6) / (1 + 1.2992 * R5) \
* (ep_r - 1)**6 / (1 + 10 * (ep_r - 1)**6)
R10 = 0.00044 * ep_r**2.136 + 0.0184
R11 = (fn / 19.47)**6 / (1 + 0.0962 * (fn / 19.47)**6)
R12 = 1 / (1 + 0.00245 * u**2)
R13 = 0.9408 * ep_reff_f**R8 - 0.9603
R14 = (0.9408 - R9) * ep_reff**R8 - 0.9603
R15 = 0.707 * R10 * (fn / 12.3)**1.097
R16 = 1 + 0.0503 * ep_r**2 * R11 * (1 - exp(-(u / 15)**6))
R17 = R7 * (1 - 1.1241 * R12 / R16 \
*exp(-0.026 * fn**1.15656 - R15))
return zl_eff * (R13 / R14)**R17, R17
def kirsching_er(u: NumberLike, fn: NumberLike,
ep_r: NumberLike, ep_reff: NumberLike):
"""
Kirschning Jansen relative permittivity dispersion.
"""
# in the paper fn is in GHz-cm while in Qucs it is GHz-mm, thus a factor
# 10 for all constant that multiply or divide fn
P1 = 0.27488 + (0.6315 + 0.525 / ( 1+ 0.0157 * fn)**20) * u \
-0.065683 * exp(-8.7513 * u)
P2 = 0.33622 * (1 -exp(-0.03442 * ep_r))
P3 = 0.0363 * exp(-4.6 * u) * (1 - exp(-(fn / 38.7)**4.97))
P4 = 1 + 2.751 * (1 - exp(-(ep_r / 15.916)**8))
Pf = P1 * P2 * ((0.1844 + P3 * P4) * fn)**1.5763
return ep_r - (ep_r - ep_reff) / (1 + Pf)