Media

Introduction

skrf supports the microwave network synthesis based on transmission line models. Network creation is accomplished through methods of the Media class, which represents a transmission line object for a given medium. Once constructed, a Media object contains the neccesary properties such as propagation constant and characteristic impedance, that are needed to generate microwave circuits.

This tutorial illustrates how created Networks using several different Media objects. The basic usage is,

In [8]: import skrf as rf

In [9]: freq = rf.Frequency(75,110,101,'ghz')

In [10]: cpw = rf.media.CPW(freq, w=10e-6, s=5e-6, ep_r=10.6)

In [11]: cpw.line(100*1e-6, name = '100um line')
Out[11]: 2-Port Network: '100um line',  75-110 GHz, 101 pts, z0=[ 50.06074662+0.j  50.06074662+0.j]

More detailed examples illustrating how to create various kinds of Media objects are given below.

Warning

The network creation and connection syntax of skrf are cumbersome if you need to doing complex circuit design. For a this type of application, you may be interested in using QUCS instead. skrf‘s synthesis cabilities lend themselves more to scripted applications such as Design Optimization or batch processing.

Media’s Supported by skrf

The base-class, Media, is constructed directly from values of propagation constant and characteristic impedance. Specific instances of Media objects can be created from relevant physical and electrical properties. Below is a list of mediums types supported by skrf,

Creating Media Objects

Typically, network analysis is done within a given frequency band. When a Media object is created, it must be given a Frequency object. This prevent having to repitously provide frequency information for each new network created.

Coplanar Waveguide

Here is an example of how to initialize a coplanar waveguide [1] media. The instance has a 10um center conductor, gap of 5um, and substrate with relative permativity of 10.6,

In [12]: import skrf as rf

In [13]: freq = rf.Frequency(75,110,101,'ghz')

In [14]: cpw = rf.media.CPW(freq, w=10e-6, s=5e-6, ep_r=10.6)

In [15]: cpw
Out[15]: 
Coplanar Waveguide Media.  75-110 GHz.  101 points
 W= 1.00e-05m, S= 5.00e-06m

See CPW for details on that class.

Freespace

Here is another example, this time constructing a plane-wave in freespace from 10-20GHz

In [16]: freq = rf.Frequency(10,20,101,'ghz')

In [17]: fs = rf.media.Freespace(freq)

In [18]: fs
Out[18]: Freespace  Media.  10-20 GHz.  101 points

See Freespace for details.

Rectangular Waveguide

or a WR-10 Rectangular Waveguide

In [19]: freq = rf.Frequency(75,110,101,'ghz')

In [20]: wg = rf.media.RectangularWaveguide(freq, a=100*rf.mil,z0=50) # see note below about z0

In [21]: wg
Out[21]: 
Rectangular Waveguide Media.  75-110 GHz.  101 points
 a= 2.54e-03m, b= 1.27e-03m

See RectangularWaveguide for details.

Note

The z0 argument in the Rectangular Waveguide constructor is used to force a specifc port impedance. This is commonly used to match the port impedance to what a VNA stores in a touchstone file. See media.Media.__init__() for more information.

Working with Media’s

Once constructed, the pertinent wave quantities of the media such as propagation constant and characteristic impedance can be accessed through the properties propagation_constant and characteristic_impedance. These properties return complex numpy.ndarray‘s,

In [22]: cpw.propagation_constant[:3]
Out[22]: array([ 0.+3785.59740815j,  0.+3803.26352939j,  0.+3820.92965062j])

In [23]: cpw.characteristic_impedance[:3]
Out[23]: array([ 50.06074662+0.j,  50.06074662+0.j,  50.06074662+0.j])

As an example, plot the cpw’s propagation constant vs frequency.

In [24]: plot(cpw.frequency.f_scaled, cpw.propagation_constant.imag);

In [25]: xlabel('Frequency [GHz]');

In [26]: ylabel('Propagation Constant [rad/m]');
../_images/media-cpw_propagation_constant.png

Because the wave quantities are dynamic they change when the attributes of the cpw line change. To illustrate this, plot the propagation constant of the cpw for various values of substrated permativity,

In [27]: figure();

