<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Media
Introduction
skrf supports some basic circuit simulation 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 networks.
This tutorial illustrates how created Networks using several different Media objects. The basic usage is,
Step1:  To create a transmission line of 100um
Step2:  More detailed examples illustrating how to create various kinds of Media 
objects are given below. A full list of media's supported can be found in the  Media API page. The network creation and connection syntax of skrf are cumbersome  if you need to doing complex circuit design. skrf's synthesis cabilities lend themselves more to scripted applications such as calibration, optimization or batch processing.
Media Object Basics
Two arguments are common to all media constructors
frequency (required)
z0   (optional)
frequency is  a Frequency object, and z0 is the port impedance. z0 is only needed if the port impedance is different from the media's characteristic impedance. Here is an example of how to initialize a coplanar waveguide [0] media. The instance has  a 10um center conductor, gap of 5um, and substrate with relative permativity of 10.6,
Step3:  For the purpose of microwave network analysis, the defining properties of a (single moded) transmisison line are it's characteristic impedance and propagation constant. These properties return complex numpy.ndarray's,  A port impedance is also needed when different networks are connected. 
The characteristic impedance is given by a Z0 (capital Z)
Step4:  The port impedance is given by z0 (lower z).  Which we set to 1, just to illustrate how this works. The port impedance is used to compute impednace mismatched if circuits of different port impedance are connected.
Step5:  The propagation constant is given by gamma
Step6:  Lets take a look at some other Media's
Slab of  Si in Freespace
A plane-wave in freespace from 10-20GHz.
Step7:  Simpulate a 1cm slab of Si in half-space,
Step8:  Rectangular Waveguide
a WR-10 Rectangular Waveguide
Step9:  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. Lets compare the propagation constant in waveguide to that of freespace,
Step10:  Because the wave quantities are dynamic they change when the attributes 
of the media change. To illustrate, plot the propagation constant of the cpw for various values of substrated permativity,
Step11:  Network Synthesis
Networks are created through methods of a Media object. To create a 1-port network for a rectangular waveguide short,
Step12:  Or to create a $90^{\circ}$ section of cpw line,
Step13:  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.
Step14:  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,
Step15:  Adding networks in shunt  is pretty common, so there is a Media.shunt() function to do this,
Step16:  If a specific circuit is created frequently, it may make sense to 
use a function to create the circuit. This can be done most quickly using lambda
Step17:  A more useful example may be to create a function for a shunt-stub tuner,
that will work for any media object
Step18:  This approach lends itself to design optimization.
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 impedance matching network 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.
<ASSISTANT_TASK:>
Python Code:
%matplotlib inline
import skrf as rf
rf.stylely()
from skrf import Frequency
from skrf.media import CPW
freq = Frequency(75,110,101,'ghz')
cpw =  CPW(freq, w=10e-6, s=5e-6, ep_r=10.6)
cpw
Explanation: Media
Introduction
skrf supports some basic circuit simulation 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 networks.
This tutorial illustrates how created Networks using several different Media objects. The basic usage is,
End of explanation
cpw.line(100*1e-6, name = '100um line')
Explanation: To create a transmission line of 100um
End of explanation
freq = Frequency(75,110,101,'ghz')
cpw = CPW(freq, w=10e-6, s=5e-6, ep_r=10.6, z0 =1)
cpw
Explanation: More detailed examples illustrating how to create various kinds of Media 
objects are given below. A full list of media's supported can be found in the  Media API page. The network creation and connection syntax of skrf are cumbersome  if you need to doing complex circuit design. skrf's synthesis cabilities lend themselves more to scripted applications such as calibration, optimization or batch processing.
Media Object Basics
Two arguments are common to all media constructors
frequency (required)
z0   (optional)
frequency is  a Frequency object, and z0 is the port impedance. z0 is only needed if the port impedance is different from the media's characteristic impedance. Here is an example of how to initialize a coplanar waveguide [0] media. The instance has  a 10um center conductor, gap of 5um, and substrate with relative permativity of 10.6,
End of explanation
cpw.Z0[:3] 
Explanation: For the purpose of microwave network analysis, the defining properties of a (single moded) transmisison line are it's characteristic impedance and propagation constant. These properties return complex numpy.ndarray's,  A port impedance is also needed when different networks are connected. 
The characteristic impedance is given by a Z0 (capital Z)
End of explanation
cpw.z0[:3]
Explanation: The port impedance is given by z0 (lower z).  Which we set to 1, just to illustrate how this works. The port impedance is used to compute impednace mismatched if circuits of different port impedance are connected.
End of explanation
cpw.gamma[:3]
Explanation: The propagation constant is given by gamma
End of explanation
from skrf.media import Freespace
freq = Frequency(10,20,101,'ghz')
air =  Freespace(freq)
air
air.z0[:2] # 377ohm baby!
# plane wave in Si
si = Freespace(freq, ep_r = 11.2)
si.z0[:3] # ~110ohm
Explanation: Lets take a look at some other Media's
Slab of  Si in Freespace
A plane-wave in freespace from 10-20GHz.
End of explanation
slab = air.thru() ** si.line(1, 'cm') ** air.thru()
slab.plot_s_db(n=0)
Explanation: Simpulate a 1cm slab of Si in half-space,
End of explanation
from skrf.media import RectangularWaveguide
freq = Frequency(75,110,101,'ghz')
wg = RectangularWaveguide(freq, a=100*rf.mil, z0=50) # see note below about z0
wg
Explanation: Rectangular Waveguide
a WR-10 Rectangular Waveguide
End of explanation
air = Freespace(freq)
from matplotlib import pyplot as plt
air.plot(air.gamma.imag, label='Freespace')
wg.plot(wg.gamma.imag, label='WR10')
plt.ylabel('Propagation Constant (rad/m)')
plt.legend()
Explanation: 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. Lets compare the propagation constant in waveguide to that of freespace,
End of explanation
for ep_r in [9,10,11]:
    cpw.ep_r = ep_r
    cpw.frequency.plot(cpw.beta, label='er=%.1f'%ep_r)
