{ "cells": [ { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ ".. _introduction:\n", "\n", "|\n", "|\n", "\n", "Download This Notebook: :download:`Introduction.ipynb`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a brief introduction to **scikit-rf** (aka `skrf`). The intended audience are those who have a working python stack, and are somewhat familiar with python. If you are completely new to python, see scipy's [Getting Started](http://www.scipy.org/Getting_Started). First, import the scikit-rf module `skrf`, as `rf`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import skrf as rf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If this produces an error, please see the [installation](Installation.ipynb) tutorial." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Networks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The central object in `skrf` is a N-port microwave [Network][Network] object. A [Network][Network] can be created in a number of ways, one way is from data stored in a touchstone file.\n", "\n", "[Network]: ../api/network.rst" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ring_slot = rf.Network('data/ring slot.s2p')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you can't find `ring slot.s2p`, then just import it from the `skrf.data` module. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from skrf.data import ring_slot # noqa: F811" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A short description of the network will be printed out if entered onto the command line" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ring_slot" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The basic attributes of a microwave [Network](../api/network.rst) are provided by the \n", "following properties,\n", "\n", "\n", "* `Network.s` : Scattering Parameter matrix. \n", "* `Network.z0` : Port Impedance matrix.\n", "* `Network.frequency` : Frequency Object. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " The [Network](../api/network.rst) object has numerous other properties and methods which can found in it's docstring. If you are using IPython/Jupyter, then these properties and methods can be 'tabbed' out on the command line. \n", "\n", "\n", "\tIn [1]: ring_slot.s\n", "\tring_slot.s ring_slot.s_arcl ring_slot.s_im\n", "\tring_slot.s11 ring_slot.s_arcl_unwrap ring_slot.s_mag\n", "\t..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other way to build Network are detailed in the [tutorial on Networks](Networks.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Linear Operations " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\t\n", "Element-wise mathematical operations on the s-parameters are accessible through overloaded operators. To illustrate, we load a couple `Networks` stored in the `skrf.data` module. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "short = rf.data.wr2p2_short\n", "delayshort = rf.data.wr2p2_delayshort" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The complex difference between their s-parameters is computed with " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "short - delayshort" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This returns a new [Network](../api/network.rst). Other arithmetic operators are overloaded as well," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "short/delayshort" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Cascading and De-embedding" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cascading and de-embeding 2-port Networks can also be done though operators. Cascading is done through the power operator, ``**``. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "short = rf.data.wr2p2_short\n", "line = rf.data.wr2p2_line\n", "\n", "delayshort = line ** short" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "De-embedding can be accomplished by cascading the *inverse* of a network. The inverse of a network is accessed through the property `Network.inv`. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "short = line.inv ** delayshort" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more information on the functionality provided by the [Network](../api/network.rst) object, such as interpolation, stitching, n-port connections, and IO support see the [Networks](Networks.ipynb) tutorial." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Finding minimum (or maximum) of a Network quantity\n", "Often, it is desirable to get the minimum (or maximum) value of a Network quantity (s-parameters, z-parameters, etc.) and the frequency at which this occurs. In `scikit-rf`, Network quantities are stored as [Numpy](https://numpy.org/) arrays of shape ($N_F$, $N_p$, $N_p$) where $N_F$ is the number of frequency points and $N_p$ is the number of ports of a Network:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(type(line.s)) # s-parameters are stored as a Numpy array" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(line.s.shape) # line is a 2-port Network defined on 201 frequency points" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The frequency points are defined in the `frequency` parameter of a Network:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(line.frequency) # returns a Frequency object" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The frequency values are given by the `frequency.f` parameter, or simply `.f`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "line.f[0:10] # the 10 first frequency points. Same than line.frequency.f[0:10]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Being a Numpy array, finding the minimum (or maximum) value of a the magnitude of the $S_{21}$ parameter can be performed using the `min()` (or `max()`) method:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "rs = rf.data.ring_slot # another 2-port example\n", "\n", "print(rs.s_mag[:,1,0].min()) # or .max() for maximum. Watch out that Python indexing starts at 0!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finding the frequency at which the magnitude of the $S_{11}$ parameter is minimum can be performed using the Numpy function [`argmin`](https://numpy.org/doc/stable/reference/generated/numpy.argmin.html?highlight=argmin#numpy.argmin):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f_match = rs.f[np.argmin(rs.s_mag[:,0,0])] # frequency for min(|S11|)\n", "print(f_match)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting " ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ ".. note::\n", "\n", " The plotting infrastructure in skrf is under refactoring at the moment to allow for multiple backends, and headless setups. The following assumes you are using `matplotlib` with an interactive session." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**skrf** has a function which updates your [matplotlib rcParams](http://matplotlib.org/users/customizing.html) so that plots appear like the ones shown in these tutorials. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# display plots in notebook\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "rf.stylely()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The methods of the [Network](../api/network.rst) class provide convenient ways to plot components of the network parameters,\n", "\n", "* `Network.plot_s_db()` : plot magnitude of s-parameters in log scale\n", "* `Network.plot_s_deg()` : plot phase of s-parameters in degrees\n", "* `Network.plot_s_smith()` : plot complex s-parameters on Smith Chart" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To plot all four s-parameters of the ``ring_slot`` in Mag, Phase, and on the Smith Chart." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ring_slot.plot_s_db()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or plot the phase of $S_{12}$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ring_slot.plot_s_deg(m=0,n=1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ring_slot.plot_s_smith(lw=2)\n", "plt.title('Big ole Smith Chart')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more detailed information about plotting see the [Plotting](Plotting.ipynb) tutorial" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## NetworkSet " ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ ".. currentmodule:: skrf.networkSet" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The [NetworkSet](../api/networkSet.rst) object\n", "represents an unordered set of networks and provides methods for \n", "calculating statistical quantities and displaying uncertainty bounds.\n", "\n", "A [NetworkSet](../api/networkSet.rst) is created from a list or dict of \n", "[Networks](../api/network.rst)'s. This can be done quickly with \n", "`rf.io.read_all()` , which loads all skrf-readable objects\n", "in a directory. The argument ``contains`` is used to load only files \n", "which match a given substring. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rf.io.read_all('data/', contains='ro')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This dictionary can be passed directly to the [NetworkSet](../api/networkSet.rst) constructor, " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from skrf.networkSet import NetworkSet\n", "\n", "ro_dict = rf.io.read_all('data/', contains='ro')\n", "ro_ns = NetworkSet(ro_dict, name='ro set') # name is optional\n", "ro_ns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[NetworkSet](../api/networkSet.rst)'s are list-like. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Statistical Properties" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Statistical quantities can be calculated by accessing \n", "properties of the [NetworkSet](../api/networkSet.rst). For example, to calculate the complex \n", "average of the set, access the ``mean_s`` property" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ro_ns.mean_s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The returned results are stored in a [Network](../api/network.rst)s s-parameters, regardless of the type of the output. Similarly, to calculate the complex standard deviation of the set, " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ro_ns.std_s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because these methods return a [Network](../api/network.rst) object the results can be \n", "saved or plotted in the same way as you would with a [Network](../api/network.rst). To plot the magnitude of the standard deviation of the set, " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ro_ns.std_s.plot_s_mag(label='S11')\n", "plt.ylabel('Standard Deviation')\n", "plt.title('Standard Deviation of RO')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting Uncertainty Bounds" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uncertainty bounds on any network parameter can be plotted through the methods " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ro_ns.plot_uncertainty_bounds_s_db(label='S11');" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "See the [networkset](NetworkSet.ipynb) tutorial for more information.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Virtual Instruments" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The [skrf.vi](../api/vi/index.rst) module provides classes to communicate with\n", "some instruments. At the moment, this is only VNAs, but more support may be\n", "added in the future. See the [Virtual Instrument](VirtualInstruments.ipynb)\n", "tutorial for more information." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An example of using the `PNA` class to retrieve some s-parameter data and plot it" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " from skrf.vi.vna.keysight import PNA\n", " instr = PNA(address=\"TCPIP0::10.0.0.1::INSTR\") \n", "\n", " freq = Frequency(start=2.3e9, stop=2.6e9, npoints=401, unit='hz')\n", " instr.frequency = freq\n", "\n", " ntwk = instr.get_snp_network(ports=(1,2))\n", " ntwk.s21.plot_s_db()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calibration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calibrations are performed through a [Calibration](../api/calibration/index.rst) class. In most cases, creating\n", "a [Calibration](../api/calibration/index.rst) object requires at least two pieces of information:\n", "\n", "* a list of measured [Network](../api/network.rst)'s\n", "* a list of ideal [Network](../api/network.rst)'s\n", "\n", "The [Network](../api/network.rst) elements in each list must all be similar (same #ports, frequency info, etc) and must be aligned to each other, meaning the first element of ideals list must correspond to the first element of measured list.\n", "\n", "Below is an example script illustrating how to create a [Calibration](../api/calibration/index.rst) .\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### One Port Calibration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " import skrf as rf\n", " from skrf.calibration import OnePort\n", " \n", " my_ideals = rf.io.read_all('ideals/')\n", " my_measured = rf.io.read_all('measured/')\n", " duts = rf.io.read_all('measured/')\n", " \n", " ## create a Calibration instance\n", " cal = OnePort(\n", " ideals = [my_ideals[k] for k in ['short','open','load']],\n", " measured = [my_measured[k] for k in ['short','open','load']],\n", " )\n", " \n", " caled_duts = [cal.apply_cal(dut) for dut in duts.values()]\n", " \n", "See the [Calibration](Calibration.ipynb) tutorial for more details and examples. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transmission Line Media" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ ".. currentModule:: skrf.media" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Simple transmission-line based networks can be created through methods of the [Media](../api/media/index.rst) class, which represents a transmission line object for a given medium. Once constructed, a [Media](../api/media/index.rst) object contains the necessary properties such as ``propagation constant`` and ``characteristic impedance``, that are needed to generate microwave circuits.\n", "\n", "The basic usage looks something like this, \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### CPW\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from skrf import Frequency\n", "from skrf.media import CPW, Coaxial\n", "\n", "freq = Frequency(75, 110, 101, 'GHz')\n", "cpw = CPW(freq, w = 10e-6, s = 5e-6, ep_r = 10.6)\n", "cpw" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cpw.line(d=90,unit='deg', name='line')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Coax" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "freq = Frequency(1, 10, 101, 'GHz')\n", "coax = Coaxial(frequency = freq, Dint = 1e-3, Dout = 2e-3)\n", "coax" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3.10.4 ('skrf')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.6" }, "vscode": { "interpreter": { "hash": "6e9ab46c0308d25f8ecf2297d605bcf30c0184a06f23fc8ad30aef47f26c08c0" } } }, "nbformat": 4, "nbformat_minor": 1 }