|
| 1 | +######################################################################################### |
| 2 | +## |
| 3 | +## RF Network Block |
| 4 | +## |
| 5 | +######################################################################################### |
| 6 | + |
| 7 | +# IMPORTS =============================================================================== |
| 8 | + |
| 9 | +from __future__ import annotations |
| 10 | + |
| 11 | +import numpy as np |
| 12 | + |
| 13 | +from inspect import signature |
| 14 | +from pathlib import Path |
| 15 | + |
| 16 | +import skrf as rf |
| 17 | + |
| 18 | +from pathsim.blocks.lti import StateSpace |
| 19 | + |
| 20 | +# BLOCKS ================================================================================ |
| 21 | + |
| 22 | +class RFNetwork(StateSpace): |
| 23 | + """N-port RF network linear time invariant (LTI) MIMO state-space model. |
| 24 | +
|
| 25 | + Uses Vector Fitting for rational approximation of the frequency response |
| 26 | + using poles and residues. The resulting approximation has guaranteed stable |
| 27 | + poles that are real or come in complex conjugate pairs. |
| 28 | +
|
| 29 | + Assumes N inputs and N outputs, where N is the number of ports of the |
| 30 | + RF network. |
| 31 | +
|
| 32 | + Parameters |
| 33 | + ---------- |
| 34 | + ntwk : :py:class:`~skrf.network.Network`, str, or Path |
| 35 | + scikit-rf RF Network object, or file to load information from. |
| 36 | + Supported formats are touchstone file V1 (.s?p) or V2 (.ts). |
| 37 | + auto_fit : bool |
| 38 | + If True (default), use ``skrf.VectorFitting.auto_fit`` for automatic |
| 39 | + pole selection. If False, use ``skrf.VectorFitting.vector_fit``. |
| 40 | + **kwargs |
| 41 | + Additional keyword arguments forwarded to the vector fitting function. |
| 42 | +
|
| 43 | + References |
| 44 | + ---------- |
| 45 | + .. [skrf] scikit-rf webpage https://scikit-rf.org/ |
| 46 | + """ |
| 47 | + |
| 48 | + def __init__(self, ntwk: rf.Network | str | Path, auto_fit: bool = True, **kwargs): |
| 49 | + |
| 50 | + if isinstance(ntwk, (Path, str)): |
| 51 | + ntwk = rf.Network(ntwk) |
| 52 | + |
| 53 | + # select the vector fitting function from scikit-rf |
| 54 | + vf_fun_name = "auto_fit" if auto_fit else "vector_fit" |
| 55 | + vf_fun = getattr(rf.VectorFitting, vf_fun_name) |
| 56 | + |
| 57 | + # filter kwargs for the selected vf function |
| 58 | + vf_fun_keys = signature(vf_fun).parameters |
| 59 | + vf_kwargs = {k: v for k, v in kwargs.items() if k in vf_fun_keys} |
| 60 | + |
| 61 | + # apply vector fitting |
| 62 | + vf = rf.VectorFitting(ntwk) |
| 63 | + getattr(vf, vf_fun_name)(**vf_kwargs) |
| 64 | + A, B, C, D, _ = vf._get_ABCDE() |
| 65 | + |
| 66 | + # keep a copy of the network and VF |
| 67 | + self.network = ntwk |
| 68 | + self.vf = vf |
| 69 | + |
| 70 | + super().__init__(A, B, C, D) |
| 71 | + |
| 72 | + def s(self, freqs: np.ndarray) -> np.ndarray: |
| 73 | + """S-matrix of the vector fitted N-port model from its state-space representation. |
| 74 | +
|
| 75 | + Parameters |
| 76 | + ---------- |
| 77 | + freqs : :py:class:`~numpy.ndarray` |
| 78 | + Frequencies (in Hz) at which to calculate the S-matrices. |
| 79 | +
|
| 80 | + Returns |
| 81 | + ------- |
| 82 | + s : :py:class:`~numpy.ndarray` |
| 83 | + Complex-valued S-matrices (fxNxN) calculated at frequencies ``freqs``. |
| 84 | + """ |
| 85 | + return rf.VectorFitting._get_s_from_ABCDE( |
| 86 | + freqs, self.A, self.B, self.C, self.D, 0 |
| 87 | + ) |
0 commit comments