Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Open, SeriesImpedance and ShuntAdmittance classmethods to Circuit #529

Merged
merged 3 commits into from
Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
139 changes: 128 additions & 11 deletions skrf/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,13 @@ def Port(cls, frequency: 'Frequency', name: str, z0: float = 50) -> 'Network':
name : string
Name of the port.
Must include the word 'port' inside. (ex: 'Port1' or 'port_3')
z0 : real
z0 : real, optional
Characteristic impedance of the port. Default is 50 Ohm.

Returns
-------
port : :class:`~skrf.network.Network` object
(External) 1-port network
1-port network

Examples
--------
Expand All @@ -240,27 +240,71 @@ def Port(cls, frequency: 'Frequency', name: str, z0: float = 50) -> 'Network':
return _media.match(name=name)

@classmethod
def Ground(cls, frequency: 'Frequency', name: str, z0: float = 50) -> 'Network':
def SeriesImpedance(cls, frequency: 'Frequency', Z: NumberLike, name: str, z0: float = 50) -> 'Network':
"""
Return a 1-port network of a grounded link, to be used in a Circuit description.
Return a 2-port network of a series impedance.

Passing the frequency and name is mandatory.

The ground link is modelled as an infinite admittance.
Parameters
----------
frequency : :class:`~skrf.frequency.Frequency`
Frequency common to all other networks in the circuit
Z : complex array of shape n_freqs
Impedance
name : string
Name of the serie impedance
z0 : real, optional
Characteristic impedance of the port. Default is 50 Ohm.

Returns
-------
serie_impedance : :class:`~skrf.network.Network` object
2-port network

Examples
--------
.. ipython::

@suppress
In [16]: import skrf as rf

In [17]: freq = rf.Frequency(start=1, stop=2, npoints=101)

In [18]: open = rf.Circuit.SeriesImpedance(freq, name='series_impedance')

"""
A = np.zeros(shape=(len(frequency), 2, 2), dtype=complex)
A[:, 0, 0] = 1
A[:, 0, 1] = Z
A[:, 1, 0] = 0
A[:, 1, 1] = 1
ntw = Network(frequency=frequency, z0=z0, name=name)
ntw.s = a2s(A)
return ntw

@classmethod
def ShuntAdmittance(cls, frequency: 'Frequency', Y: NumberLike, name: str, z0: float = 50) -> 'Network':
"""
Return a 2-port network of a shunt admittance.

Passing the frequency and name is mandatory.

Parameters
----------
frequency : :class:`~skrf.frequency.Frequency`
Frequency common to all other networks in the circuit
Y : complex array of shape n_freqs
Admittance
name : string
Name of the ground.
z0 : real
Name of the serie impedance
jhillairet marked this conversation as resolved.
Show resolved Hide resolved
z0 : real, optional
Characteristic impedance of the port. Default is 50 Ohm.

Returns
-------
ground : :class:`~skrf.network.Network` object
(External) 2-port network
shunt_admittance : :class:`~skrf.network.Network` object
2-port network

Examples
--------
Expand All @@ -271,10 +315,9 @@ def Ground(cls, frequency: 'Frequency', name: str, z0: float = 50) -> 'Network':

In [17]: freq = rf.Frequency(start=1, stop=2, npoints=101)

In [18]: ground = rf.Circuit.Ground(freq, name='GND')
In [18]: open = rf.Circuit.ShuntAdmittance(freq, name='shunt_admittance')

"""
Y = INF
A = np.zeros(shape=(len(frequency), 2, 2), dtype=complex)
A[:, 0, 0] = 1
A[:, 0, 1] = 0
Expand All @@ -284,6 +327,80 @@ def Ground(cls, frequency: 'Frequency', name: str, z0: float = 50) -> 'Network':
ntw.s = a2s(A)
return ntw

@classmethod
def Ground(cls, frequency: 'Frequency', name: str, z0: float = 50) -> 'Network':
"""
Return a 2-port network of a grounded link.

Passing the frequency and a name is mandatory.

The ground link is modelled as an infinite shunt admittance.

Parameters
----------
frequency : :class:`~skrf.frequency.Frequency`
Frequency common to all other networks in the circuit
name : string
Name of the ground.
z0 : real, optional
Characteristic impedance of the port. Default is 50 Ohm.

Returns
-------
ground : :class:`~skrf.network.Network` object
2-port network

Examples
--------
.. ipython::

@suppress
In [16]: import skrf as rf

In [17]: freq = rf.Frequency(start=1, stop=2, npoints=101)

In [18]: ground = rf.Circuit.Ground(freq, name='GND')

"""
return cls.ShuntAdmittance(frequency, Y=INF, name=name)