plt.xlabel('Frequency [GHz]')
plt.ylabel('Propagation Constant [rad/m]')
plt.legend()
Explanation: Because the wave quantities are dynamic they change when the attributes 
of the media change. To illustrate, plot the propagation constant of the cpw for various values of substrated permativity,
End of explanation
wg.short(name = 'short') 
Explanation: Network Synthesis
Networks are created through methods of a Media object. To create a 1-port network for a rectangular waveguide short,
End of explanation
cpw.line(d=90,unit='deg', name='line')
Explanation: Or to create a $90^{\circ}$ section of cpw line,
End of explanation
delay_short = wg.line(d=90,unit='deg') ** wg.short()
delay_short.name = 'delay short'
delay_short
Explanation: 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.
End of explanation
tee = cpw.tee()
delay_open = cpw.delay_open(40,'deg')
shunt_open = rf.connect(tee,1,delay_open,0)
Explanation: 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,
End of explanation
cpw.shunt(delay_open)
Explanation: Adding networks in shunt  is pretty common, so there is a Media.shunt() function to do this,
End of explanation
delay_short = lambda d: wg.line(d,'deg')**wg.short()
delay_short(90)
Explanation: If a specific circuit is created frequently, it may make sense to 
use a function to create the circuit. This can be done most quickly using lambda
End of explanation
def shunt_stub(med, d0, d1):
    return med.line(d0,'deg')**med.shunt_delay_open(d1,'deg')
shunt_stub(cpw,10,90)
Explanation: A more useful example may be to create a function for a shunt-stub tuner,
that will work for any media object
End of explanation
from scipy.optimize import fmin
# the load we are trying to match
load = cpw.load(.2+.2j)
# single stub circuit generator function
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)
def cost(d):
    # prevent negative length lines, returning high cost
    if d[0] <0 or d[1] <0:
        return 1e3 
    return (shunt_stub(cpw,d[0],d[1]) ** load)[100].s_mag.squeeze()
# initial guess of optimal delay lengths in degrees
d0 = 120,40 # initial guess
#determine the optimal delays
d_opt = fmin(cost,(120,40))
d_opt 
Explanation: This approach lends itself to design optimization.
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 impedance matching network 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.
End of explanation
<END_TASK>