In [28]: for ep_r in [9,10,11]:
   ....:      cpw.ep_r = ep_r
   ....:      plot(cpw.frequency.f_scaled, cpw.propagation_constant.imag, label='er=%.1f'%ep_r)
   ....: 

In [29]: xlabel('Frequency [GHz]');

In [30]: ylabel('Propagation Constant [rad/m]');

In [31]: legend();

In [32]: cpw.ep_r = 10.6
../_images/media-cpw_propagation_constant2.png

Network Synthesis

Networks are created through methods of a Media object. Here is a brief list of some generic network components skrf supports,

Usage of these methods can is demonstrated below.

To create a 1-port network for a rectangular waveguide short,

In [33]: wg.short(name = 'short')
Out[33]: 1-Port Network: 'short',  75-110 GHz, 101 pts, z0=[ 50.+0.j]

Or to create a 90^{\circ} section of cpw line,

In [34]: cpw.line(d=90,unit='deg', name='line')
Out[34]: 2-Port Network: 'line',  75-110 GHz, 101 pts, z0=[ 50.06074662+0.j  50.06074662+0.j]

Note

Simple circuits like short() and open() are ideal short and opens with \Gamma = -1 and \Gamma = 1, i.e. they dont take into account sophisticated effects of the discontinuties. Effects of discontinuities are implemented as methods specific to a given Media, like CPW.cpw_short.

Building Cicuits

By connecting a series of simple circuits, more complex circuits can be made. To build a the 90^{\circ} delay short, in the rectangular waveguide media defined above.

In [35]: delay_short = wg.line(d=90,unit='deg') ** wg.short()

In [36]: delay_short.name = 'delay short'

In [37]: delay_short
Out[37]: 1-Port Network: 'delay short',  75-110 GHz, 101 pts, z0=[ 50.+0.j]

When Networks with more than 2 ports need to be connected together, use rf.connect(). To create a two-port network for a shunted delayed open, you can create an ideal 3-way splitter (a ‘tee’) and conect the delayed open to one of its ports,

In [38]: tee = cpw.tee()

In [39]: delay_open = cpw.delay_open(40,'deg')

In [40]: shunt_open = rf.connect(tee,1,delay_open,0)

If a specific circuit is created frequenctly, it may make sense to use a function to create the circuit. This can be done most quickly using lamba

In [41]: delay_short = lambda d: wg.line(d,'deg')**wg.short()

In [42]: delay_short(90)
Out[42]: 1-Port Network: '',  75-110 GHz, 101 pts, z0=[ 50.+0.j]

This is how many of skrf‘s network creation methods are made internally.

A more useful example may be to create a function for a shunt-stub tuner, that will work for any media object

In [43]: def shunt_stub(med, d0, d1):
   ....:      return med.line(d0,'deg')**med.shunt_delay_open(d1,'deg')
   ....: 

In [44]: shunt_stub(cpw,10,90)
Out[44]: 2-Port Network: '',  75-110 GHz, 101 pts, z0=[ 50.06074662+0.j  50.06074662+0.j]

Design Optimization

The abilities of scipy‘s optimizers can be used to automate network design. In this example, skrf is used to automate the single stub design. First, we create a ‘cost’ function which returns somthing we want to minimize, such as the reflection coefficient magnitude at band center. Then, one of scipy’s minimization algorithms is used to determine the optimal parameters of the stub lengths to minimize this cost.

In [45]: from scipy.optimize import fmin

# the load we are trying to match
In [46]: load = cpw.load(rf.zl_2_Gamma0(z0=50,zl=100))

# single stub circuit generator function
In [47]: def shunt_stub(med, d0, d1):
   ....:      return med.line(d0,'deg')**med.shunt_delay_open(d1,'deg')
   ....: 

# define the cost function we want to minimize (this uses sloppy namespace)
In [48]: def cost(d):
   ....:      return (shunt_stub(cpw,d[0],d[1]) ** load)[100].s_mag.squeeze()
   ....: 

# initial guess of optimal delay lengths in degrees
In [49]: d0 = 120,40 # initial guess

#determine the optimal delays
In [50]: d_opt = fmin(cost,(120,40))
Optimization terminated successfully.
         Current function value: 0.333333
         Iterations: 65
         Function evaluations: 140

In [51]: d_opt
Out[51]: array([  1.74945025e+02,  -9.55405994e-08])