@classmethod
def Open(cls, frequency: 'Frequency', name: str, z0: float = 50) -> 'Network':
"""
Return a 2-port network of an open link.

Passing the frequency and name is mandatory.

The open link is modelled as an infinite series impedance.

Parameters
----------
frequency : :class:`~skrf.frequency.Frequency`
Frequency common to all other networks in the circuit
name : string
Name of the open.
z0 : real, optional
Characteristic impedance of the port. Default is 50 Ohm.

Returns
-------
open : :class:`~skrf.network.Network` object
2-port network

Examples
--------
.. ipython::

@suppress
In [16]: import skrf as rf

In [17]: freq = rf.Frequency(start=1, stop=2, npoints=101)

In [18]: open = rf.Circuit.Open(freq, name='open')

"""
return cls.SeriesImpedance(frequency, Z=INF, name=name)

def networks_dict(self, connections: List = None, min_nports: int = 1) -> dict:
"""
Return the dictionary of Networks from the connection setup X.
Expand Down
70 changes: 69 additions & 1 deletion skrf/tests/test_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import os, sys
from numpy.testing import assert_array_almost_equal, run_module_suite


class CircuitTestConstructor(unittest.TestCase):
'''
Various tests on the Circuit constructor.
Expand Down Expand Up @@ -62,6 +61,75 @@ def test_s_active(self):
assert_array_almost_equal(circuit.s_active([0, 1])[:,1], circuit.s_external[:,1,1])


class CircuitClassMethods(unittest.TestCase):
"""
Test the various class methods of Circuit such as Ground, Port, etc.
"""
def setUp(self):
self.freq = rf.Frequency(start=1, stop=2, npoints=101)
self.media = rf.DefinedGammaZ0(self.freq)

def test_ground(self):
"""
Ground object are infinite shunt admittance (ie. a 2-port short)
"""
# should raise an exception if no name is passed
with self.assertRaises(TypeError):
gnd = rf.Circuit.Ground(self.freq)

gnd = rf.Circuit.Ground(self.freq, 'gnd')
gnd_ref = rf.Network(frequency=self.freq,
s=np.tile(np.array([[-1, 0],
[0, -1]]),
(len(self.freq),1,1)))

assert_array_almost_equal(gnd.s, gnd_ref.s)


def test_open(self):
"""
Open object are infinite series resistance (ie. a 2-port open)
"""
# should raise an exception if no name is passed
with self.assertRaises(TypeError):
opn = rf.Circuit.Open(self.freq)

opn = rf.Circuit.Open(self.freq, 'open')
opn_ref = rf.Network(frequency=self.freq,
s=np.tile(np.array([[1, 0],
[0, 1]]),
(len(self.freq),1,1)))

assert_array_almost_equal(opn.s, opn_ref.s)

def test_series_impedance(self):
Zs = [1, 1 + 1j, rf.INF]
for Z in Zs:
assert_array_almost_equal(
rf.Circuit.SeriesImpedance(self.freq, Z, 'imp').s,
self.media.resistor(Z).s
)

# Z=0 is a thru
assert_array_almost_equal(
rf.Circuit.SeriesImpedance(self.freq, Z=0, name='imp').s,
self.media.thru().s
)

def test_shunt_admittance(self):
Ys = [1, 1 + 1j, rf.INF]
for Y in Ys:
assert_array_almost_equal(
rf.Circuit.ShuntAdmittance(self.freq, Y, 'imp').s,
self.media.shunt(self.media.load(rf.zl_2_Gamma0(self.media.z0, 1/Y))).s
)

# Y=INF is a a 2-ports short, aka a ground
assert_array_almost_equal(
rf.Circuit.ShuntAdmittance(self.freq, rf.INF, 'imp').s,
rf.Circuit.Ground(self.freq, 'ground').s
)

class CircuitTestWilkinson(unittest.TestCase):
'''
Create a Wilkinson power divider Circuit [#]_ and test the results
Expand Down