RF Network - One Port

Simulation of a Radio Frequency (RF) network using scikit-rf for state-space conversion.

You can also find a similar example in the GitHub repository.

This is an example of a simulation of a Radio Frequency (RF) network with PathSim.

You can also find a similar example in the GitHub repository.

In this example, we are using the block RFNetwork provided in PathSim to create the state-space model of an N-port RF network. This block uses the scikit-rf package to convert the frequency domain data into a state-space model. This conversion is performed using a Vector Fitting method for fitting a rational function (model) to a set of frequency‐domain.

Let’s first make all the necessary import

[1]:
import matplotlib.pyplot as plt

# Apply PathSim docs matplotlib style for consistent, theme-friendly figures
plt.style.use('../pathsim_docs.mplstyle')

from pathsim import Simulation, Connection
from pathsim.blocks import Spectrum, GaussianPulseSource
from pathsim.solvers import RKBS32

from pathsim.blocks.rf import RFNetwork  # requires the scikit-rf package to be installed

The block RFNetwork takes as input either a Touchstone file (.sNp file) or a scikit-rf Network. An N-port network has N inputs and N outputs.

[2]:
# The RF-Network block is created from a scikit-rf Network object example.
# Here we use a frequency measurement example of a 1-port RF network (included in scikit-rf)
import skrf as rf  # for the example
rfntwk = RFNetwork(rf.data.ring_slot_meas)
/tmp/ipykernel_6270/1059953293.py:4: DeprecationWarning: 'RFNetwork' is deprecated and will be removed in version 1.0.0. Use 'pathsim_rf.RFNetwork' instead. This block has moved to the pathsim-rf package: pip install pathsim-rf
  rfntwk = RFNetwork(rf.data.ring_slot_meas)
/home/docs/checkouts/readthedocs.org/user_builds/pathsim/envs/v0.22.2/lib/python3.13/site-packages/pathsim/blocks/rf.py:88: FutureWarning: skrf.VectorFitting is deprecated. Please import VectorFitting from skrf.vectorFitting instead.
  vf_fun = getattr(rf.VectorFitting, vf_fun_name)
/home/docs/checkouts/readthedocs.org/user_builds/pathsim/envs/v0.22.2/lib/python3.13/site-packages/pathsim/blocks/rf.py:93: FutureWarning: skrf.VectorFitting is deprecated. Please import VectorFitting from skrf.vectorFitting instead.
  vf = rf.VectorFitting(ntwk)

Under the hood, scikit-rf performs a Vector Fitting of the frequency data and creates a PathSim State-Space model.

In the following, we use a gaussian pulse to simulate the impulse response of the RF block. A spectrum analyzer (Spectrum) is used to display the frequency response of the response. This frequency response is then compared to the original frequency data.

[3]:
# Gaussian pulse simulating an impulse response
# Note that the scikit-rf Network object is passed as the 'network' parameter of the block,
# which is convenient to access its frequency data.
src = GaussianPulseSource(f_max=rfntwk.network.frequency.stop)

# Spectrum analyser setup with the start and stop frequencies of the RF network
spc = Spectrum(
    freq=rfntwk.network.f,
    labels=["pulse", "response"]
)
[4]:
# create the system connections and simulation setup
sim = Simulation(
    blocks=[src, rfntwk, spc],
    connections=[
        Connection(src, rfntwk, spc[0]),
        Connection(rfntwk, spc[1])
    ],
    tolerance_lte_abs=1e-16, # this is due to the super tiny states
    tolerance_lte_rel=1e-5,  # so error control is dominated by the relative truncation error
    Solver=RKBS32,
)

sim.run(1e-9)
11:41:01 - INFO - LOGGING (log: True)
11:41:01 - INFO - BLOCKS (total: 3, dynamic: 2, static: 1, eventful: 0)
11:41:01 - INFO - GRAPH (nodes: 3, edges: 3, alg. depth: 2, loop depth: 0, runtime: 0.053ms)
11:41:01 - INFO - STARTING -> TRANSIENT (Duration: 0.00s)
11:41:01 - INFO - --------------------   1% | 0.0s<2.2s | 3625.2 it/s
11:41:01 - INFO - ####----------------  20% | 0.3s<0.6s | 3607.7 it/s
11:41:01 - INFO - ########------------  40% | 0.4s<0.1s | 3586.2 it/s
11:41:01 - INFO - ############--------  60% | 0.4s<0.1s | 3555.1 it/s
11:41:01 - INFO - ################----  80% | 0.4s<0.0s | 3574.4 it/s
11:41:01 - INFO - #################### 100% | 0.5s<--:-- | 3543.1 it/s
11:41:01 - INFO - FINISHED -> TRANSIENT (total steps: 1612, successful: 1572, runtime: 456.23 ms)
[4]:
{'total_steps': 1612,
 'successful_steps': 1572,
 'runtime_ms': 456.2297339998622}

Below, we compare the PathSim’s frequency response to the original measurement data and to their Vector Fitted model calculated with scikit-rf. The Vector Fitted model and the PathSim’s frequency response are in perfect agreement:

[5]:
# model frequency response H(f) recovered from the spectrum block
freq, (G_pulse, G_filt) = spc.read()
H_filt_sim = G_filt / G_pulse

# plot the original S11 data, the vector-fitted model and the recovered frequency response
fig, ax = plt.subplots()
ax.plot(rfntwk.network.f/1e9, abs(rfntwk.network.s[:, 0, 0]), '.', label="S11 measurements", alpha=0.5)
ax.plot(freq/1e9, abs(rfntwk.vf.get_model_response(0, 0, freqs=freq)), lw=2, label="scikit-rf vector-fitting model")
ax.plot(freq/1e9, abs(H_filt_sim), '--', lw=2, label="pathsim impulse response")
ax.set_xlabel("Frequency [GHz]")
ax.set_ylabel("S11 magnitude")
ax.legend()
plt.show()
../_images/examples_rf_network_oneport_13_0.svg