Lumped Elements Circuits

In this notebook, we construct various network from basic lumped elements (resistor, capacitor, inductor), with the ‘classic’ and the Circuit approach. Generally the Circuit approach is more verbose than the ‘classic’ way for building a circuit. However, as the circuit complexity increases, in particular when components are connected in parallel, the Circuit approach is interesting as it increases the readability of the code. Moreover, Circuit object can be plotted using its plot_graph() method, which is usefull to rapidly control if the circuit is built as expected.

[1]:
import numpy as np  # for np.allclose() to check that S-params are similar
import skrf as rf
rf.stylely()

LC Series Circuit

In this section we reproduce a simple equivalent model of a capacitor \(C\), as illustrated by the figure below:

6457506f6bbd46f487f7f7501d646f3c

[2]:
# reference LC circuit made in Designer
LC_designer = rf.Network('designer_capacitor_30_80MHz_simple.s2p')
[3]:
# scikit-rf: manually connecting networks
line = rf.media.DefinedGammaZ0(frequency=LC_designer.frequency, z0=50)
LC_manual = line.inductor(24e-9) ** line.capacitor(70e-12)
[4]:
# scikit-rf: using Circuit builder
port1 = rf.Circuit.Port(frequency=LC_designer.frequency, name='port1', z0=50)
port2 = rf.Circuit.Port(frequency=LC_designer.frequency, name='port2', z0=50)
line = rf.media.DefinedGammaZ0(frequency=LC_designer.frequency, z0=50)
cap = line.capacitor(70e-12, name='cap')
ind = line.inductor(24e-9, name='ind')

connections = [
    [(port1, 0), (cap, 0)],
    [(cap, 1), (ind, 0)],
    [(ind, 1), (port2, 0)]
]
circuit = rf.Circuit(connections)
LC_from_circuit = circuit.network
[5]:
# testing the equivalence of the results
print(np.allclose(LC_designer.s, LC_manual.s))
print(np.allclose(LC_designer.s, LC_from_circuit.s))
True
True
[6]:
circuit.plot_graph(network_labels=True, edge_labels=True, port_labels=True)
../../_images/examples_circuit_Lumped_Element_Circuits_9_0.png

A More Advanced Equivalent Model

In this section we reproduce an equivalent model of a capacitor \(C\), as illustrated by the figure below:

f37b6629eab447c3b6b08bc7646f5f7b

[7]:
# Reference results from ANSYS Designer
LCC_designer = rf.Network('designer_capacitor_30_80MHz_adv.s2p')
[8]:
# scikit-rf: usual way, but this time this is more tedious to deal with connection and port number
freq = LCC_designer.frequency
line = rf.media.DefinedGammaZ0(frequency=freq, z0=50)
elements1 = line.resistor(1e-2) ** line.inductor(24e-9) ** line.capacitor(70e-12)
elements2 = line.resistor(20e6)
T_in = line.tee()
T_out = line.tee()
ntw = rf.connect(T_in, 1, elements1, 0)
ntw = rf.connect(ntw, 2, elements2, 0)
ntw = rf.connect(ntw, 1, T_out, 1)
ntw = rf.innerconnect(ntw, 1, 2)
LCC_manual = ntw ** line.shunt_capacitor(50e-12)
[9]:
# scikit-rf: using Circuit builder
freq = LCC_designer.frequency
port1 = rf.Circuit.Port(frequency=freq, name='port1', z0=50)
port2 = rf.Circuit.Port(frequency=freq, name='port2', z0=50)
line = rf.media.DefinedGammaZ0(frequency=freq, z0=50)
cap = line.capacitor(70e-12, name='cap')
ind = line.inductor(24e-9, name='ind')
res_series = line.resistor(1e-2, name='res_series')
res_parallel = line.resistor(20e6, name='res_parallel')
cap_shunt = line.capacitor(50e-12, name='cap_shunt')
ground = rf.Circuit.Ground(frequency=freq, name='ground', z0=50)

connections = [
    [(port1, 0), (res_series, 0), (res_parallel, 0)],
    [(res_series, 1), (cap, 0)],
    [(cap, 1), (ind, 0)],
    [(ind, 1), (cap_shunt, 0), (res_parallel, 1), (port2, 0)],
    [(cap_shunt, 1), (ground, 0)],
]
circuit = rf.Circuit(connections)
LCC_from_circuit = circuit.network
[10]:
# testing the equivalence of the results
print(np.allclose(LCC_designer.s, LCC_manual.s))
print(np.allclose(LCC_designer.s, LCC_from_circuit.s))
True
True
[11]:
circuit.plot_graph(network_labels=True, edge_labels=True, port_labels=True)
../../_images/examples_circuit_Lumped_Element_Circuits_16_0.png

Pass band filter

Below we construct a pass-band filter, from an example given in Microwaves101:

d90cb9158e5d4cd19e53c1444a8706d7

[12]:
# Reference result calculated from Designer
passband_designer = rf.Network('designer_bandpass_filter_450_550MHz.s2p')
[13]:
# scikit-rf:
freq = passband_designer.frequency
passband_manual = line.shunt_capacitor(25.406e-12) ** line.shunt_inductor(4.154e-9) ** \
                  line.capacitor(2.419e-12) ** line.inductor(43.636e-9) ** \
                  line.shunt_capacitor(25.406e-12) ** line.shunt_inductor(4.154e-9)
[14]:
# scikit-rf: the filter with the Circuit builder
freq = passband_designer.frequency
line = rf.media.DefinedGammaZ0(frequency=freq)
C1 = line.capacitor(25.406e-12, name='C1')
C2 = line.capacitor(2.419e-12, name='C2')
C3 = line.capacitor(25.406e-12, name='C3')
L1 = line.inductor(4.154e-9, name='L1')
L2 = line.inductor(43.636e-9, name='L2')
L3 = line.inductor(4.154e-9, name='L3')
port1 = rf.Circuit.Port(frequency=freq, name='port1', z0=50)
port2 = rf.Circuit.Port(frequency=freq, name='port2', z0=50)
ground1 =  rf.Circuit.Ground(frequency=freq, name='ground1', z0=50)
ground2 =  rf.Circuit.Ground(frequency=freq, name='ground2', z0=50)
ground3 =  rf.Circuit.Ground(frequency=freq, name='ground3', z0=50)
ground4 =  rf.Circuit.Ground(frequency=freq, name='ground4', z0=50)

connections = [
    [(port1, 0), (C1, 0), (L1, 0), (C2, 0)],
    [(C2, 1), (L2, 0)],
    [(L2, 1), (C3, 0), (L3, 0), (port2, 0)],
    # grounding must be done on ground ntw having different names
    [(C1, 1), (ground1, 0)],
    [(C3, 1), (ground2, 0)],
    [(L1, 1), (ground3, 0)],
    [(L3, 1), (ground4, 0)],
]

circuit = rf.Circuit(connections)
passband_circuit = circuit.network
passband_circuit.name = 'Pass-band circuit'
[15]:
passband_circuit.plot_s_db(m=0, n=0, lw=2)
passband_circuit.plot_s_db(m=1, n=0, lw=2)
passband_designer.plot_s_db(m=0, n=0, lw=2, ls='-.')
passband_designer.plot_s_db(m=1, n=0, lw=2, ls='-.')
../../_images/examples_circuit_Lumped_Element_Circuits_23_0.png
[16]:
circuit.plot_graph(network_labels=True, port_labels=True, edge_labels=True)
../../_images/examples_circuit_Lumped_Element_Circuits_24_0.png