RF Network - One Port¶
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.
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)
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)
2025-10-13 13:30:09,744 - INFO - LOGGING (log: True)
2025-10-13 13:30:09,745 - INFO - BLOCK (type: GaussianPulseSource, dynamic: False, events: 0)
2025-10-13 13:30:09,746 - INFO - BLOCK (type: RFNetwork, dynamic: True, events: 0)
2025-10-13 13:30:09,746 - INFO - BLOCK (type: Spectrum, dynamic: True, events: 0)
2025-10-13 13:30:09,746 - INFO - GRAPH (nodes: 3, edges: 3, alg. depth: 2, loop depth: 0, runtime: 0.057ms)
2025-10-13 13:30:09,747 - INFO - STARTING -> TRANSIENT (Duration: 0.00s)
2025-10-13 13:30:09,747 - INFO - TRANSIENT: 0% | elapsed: 00:00:00 (eta: --:--:--) | 0 steps (N/A steps/s)
2025-10-13 13:30:10,034 - INFO - TRANSIENT: 20% | elapsed: 00:00:00 (eta: 00:00:01) | 1030 steps (3585.7 steps/s)
2025-10-13 13:30:10,128 - INFO - TRANSIENT: 40% | elapsed: 00:00:00 (eta: 00:00:00) | 1342 steps (3332.4 steps/s)
2025-10-13 13:30:10,163 - INFO - TRANSIENT: 60% | elapsed: 00:00:00 (eta: 00:00:00) | 1464 steps (3494.0 steps/s)
2025-10-13 13:30:10,200 - INFO - TRANSIENT: 80% | elapsed: 00:00:00 (eta: 00:00:00) | 1586 steps (3306.7 steps/s)
2025-10-13 13:30:10,236 - INFO - TRANSIENT: 100% | elapsed: 00:00:00 (eta: 00:00:00) | 1707 steps (3332.0 steps/s)
2025-10-13 13:30:10,237 - INFO - TRANSIENT: 100% | elapsed: 00:00:00 (eta: 00:00:00) | 1707 steps (3481.0 avg steps/s)
2025-10-13 13:30:10,237 - INFO - FINISHED -> TRANSIENT (total steps: 1707, successful: 1661, runtime: 490.37 ms)
[4]:
{'total_steps': 1707,
'successful_steps': 1661,
'runtime_ms': 490.37446999864187}
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()