Source code for skrf.media.circularWaveguide

"""
circularWaveguide (:mod:`skrf.media.circularWaveguide`)
================================================================

.. autosummary::
   :toctree: generated/

   CircularWaveguide

"""
from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np
import scipy
from numpy import pi, sqrt, where

from .. import constants as _const
from ..data import materials
from .freespace import Freespace
from .media import Media

if TYPE_CHECKING:
    from ..constants import NumberLike
    from ..frequency import Frequency


[docs] class CircularWaveguide(Media): r""" A single mode of a homogeneously filled Circular Waveguide Represents a single mode of a homogeneously filled circular waveguide of cross-section `r^2 pi`. The mode is determined by `mode-type` (`'te'` or `'tm'`) and mode indices ( `m` and `n` ). Corrugated circular waveguides, which also support HE modes, are not supported. ==================================== ============= =============== Quantity Symbol Variable ==================================== ============= =============== Characteristic Wave Number :math:`k_0` :attr:`k0` Cut-off Wave Number :math:`k_c` :attr:`kc` Longitudinal Wave Number :math:`k_z` :attr:`gamma` Transverse Wave Number (a) :math:`k_x` :attr:`kx` Transverse Wave Number (b) :math:`k_y` :attr:`ky` Characteristic Impedance :math:`z_0` :attr:`z0` ==================================== ============= =============== Parameters ---------- frequency : :class:`~skrf.frequency.Frequency` object frequency band of this transmission line medium 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` overridden by `z0_override`. (Default is None) z0 : number, array-like, or None deprecated parameter, alias to `z0_override` if `z0_override` is None. Emit a deprecation warning. r : number radius of the waveguide, in meters. mode_type : ['te','tm'] mode type, transverse electric (te) or transverse magnetic (tm) to-z. where z is direction of propagation m : int mode index in 'phi'-direction, the azimuthal index n : int mode index in 'r'-direction, the radial index ep_r : number, array-like, filling material's relative permittivity mu_r : number, array-like filling material's relative permeability rho : number, array-like, string resistivity (ohm-m) of the conductor walls. If array-like must be same length as frequency. if str, it must be a key in `skrf.data.materials`. \*args, \*\*kwargs : arguments, keyword arguments passed to :class:`~skrf.media.media.Media`'s constructor (:func:`~skrf.media.media.Media.__init__` Examples -------- In the following example an ideal waveguide of 2.39 mm diameter is constructed for the high W band, operated in the fundamental TE11 mode. If no conductivity is provided the walls are treated as perfect electric conductors. >>> freq = rf.Frequency(88, 110, 101, 'ghz') >>> rf.CircularWaveguide(freq, r=0.5 * 2.39e-3) """
[docs] def __init__(self, frequency: Frequency | None = None, z0_port: NumberLike | None = None, z0_override: NumberLike | None = None, z0: NumberLike | None = None, r: NumberLike = 1, mode_type: str = 'te', m: int = 1, n: int = 1, ep_r: NumberLike = 1, mu_r: NumberLike = 1, rho: NumberLike | str | None = None, *args, **kwargs): Media.__init__(self, frequency = frequency, z0_port = z0_port, z0_override = z0_override, z0 = z0) if mode_type.lower() not in ['te','tm']: raise ValueError('mode_type must be either \'te\' or \'tm\'') self.r = r self.mode_type = mode_type.lower() self.m = m self.n = n self.ep_r = ep_r self.mu_r = mu_r self.rho = rho
def __str__(self) -> str: f=self.frequency output = \ 'Circular Waveguide Media. %i-%i %s. %i points'%\ (f.f_scaled[0], f.f_scaled[-1], f.unit, f.npoints) + \ f'\n r= {self.r:.2e}m' return output def __repr__(self) -> str: return self.__str__()
[docs] @classmethod def from_z0(cls, frequency: Frequency, z0: NumberLike, f: NumberLike, ep_r: NumberLike = 1, mu_r: NumberLike = 1, **kwargs): r""" Initialize from specified impedance at a given frequency, assuming the fundamental TE11 mode. Parameters ---------- frequency : Frequency Object z0 : number /array characteristic impedance to create at `f` f : number frequency (in Hz) at which the resultant waveguide has the characteristic impedance Z0 ep_r : number, array-like, filling material's relative permittivity mu_r : number, array-like filling material's relative permeability \*\*kwargs : arguments, keyword arguments passed to :class:`~skrf.media.media.Media`'s constructor (:func:`~skrf.media.media.Media.__init__` """ mu = _const.mu_0*mu_r ep = _const.epsilon_0*ep_r w = 2*pi*f # if self.mode_type =="te": u = scipy.special.jnp_zeros(1, 1)[-1] r =u/(w*mu) * 1./sqrt(1/(z0*1j)**2+ep/mu) kwargs.update(dict(frequency=frequency, r=r, m=1, n=1, ep_r=ep_r, mu_r=mu_r)) return cls(**kwargs)
@property def ep(self) -> NumberLike: """ The permativity of the filling material. Returns ------- ep : number filling material's relative permittivity """ return self.ep_r * _const.epsilon_0 @property def mu(self) -> NumberLike: """ The permeability of the filling material. Returns ------- mu : number filling material's relative permeability """ return self.mu_r * _const.mu_0 @property def k0(self) -> NumberLike: r""" Characteristic wave number. .. math:: k_0 = \omega \sqrt{\varepsilon \mu} Returns ------- k0 : number characteristic wave number """ return 2*pi*self.frequency.f*sqrt(self.ep * self.mu) @property def kc(self) -> NumberLike: r""" Cut-off wave number. Defined as .. math:: k_c = \frac{u_{mn}}{R} where R is the radius of the waveguide, and u_mn is: * the n-th root of the m-th Bessel function for 'tm' mode * the n-th root of the Derivative of the m-th Bessel function for 'te' mode. Returns ------- kc : number cut-off wavenumber """ if self.mode_type =="te": u = scipy.special.jnp_zeros(self.m, self.n)[-1] elif self.mode_type =="tm": u = scipy.special.jn_zeros(self.m,self.n)[-1] return u/self.r @property def f_cutoff(self) -> NumberLike: r""" cutoff frequency for this mode .. math:: f_c = \frac{v}{2 \pi} \frac{u_{mn}}{R} where R is the radius of the waveguide, and u_mn is: * the n-th root of the m-th Bessel function for 'tm' mode * the n-th root of the Derivative of the m-th Bessel function for 'te' mode. and v= 1/sqrt(ep*mu) is the bulk velocity inside the filling material. """ v = 1/sqrt(self.ep*self.mu) return v* self.kc/(2*np.pi) @property def f_norm(self) -> NumberLike: """ frequency vector normalized to cutoff """ return self.frequency.f/self.f_cutoff @property def rho(self) -> NumberLike: """ conductivity of sidewalls in ohm*m Parameters -------------- val : float, array-like or str the conductivity in ohm*m. If array-like must be same length as self.frequency. if str, it must be a key in `skrf.data.materials`. Examples --------- >>> wg.rho = 2.8e-8 >>> wg.rho = 2.8e-8 * ones(len(wg.frequency)) >>> wg.rho = 'al' >>> wg.rho = 'aluminum' """ # if self.roughness != None: # delta = skin_depth(self.frequency.f, self._rho, self.mu_r) # k_w = 1. +exp(-(delta/(2*self.roughness))**1.6) # return self._rho*k_w**2 return self._rho @rho.setter def rho(self, val): if isinstance(val, str): self._rho = materials[val.lower()]['resistivity(ohm*m)'] else: self._rho=val @property def lambda_guide(self) -> NumberLike: r""" Guide wavelength. .. math:: \lambda_g = 2\pi/\beta the distance in which the phase of the field increases by 2 pi. """ return 2*pi/self.beta @property def lambda_cutoff(self) -> NumberLike: r""" Cutoff wavelength. .. math:: \lambda_c = v/f_c where v= 1/sqrt(ep*mu) """ v = 1/sqrt(self.ep*self.mu) return v/self.f_cutoff @property def gamma(self) -> NumberLike: r""" The propagation constant (aka Longitudinal wave number) Defined as .. math:: k_z = \pm j \sqrt {k_0^2 - k_c^2} This is: * IMAGINARY for propagating modes * REAL for non-propagating modes, Returns ------- gamma : number The propagation constant """ # This also holds for the circular waveguide ## haringtons form if False: #self.m==1 and self.n==0: fs = Freespace(frequency=self.frequency, ep_r=self.ep_r, mu_r=self.mu_r) g= where(self.f_norm>1., sqrt(1-self.f_norm**(-2))*fs.gamma, # cutton -1j*sqrt(1-self.f_norm**(2))*fs.gamma)# cutoff else: # TODO: fix this for lossy ep/mu (remove abs?) k0,kc = self.k0, self.kc g= 1j*sqrt(abs(k0**2 - kc**2)) * (k0>kc) +\ sqrt(abs(kc**2- k0**2))*(k0<kc) + \ 0*(kc==k0) g = g + self.alpha_c *(self.rho is not None) return g @property def alpha_c(self) -> NumberLike: """ Loss due to finite conductivity of the sidewalls. Effects due to surface roughness are not implemented. In units of Np/m See property `rho` for setting conductivity. Effects of finite conductivity are taken from [#]. References ---------- .. [#] Eq. (9-34a) and Eq. (9-34b), Chapter 9.2.3, Advanced Engineering Electromagnetics, Balanis Constantine A., 2024 See Also -------- rho """ if self.rho is None: return 0 r, w, m, n, rho, f_n, mu = self.r, self.frequency.w, self.m, self.n, \ self.rho, self.f_norm, self.mu Rs = np.sqrt(w * mu * rho / 2) z0 = np.sqrt(_const.mu_0 / _const.epsilon_0) if (self.mode_type == "tm"): return Rs / r / z0 / np.sqrt(1 - (1 / f_n)**2) elif (self.mode_type == "te"): Jp = scipy.special.jnp_zeros(m, n)[-1] return Rs / r / z0 / np.sqrt(1 - (1 / f_n)**2) * ((1 / f_n)**2 + m**2 / (Jp**2 - m**2)) else: raise NotImplementedError @property def z0_characteristic(self) -> NumberLike: """ The characteristic impedance, :math:`z_0`. Returns ------- z0_characteristic : np.ndarray Characteristic Impedance in units of ohms """ omega = self.frequency.w impedance_dict = {'te': 1j*omega*self.mu/(self.gamma), 'tm': -1j*self.gamma/(omega*self.ep),\ } return impedance_dict[self.mode_type]