diff --git a/.travis.yml b/.travis.yml index a5e005592..cd89047b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,15 +2,15 @@ dist: xenial language: python python: - 2.7 -- 3.5 - 3.6 - 3.7 +- 3.8 services: - xvfb before_install: - sudo apt-get update -- if [[ "$TRAVIS_PYTHON_VERSION" == 2* ]]; then wget http://repo.continuum.io/miniconda/Miniconda-3.7.0-Linux-x86_64.sh - -O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-3.7.0-Linux-x86_64.sh +- if [[ "$TRAVIS_PYTHON_VERSION" == 2* ]]; then wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh + -O miniconda.sh; else wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; fi - bash miniconda.sh -b -p $HOME/miniconda - export PATH="$HOME/miniconda/bin:$PATH" diff --git a/LICENSE.txt b/LICENSE.txt index 7934c74c0..ddfd40848 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,7 @@ Copyright (c) 2010, Alexander Arsenovic All rights reserved. -Copyright (c) 2017, scikit-rf Developers +Copyright (c) 2020, scikit-rf Developers All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index 1e7a182f7..76da1f219 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -1,5 +1,5 @@ {% set name = "scikit-rf" %} -{% set version = "0.15.3" %} +{% set version = "0.15.4" %} {% set hash_val = "8223204281599ba14b685d7e28b7e361" %} package: diff --git a/doc/make.bat b/doc/make.bat index 955d83152..2119f5109 100644 --- a/doc/make.bat +++ b/doc/make.bat @@ -1,155 +1,35 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\mwavepy.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\mwavepy.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/doc/source/api/calibration/calibration.rst b/doc/source/api/calibration/calibration.rst deleted file mode 100644 index 243df9f55..000000000 --- a/doc/source/api/calibration/calibration.rst +++ /dev/null @@ -1,2 +0,0 @@ -.. automodule:: skrf.calibration.calibration - diff --git a/doc/source/api/calibration/calibrationFunctions.rst b/doc/source/api/calibration/calibrationFunctions.rst deleted file mode 100644 index 4713ed64f..000000000 --- a/doc/source/api/calibration/calibrationFunctions.rst +++ /dev/null @@ -1 +0,0 @@ -.. automodule:: skrf.calibration.calibrationFunctions diff --git a/doc/source/api/index.rst b/doc/source/api/index.rst index 13c95d9b2..3c366d682 100644 --- a/doc/source/api/index.rst +++ b/doc/source/api/index.rst @@ -13,7 +13,6 @@ API circuit plotting - time mathFunctions tlineFunctions constants @@ -22,5 +21,6 @@ API io/index calibration/index media/index + media/device vi/index diff --git a/doc/source/api/io/index.rst b/doc/source/api/io/index.rst index 1153b9c4e..47500e086 100644 --- a/doc/source/api/io/index.rst +++ b/doc/source/api/io/index.rst @@ -1 +1,21 @@ -.. automodule:: skrf.io +IO +== + +This Package provides functions and objects for input/output. + +The general functions :func:`~general.read` and :func:`~general.write` +can be used to read and write [almost] any skrf object to disk, using the +:mod:`pickle` module. + +Reading and writing touchstone files is supported through the +:class:`~touchstone.Touchstone` class, which can be more easily used +through the Network constructor, :func:`~skrf.network.Network.__init__` + +.. automodule:: skrf.io.general + +.. automodule:: skrf.io.touchstone + +.. automodule:: skrf.io.csv + + + diff --git a/doc/source/api/media/device.rst b/doc/source/api/media/device.rst new file mode 100644 index 000000000..4920cf851 --- /dev/null +++ b/doc/source/api/media/device.rst @@ -0,0 +1,5 @@ +.. automodule:: skrf.media.device + + + + diff --git a/doc/source/api/media/index.rst b/doc/source/api/media/index.rst index 1d5da17e3..3c1c116ea 100644 --- a/doc/source/api/media/index.rst +++ b/doc/source/api/media/index.rst @@ -1 +1,20 @@ +Media +===== .. automodule:: skrf.media + + +Transmission Line Classes +------------------------- + +.. autosummary:: + :toctree: generated/ + + ~media.DefinedGammaZ0 + ~distributedCircuit.DistributedCircuit + ~rectangularWaveguide.RectangularWaveguide + ~cpw.CPW + ~coaxial.Coaxial + ~mline.MLine + ~freespace.Freespace + ~definedAEpTandZ0.DefinedAEpTandZ0 + diff --git a/doc/source/api/media/media.rst b/doc/source/api/media/media.rst deleted file mode 100644 index 930a4c9b3..000000000 --- a/doc/source/api/media/media.rst +++ /dev/null @@ -1 +0,0 @@ -.. automodule:: skrf.media.media diff --git a/doc/source/api/touchstone.rst b/doc/source/api/touchstone.rst deleted file mode 100644 index f4630f69e..000000000 --- a/doc/source/api/touchstone.rst +++ /dev/null @@ -1 +0,0 @@ -.. automodule:: skrf.touchstone diff --git a/doc/source/conf.py b/doc/source/conf.py index f2246dde6..5bde2578d 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,77 +1,82 @@ -# -*- coding: utf-8 -*- # -# skrf documentation build configuration file, created by -# sphinx-quickstart on Sun Aug 21 15:10:05 2011. +# scikit-rf (aka skrf) documentation build configuration file # -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. + +# -- Project information ----------------------------------------------------- + +project = 'scikit-rf' +copyright = '2020, scikit-rf team' +author = 'scikit-rf team' + +# -- General configuration --------------------------------------------------- import sys, os import sphinx_rtd_theme - +import nbsphinx import warnings warnings.filterwarnings('ignore') + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('../../')) -# -- General configuration ----------------------------------------------------- +import skrf as rf +rf.setup_pylab() -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.3' +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. -#from subprocess import call -#call(['make','notebooks']) # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. sys.path.insert(0, os.path.abspath('../sphinxext')) -import skrf as rf -rf.setup_pylab() - extensions = [ - #'notebook_sphinxext_alex', 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', - #'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'nbsphinx', - #'numpydoc', #'inheritance_diagram', 'IPython.sphinxext.ipython_directive', 'IPython.sphinxext.ipython_console_highlighting', ] -import nbsphinx +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_init_with_doc = False +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True + +# NBsphinx settings nbsphinx_execute = 'always' -nbsphinx_allow_errors=True -nbsphinx_kernel_name='python' +nbsphinx_allow_errors = True +nbsphinx_kernel_name = 'python' numpydoc_show_class_members = False nbsphinx_timeout = 120 + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' -# The encoding of source files. -#source_encoding = 'utf-8-sig' - # The master toctree document. master_doc = 'index' -# General information about the project. -project = u'scikit-rf' -copyright = u'2017, scikit-rf development team' +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', "**/*.rst.rst", '**.ipynb_checkpoints'] # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -87,49 +92,15 @@ break ''' -# The full version, including alpha/beta/rc tags. -#release = version - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. - -exclude_patterns = ["**/*.rst.rst", '**.ipynb_checkpoints'] -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -#html_style = 'scipy.css' + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -150,6 +121,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = 'scikit-rf-logo-flat.svg' +#html_logo = '_static/scikit-rf-logo-flat-docs.svg' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -160,47 +132,6 @@ # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -#html_logo = '_static/scikit-rf-logo-flat-docs.svg' -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'skrfdoc' @@ -217,8 +148,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'scikit-rf.tex', u'scikit-rf Documentation', - u'scikit-rf Developers', 'manual'), + ('index', 'scikit-rf.tex', 'scikit-rf Documentation', + 'scikit-rf Developers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -236,7 +167,7 @@ #latex_show_urls = False # Additional stuff for the LaTeX preamble. -latex_preamble = '\usepackage{epstopdf}' +latex_preamble = r'\usepackage{epstopdf}' # Documents to append as an appendix to all manuals. #latex_appendices = [] @@ -244,14 +175,15 @@ # If false, no module index is generated. #latex_domain_indices = True -autosummary_generate=True +autosummary_generate = True + # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'scikit-rf', u'scikit-rf Documentation', - [u'alex arsenovic'], 1) + ('index', 'scikit-rf', 'scikit-rf Documentation', + ['alex arsenovic'], 1) ] diff --git a/doc/source/examples/circuit/Mixed Mode S and Impedance Transformation.ipynb b/doc/source/examples/circuit/Mixed Mode S and Impedance Transformation.ipynb index 040773448..9b5d89c32 100644 --- a/doc/source/examples/circuit/Mixed Mode S and Impedance Transformation.ipynb +++ b/doc/source/examples/circuit/Mixed Mode S and Impedance Transformation.ipynb @@ -6,9 +6,9 @@ "source": [ "# Mixed Mode S-Parameters & Impedance Transformation\n", "\n", - "Mini-circuits [EP2C+](https://www.minicircuits.com/pdfs/EP2C+.pdf) is a 1.8 to 12.5 GHz MMIC based splitter/combiner. The s-parameters provided by Mini-circuits are single-ended. For this example, the single-ended s-parameters will be converted to mixed mode s-parameters so that the common mode gain (the gain from the common port to the common mode terminated in 25 ohms) can be examined. Additionally, the differential mode gain (the gain from the common port to the differential mode terminated in 100 ohms) can be plotted. It is expected that the differntial mode gain should be well below the common mode gain since this is a 0 degree splitter/combiner.\n", + "Mini-circuits [EP2C+](https://www.minicircuits.com/pdfs/EP2C+.pdf) is a 1.8 to 12.5 GHz MMIC based splitter/combiner. The s-parameters provided by Mini-circuits are single-ended. For this example, the single-ended s-parameters will be converted to mixed mode s-parameters so that the common mode gain (the gain from the common port to the common mode terminated in 25 Ω) can be examined. Additionally, the differential mode gain (the gain from the common port to the differential mode terminated in 100 Ω) can be plotted. It is expected that the differential mode gain should be well below the common mode gain since this is a 0 degree splitter/combiner.\n", "\n", - "Lastly, since it is desired to use this network in a cascade analysis as a 2-port block in a 50 ohm environment, the differential mode will be terminated in 100 ohms and a 50 ohm port transformed to 25 ohms will be connected to the common mode port:\n", + "Lastly, since it is desired to use this network in a cascade analysis as a 2-port block in a 50 Ω environment, the differential mode will be terminated in 100 Ω and a 50 Ω port transformed to 25 Ω will be connected to the common mode port:\n", "\n", "![](mixed_mode.png)" ] @@ -55,9 +55,7 @@ "fig,ax1 = plt.subplots(1)\n", "mm_ntwk.plot_s_db(1,0,label='Differential Mode Gain',ax=ax1)\n", "mm_ntwk.plot_s_db(2,0,label='Common Mode Gain',ax=ax1)\n", - "ax1.set_title('Mixed Mode Gain')\n", - "\n", - "print(mm_ntwk)" + "ax1.set_title('Mixed Mode Gain')" ] }, { @@ -69,18 +67,21 @@ "# create a 25 to 50 ohm transformer\n", "\n", "# turns ratio\n", - "n = 2\n", + "n = np.sqrt(2)\n", "\n", "# ABCD Parameters\n", "a = np.array([[n, 0], [0, 1/n]])[np.newaxis, :, :]\n", - "abcd = np.tile(a, [freq.npoints, 1, 1])\n", + "abcd = np.tile(a, [freq.npoints,1,1])\n", "\n", "transformer = skrf.Network(name='transformer',frequency=freq)\n", "transformer.s = skrf.a2s(abcd, z0=[50, 50])\n", "\n", "# connect the transformer to the common mode port\n", - "# common mode port impedance transformed from 50 ohms to 25 ohms\n", - "mm_ntwk_t = skrf.connect(mm_ntwk,2,transformer,1)" + "# common mode port impedance transformed from 50 Ω to 25 Ω\n", + "mm_ntwk_t = skrf.connect(mm_ntwk,2,transformer,1)\n", + "\n", + "# skrf.connect() re-ordered the ports. Change them back so they are consistent with the schematic above.\n", + "mm_ntwk_t.renumber([0,1,2],[0,2,1])" ] }, { @@ -89,16 +90,16 @@ "metadata": {}, "outputs": [], "source": [ - "# create a 100 ohm termination\n", + "# create a 100 Ω termination\n", "term = skrf.Network(name='100 ohm termination',z0=100,\n", " s=np.zeros([mm_ntwk.frequency.npoints]),\n", " frequency=mm_ntwk.frequency)\n", "\n", - "# connect the 100 ohm termination to the differential mode port\n", + "# connect the 100 Ω termination to the differential mode port\n", "mm_ntwk_2port = skrf.connect(mm_ntwk_t,1,term,0)\n", "\n", "fig,ax2 = plt.subplots(1)\n", - "mm_ntwk.plot_s_db(1,0,label='from 3-Port',ax=ax2,marker='o',lw=0,markersize=5)\n", + "mm_ntwk.plot_s_db(2,0,label='from 3-Port',ax=ax2,marker='o',lw=1,markersize=5)\n", "mm_ntwk_2port.plot_s_db(1,0,label='from 2-Port',ax=ax2)\n", "\n", "ax2.set_title('Common Mode Gain');" @@ -111,7 +112,7 @@ "outputs": [], "source": [ "# compare the common mode gain of the impedance transformed 2-port to the mixed-mode untransformed 3-port\n", - "complex_diff = np.abs(mm_ntwk_2port.s[:,1,0] - mm_ntwk.s[:,1,0])\n", + "complex_diff = np.abs(mm_ntwk_2port.s[:,1,0] - mm_ntwk.s[:,2,0])\n", "\n", "# don't give warning for -inf\n", "complex_diff[complex_diff==0] = np.nan\n", @@ -139,7 +140,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.7" } }, "nbformat": 4, diff --git a/doc/source/examples/circuit/Voltages and Currents in Circuits.ipynb b/doc/source/examples/circuit/Voltages and Currents in Circuits.ipynb new file mode 100644 index 000000000..9e6304a25 --- /dev/null +++ b/doc/source/examples/circuit/Voltages and Currents in Circuits.ipynb @@ -0,0 +1,460 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Voltages and Currents in Circuits\n", + "The scikit-rf `Circuit` object allows one to deduce the voltages and currents at all the intersections of the circuit for a given power (and phase) excitation at circuit's ports. Here, few examples are examined, in order to clarifiy the conventions used for current directions. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# standard imports\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import skrf as rf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rf.stylely()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A simple transmission line\n", + "To start, let's assume a simple transmission line excited by a generator. Let's assume the generator is matched to the line ($Z_s=Z_0$) and the line connected to a matched load ($Z_0=Z_L$), all 50 Ohm. \n", + "\n", + "![](circuit_vi_simple_line.svg)\n", + "\n", + "What is the RF currents and voltages at the input and output of this line for a given input power (and phase)?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "P_f = 1 # forward power in Watt\n", + "Z = 50 # source internal impedance, line characteristic impedance and load impedance\n", + "L = 10 # line length in [m]\n", + "\n", + "freq = rf.Frequency(2, 2, 1, unit='GHz')\n", + "line_media = rf.media.DefinedGammaZ0(freq, z0=Z) # lossless line medium\n", + "line = line_media.line(d=L, unit='m', name='line') # transmisison line Network" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Assuming the source generates an input power of $P_f$ with a phase $\\phi$, with such a line the voltage and current at the entrance of the line are:\n", + "\n", + "$$\n", + "V_{in} = \\sqrt{2 Z_0 P_f} e^{j \\phi}\n", + "$$\n", + "\n", + "$$\n", + "I_{in} = \\sqrt{2 \\frac{P_f}{Z_0}} e^{j \\phi}\n", + "$$\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "V_in = np.sqrt(2*Z*P_f)\n", + "I_in = np.sqrt(2*P_f/Z)\n", + "print(f'Input voltage and current: {V_in} V and {I_in} A')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The voltage and current evolve along the transmission line. The voltage and current at the output of the line can be calculated using the transmission line tools provided with scikit-rf:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "theta = rf.theta(line_media.gamma, freq.f, L) # electrical length \n", + "V_out, I_out = rf.tlineFunctions.voltage_current_propagation(V_in, I_in, Z, theta)\n", + "print(f'Output voltage and current: {V_out} V and {I_out} A')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's perform the same calculation using `Circuit`. First, one needs to define the circuit, that is to create input/output ports and to connect these ports to the transmission line Network we've already created. Then, we can build the circuit: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "port1 = rf.Circuit.Port(frequency=freq, name='port1', z0=50)\n", + "port2 = rf.Circuit.Port(frequency=freq, name='port2', z0=50)\n", + "cnx = [\n", + " [(port1, 0), (line, 0)],\n", + " [(port2, 0), (line, 1)]\n", + "]\n", + "crt = rf.Circuit(cnx)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It's always a good practice to check if the circuit's graph is as expected. In this case, the graph is pretty simple: 2 ports connected to a 2-ports Network. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "crt.plot_graph(network_labels=True, edge_labels=True, inter_labels=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`Circuit` provides two methods to determine voltages and currents at the circuit input/output ports (also known as \"external ports\"). These methods take as input the power and phase inputs at each ports:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "power = [1, 0] # 1 Watt at port1 and 0 at port2\n", + "phase = [0, 0] # 0 radians" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "V_at_ports = crt.voltages_external(power, phase)\n", + "print(V_at_ports)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "I_at_ports = crt.currents_external(power, phase)\n", + "print(I_at_ports)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The results are similar to the previous, except the sign of the current at port2 which is reversed. \n", + "\n", + "This is normal, as the `currents_external()` method defines the positive direction of a current as the direction which \"enters\" into the circuit. More details about this convention at the bottom of this example." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A coaxial T with different characteistic impedances\n", + "As a more advanced example, we've built in a full-wave software (here ANSYS HFSS, but other are fine too) the following structure: a coaxial T, defined with different coaxial cross-sections (and such different characteristic impedances). \n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All the three ports are excited with different power and phase to complicate a bit, as the following:\n", + "\n", + "| port | power [W] | phase [deg] |\n", + "| --- | --- | --- |\n", + "| #1 | 1 | -10 |\n", + "| #2 | 2 | -20 |\n", + "| #3 | 3 | +60 |\n", + "\n", + "### Full-wave reference solution\n", + "The voltages and currents are evaluated in the full-wave software directly. Voltage is obtained by integrating the E fields along a straight line going from the inner to the outer conductors in the port's cross-sections. Current is obtained by integrating the H fields along a circle enclosing the inner conductor in port's cross-sectionos. Note the circles are directed in order to define the positive current direction as the direction inward the ports (right-hand rule). \n", + "\n", + "The full-wave solutions are given here for reference, at 3 frequencies:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd # convenient to read .csv files\n", + "pd.read_csv('circuit_vi_HFSS_Voltages.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pd.read_csv('circuit_vi_HFSS_Currents.csv')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### In a Circuit simulator\n", + "The voltages and currents can also be derived using a Circuit simulator, like for example:\n", + "\n", + "\n", + "\n", + "(where, again, the current probes are oriented in such a way that the current is positive when flowing in the Network). This gives essentially the same results:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pd.read_csv('circuit_vi_Designer_Voltages.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pd.read_csv('circuit_vi_Designer_Currents.csv')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### With `Circuit`\n", + "Now let's build the same circuit with scikit-rf `Circuit`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Importing the 3-port .s3p file exported from full-wave simulation\n", + "coaxial_T = rf.Network('circuit_vi_Coaxial_T.s3p')\n", + "# pay attention to the port's characteristic impedance\n", + "# it should match the Network characteric impedances otherwise this will generate mismatches \n", + "port1 = rf.Circuit.Port(coaxial_T.frequency, 'port1', coaxial_T.z0[:,0])\n", + "port2 = rf.Circuit.Port(coaxial_T.frequency, 'port2', coaxial_T.z0[:,1])\n", + "port3 = rf.Circuit.Port(coaxial_T.frequency, 'port3', coaxial_T.z0[:,2])\n", + "# connexion list\n", + "cnx = [\n", + " [(port1, 0), (coaxial_T, 0)],\n", + " [(port2, 0), (coaxial_T, 1)],\n", + " [(port3, 0), (coaxial_T, 2)]\n", + "]\n", + "# building the circuit\n", + "crt = rf.Circuit(cnx)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# let's check if our connexion list is correctly defined\n", + "crt.plot_graph(network_labels=True, edge_labels=True, inter_labels=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The voltages and currents at the ports for the given excitation is:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "power = [1, 2, 3] # input power in watts at ports 1, 2 and 3\n", + "phase = np.deg2rad([-10, -20, +60]) # input phase in rad at ports 1, 2 and 3\n", + "\n", + "voltages = crt.voltages_external(power, phase)\n", + "currents = crt.currents_external(power, phase)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# just for a better rendering in the notebook \n", + "pd.concat([\n", + " pd.DataFrame(np.abs(voltages), columns=['mag V1', 'mag V2', 'mag V3'], index=crt.frequency.f/1e6),\n", + " pd.DataFrame(np.angle(voltages, deg=True), columns=['Phase V1', 'Phase V2', 'Phase V3'], index=crt.frequency.f/1e6)\n", + "], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# just for a better rendering in the notebook \n", + "pd.concat([\n", + " pd.DataFrame(np.abs(currents), columns=['mag I1', 'mag I2', 'mag I3'], index=crt.frequency.f/1e6),\n", + " pd.DataFrame(np.angle(currents, deg=True), columns=['Phase I1', 'Phase I2', 'Phase I3'], index=crt.frequency.f/1e6)\n", + "], axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These results matches well the one given by the full-wave calculations, hourra. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## external vs internal ports? \n", + "You have maybe noticed in the `Circuit` documentation that we often talk about \"internal\" or \"inner\" ports, and of \"external\" or \"outer\" ports. The external ports corresponds to the `Circuit.Port()` Networks defined when building a `Circuit`. The internal ports are all the other connexions inside the `Circuit`\n", + "\n", + "The `Circuit` algorythm allows one to have access to the voltages and current at the internal connexions inside the circuit. In the previous examples, there is not too much internal ports as we've connected a N-port directly to external ports. However, in more complex usages we can have a lot (look to the other `Circuit` examples).\n", + "\n", + "In `Circuit`, voltages and currents are peak values. While voltages are defined in a non-ambiguous manner, positive currents can be defined in a way or another, leading to a 180 degree ambiguity. To solve this, we have choosen the following definition: internal currents are defined such as they are measured positive when flowing into Networks. \n", + "\n", + "Hence, you find that \"external\" current are sign opposite of \"internal\" ones at the corresponding ports, because the internal currents are actually flowing into the ports Networks." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# internals currents (currents at all connexions)\n", + "# in this example, there are 6 internal connexions (3 pairs of connexions)\n", + "crt.currents(power, phase)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This gives the indices of the \"external\" ports\n", + "crt.port_indexes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# So we can keep only \"external\" ports\n", + "crt.currents(power, phase)[:, crt.port_indexes]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# note the sign difference due to the convention choosen for internal ports\n", + "crt.currents_external(power, phase)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The figure below illustrates these differences using the previous example:\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/doc/source/examples/circuit/Wilkinson Power Splitter.ipynb b/doc/source/examples/circuit/Wilkinson Power Splitter.ipynb index 36cacca9a..75a336595 100644 --- a/doc/source/examples/circuit/Wilkinson Power Splitter.ipynb +++ b/doc/source/examples/circuit/Wilkinson Power Splitter.ipynb @@ -122,6 +122,144 @@ "fig.suptitle('Ideal Wilkinson Divider @ 1 GHz')" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Currents and Voltages\n", + "Is is possible to calculate currents and voltages at the Circuit's internals ports. However, if you try with this specific example, one obtains: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "power = [1,0,0]\n", + "phase = [0,0,0]\n", + "C.voltages(power, phase) # or C.currents(power, phase)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This situation is \"normal\", in the sense that the voltages and currents calculation methods does not support the case of more than 2 ports are connected together, which is the case in this example, as we have defined the connection list:\n", + "\n", + "```\n", + "connections = [\n", + " [(port1, 0), (branch1, 0), (branch2, 0)],\n", + " [(port2, 0), (branch1, 1), (resistor, 0)],\n", + " [(port3, 0), (branch2, 1), (resistor, 1)]\n", + " ]\n", + "```\n", + "\n", + "However, note that the voltages and currents calculations at external ports works:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C.voltages_external(power, phase) # or C.currents_external(power, phase)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But there is hope! It is possible to calculate the internal voltages and currents of the circuit using intermediate splitting Networks. In our case, one needs three \"T\" Networks and to make only pair of connections: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tee1 = line_branches.tee(name='tee1')\n", + "tee2 = line_branches.tee(name='tee2')\n", + "tee3 = line_branches.tee(name='tee3')\n", + "\n", + "cnx = [\n", + " [(port1, 0), (tee1, 0)],\n", + " [(tee1, 1), (branch1, 0)],\n", + " [(tee1, 2), (branch2, 0)],\n", + " [(branch1, 1), (tee2, 0)],\n", + " [(branch2, 1), (tee3, 0)],\n", + " [(tee2, 2), (resistor, 0)],\n", + " [(tee3, 2), (resistor, 1)],\n", + " [(tee3, 1), (port3, 0)],\n", + " [(tee2, 1), (port2, 0)], \n", + "]\n", + "C2 = rf.Circuit(cnx)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The resulting graph is a bit more stuffed:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C2.plot_graph(network_labels=True, edge_labels=True, port_labels=True, port_fontize=2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But the results are the same:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax1,ax2) = plt.subplots(2, 1, sharex=True)\n", + "C2.network.plot_s_db(ax=ax1, m=0, n=0, lw=2) # S11\n", + "C2.network.plot_s_db(ax=ax1, m=1, n=1, lw=2) # S22\n", + "ax1.set_ylim(-90, 0)\n", + "C2.network.plot_s_db(ax=ax2, m=1, n=0, lw=2) # S21\n", + "C2.network.plot_s_db(ax=ax2, m=2, n=0, ls='--', lw=2) # S31\n", + "ax2.set_ylim(-4, 0)\n", + "fig.suptitle('Ideal Wilkinson Divider (2nd way) @ 1 GHz')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And this time one can calculate internal voltages and currents:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "C2.voltages(power, phase) # or C2.currents(power, phase)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You will find more details on voltages and currents calculation on the dedicated example." + ] + }, { "cell_type": "code", "execution_count": null, @@ -146,7 +284,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.6" + "version": "3.7.8" } }, "nbformat": 4, diff --git a/doc/source/examples/circuit/circuit_vi_Coaxial_T.s3p b/doc/source/examples/circuit/circuit_vi_Coaxial_T.s3p new file mode 100644 index 000000000..3c8c5c3d3 --- /dev/null +++ b/doc/source/examples/circuit/circuit_vi_Coaxial_T.s3p @@ -0,0 +1,34 @@ +! Touchstone file exported from HFSS 2020.2.0 +! File: C:/Users/JH218595/Documents/Modeling/skrf_current_voltage_benchmark/current_voltage_benchmark.aedt +! Generated: 3:05:47 ao%xFBt 06, 2020 +! Design: Coaxial T +! Project: current_voltage_benchmark +! Setup: Setup1 +! Solution: LastAdaptive +! +! Variables: +! L = 3000mm +! Pin = 500kW +! Pref = 300kW +! +!Data is not renormalized +# GHZ S MA +! Terminal data exported +! Port[1] = 1 +! Port[2] = 2 +! Port[3] = 3 +0.01 0.320842043701007 148.551878810503 0.810274252637408 -35.7137843917257 0.490155334795591 -22.1576640369248 + 0.810274252637407 -35.7137843917257 0.0366505674584357 167.915339991294 0.58467654397948 -23.6351577265636 + 0.490155334795591 -22.1576640369248 0.58467654397948 -23.6351577265636 0.646356331452381 171.311060820221 +! Gamma 4.39118159915976E-05 0.209628424919554 5.5202640364583E-05 0.209639719464457 2.85609462621175E-05 0.209613068720395 +! Port Impedance 42.5668754272387 -0.00890159842753428 29.7768812434469 -0.00783825021061899 81.5297414141364 -0.011075836989305 +0.05 0.28562283467114 22.5085051437231 0.820259159107778 -178.777398058005 0.494976553183397 -110.994402953149 + 0.820259159107778 -178.777398058005 0.0954574908029948 42.8241589414672 0.563437388934213 -117.797291852353 + 0.494976553183397 -110.994402953149 0.563437388934213 -117.797291852353 0.661259050076044 136.19010588335 +! Gamma 9.8203337333854E-05 1.048020725275 0.000123454951206083 1.04804598055049 6.38711775867175E-05 1.04798638779204 +! Port Impedance 42.5619492690417 -0.00397693092854242 29.7725447770903 -0.00350343494173246 81.5236181381169 -0.00495377062966894 +0.1 0.178288179734708 -135.564599445407 0.843748941011795 1.2586296960786 0.505424168088701 136.765848514915 + 0.843748941011795 1.2586296960786 0.181618968248254 -155.946119519778 0.504209459036608 126.929755474624 + 0.505424168088701 136.765848514915 0.504209459036608 126.929755474624 0.699967464629951 90.4862842143751 +! Gamma 0.000138885068213894 2.09598391796435 0.000174597755567374 2.09601963430039 9.03298831431644E-05 2.09593535743367 +! Port Impedance 42.5607745205549 -0.00280236845949581 29.7715131160175 -0.00247198004554454 81.5221674134439 -0.00350319857488833 diff --git a/doc/source/examples/circuit/circuit_vi_Designer_Currents.csv b/doc/source/examples/circuit/circuit_vi_Designer_Currents.csv new file mode 100644 index 000000000..4e8b2d280 --- /dev/null +++ b/doc/source/examples/circuit/circuit_vi_Designer_Currents.csv @@ -0,0 +1,4 @@ +"Freq [MHz]","mag(I(I1)) [A]","mag(I(I2)) [A]","mag(I(I3)) [A]","ang_deg(I(I1)) [deg]","ang_deg(I(I2)) [deg]","ang_deg(I(I3)) [deg]" +10,0.0214810124469517,0.13777879825071,0.509420567665561,156.253941081199,-90.8929769388606,80.2296046884693 +50,0.274448031462288,0.389874936457774,0.619154733591792,2.59972659357075,6.28666080348593,44.6741951102422 +100,0.219239419059839,0.423718081047774,0.381924745283975,33.8367265492274,-8.15295711800169,-4.33332799281655 diff --git a/doc/source/examples/circuit/circuit_vi_Designer_Voltages.csv b/doc/source/examples/circuit/circuit_vi_Designer_Voltages.csv new file mode 100644 index 000000000..b641a4187 --- /dev/null +++ b/doc/source/examples/circuit/circuit_vi_Designer_Voltages.csv @@ -0,0 +1,4 @@ +"Freq [MHz]","mag(V(V1)) [V]","mag(V(V2)) [V]","mag(V(V3)) [V]","ang_deg(V(V1)) [deg]","ang_deg(V(V2)) [deg]","ang_deg(V(V3)) [deg]" +10,19.3429848104376,20.8490544010339,15.2900357998877,-10.6441503071867,-9.28326205552252,-9.8706253129539 +50,7.4994115583165,12.5226808775514,14.0649613035433,-29.8543000052229,-44.2300837569486,168.423656993655 +100,13.3858094825219,9.82815819908875,41.6311386950269,-38.8664368173431,-35.2721305456684,102.384692630193 diff --git a/doc/source/examples/circuit/circuit_vi_Designer_circuit.png b/doc/source/examples/circuit/circuit_vi_Designer_circuit.png new file mode 100644 index 000000000..670f2ad24 Binary files /dev/null and b/doc/source/examples/circuit/circuit_vi_Designer_circuit.png differ diff --git a/doc/source/examples/circuit/circuit_vi_HFSS_Coaxial_T.png b/doc/source/examples/circuit/circuit_vi_HFSS_Coaxial_T.png new file mode 100644 index 000000000..03ca5ca26 Binary files /dev/null and b/doc/source/examples/circuit/circuit_vi_HFSS_Coaxial_T.png differ diff --git a/doc/source/examples/circuit/circuit_vi_HFSS_Currents.csv b/doc/source/examples/circuit/circuit_vi_HFSS_Currents.csv new file mode 100644 index 000000000..893cf1d1f --- /dev/null +++ b/doc/source/examples/circuit/circuit_vi_HFSS_Currents.csv @@ -0,0 +1,4 @@ +"Phase [deg]","Freq [MHz]","mag(I1) [A]","mag(I2) [A]","mag(I3) [A]","ang_deg(I1) [deg]","ang_deg(I2) [deg]","ang_deg(I3) [deg]" +0,10,0.0215914352034971,0.137606187819752,0.512142182574511,156.244427305975,-90.890033727616,80.2249708067984 +0,50,0.275976429644053,0.389991181742925,0.622468573003606,2.59666791270362,6.31782561250411,44.6725845103223 +0,100,0.220526242759198,0.424061155827657,0.384085390498598,33.8335929011538,-8.08797069640794,-4.33108656186798 diff --git a/doc/source/examples/circuit/circuit_vi_HFSS_Voltages.csv b/doc/source/examples/circuit/circuit_vi_HFSS_Voltages.csv new file mode 100644 index 000000000..c780a58c2 --- /dev/null +++ b/doc/source/examples/circuit/circuit_vi_HFSS_Voltages.csv @@ -0,0 +1,4 @@ +"Phase [deg]","Freq [MHz]","mag(V1) [V]","mag(V2) [V]","mag(V3) [V]","ang_deg(V1) [deg]","ang_deg(V2) [deg]","ang_deg(V3) [deg]" +0,10,19.3337375946237,20.8460312806295,15.2721997104635,-10.6501771634093,-9.28947388310908,-9.87741253464379 +0,50,7.49588848950888,12.5203794010283,14.0483129763389,-29.8552893135819,-44.2333390540522,168.419883839628 +0,100,13.3785409610901,9.82592143015406,41.5810577645372,-38.8699644202405,-35.2756517695692,102.383085703918 diff --git a/doc/source/examples/circuit/circuit_vi_convention_currents.png b/doc/source/examples/circuit/circuit_vi_convention_currents.png new file mode 100644 index 000000000..dee51f218 Binary files /dev/null and b/doc/source/examples/circuit/circuit_vi_convention_currents.png differ diff --git a/doc/source/examples/circuit/circuit_vi_simple_line.svg b/doc/source/examples/circuit/circuit_vi_simple_line.svg new file mode 100644 index 000000000..56d68f72d --- /dev/null +++ b/doc/source/examples/circuit/circuit_vi_simple_line.svg @@ -0,0 +1,649 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + Z + s + + Source + + + + + + + + + P + f + + + + + + + + + + + + + + + + 0 + γ ,Z + θ + line + Line delay + + + + + + + + + + 0 + γ ,Z + θ + + Line delay + + + + + + + + + + + + + + + + + + Z + L + + Load + + + + + + + + + diff --git a/doc/source/examples/index.rst b/doc/source/examples/index.rst index c4d218be1..318be0aee 100644 --- a/doc/source/examples/index.rst +++ b/doc/source/examples/index.rst @@ -69,7 +69,15 @@ Internals :glob: internals/* - + +Instrument Control +------------------ +.. toctree:: + :maxdepth: 1 + :glob: + + instrumentcontrol/* + Interactive ------------------ diff --git a/doc/source/tutorials/LNA Example.ipynb b/doc/source/examples/networktheory/LNA Example.ipynb similarity index 99% rename from doc/source/tutorials/LNA Example.ipynb rename to doc/source/examples/networktheory/LNA Example.ipynb index d0bd775dc..f1f312023 100644 --- a/doc/source/tutorials/LNA Example.ipynb +++ b/doc/source/examples/networktheory/LNA Example.ipynb @@ -4,6 +4,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "# LNA Example\n", + "\n", "Let's design a LNA using Infineon's BFU520 transistor. First we need to import scikit-rf and a bunch of other utilities:" ] }, @@ -323,7 +325,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.5" + "version": "3.7.7" } }, "nbformat": 4, diff --git a/doc/source/examples/networktheory/Rational Interpolation.ipynb b/doc/source/examples/networktheory/Rational Interpolation.ipynb index 3426759c8..bfe0a0860 100644 --- a/doc/source/examples/networktheory/Rational Interpolation.ipynb +++ b/doc/source/examples/networktheory/Rational Interpolation.ipynb @@ -18,6 +18,15 @@ "Example:" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline" + ] + }, { "cell_type": "code", "execution_count": null, @@ -28,10 +37,15 @@ "import matplotlib.pyplot as plt\n", "from skrf.plotting import stylely\n", "from skrf.media import Coaxial\n", - "\n", - "%matplotlib inline\n", - "stylely()\n", - "\n", + "stylely()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "freq = skrf.F(0.5,110,801)\n", "freq2 = skrf.F(0,110,801)\n", "coax1mm = Coaxial(freq, z0=50, Dint=0.44e-3, Dout=1.0e-3, sigma=1e20)\n", @@ -51,30 +65,49 @@ "dut_dc_linear = dut.extrapolate_to_dc(kind='linear', dc_sparam=[[0,1],[1,0]])\n", "dut_dc_linear.name = 'linear'\n", "dut_dc_cubic = dut.extrapolate_to_dc(kind='cubic', dc_sparam=[[0,1],[1,0]])\n", - "dut_dc_cubic.name = 'cubic'\n", - "\n", + "dut_dc_cubic.name = 'cubic'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "plt.figure()\n", "plt.title('Step Response Lowpass')\n", "dut2.s11.plot_s_time_step(pad=2000, window='hamming')\n", "dut_dc_rational.s11.plot_s_time_step(pad=2000, window='hamming')\n", "dut_dc_linear.s11.plot_s_time_step(pad=2000, window='hamming')\n", - "dut_dc_cubic.s11.plot_s_time_step(pad=2000, window='hamming')\n", - "\n", + "dut_dc_cubic.s11.plot_s_time_step(pad=2000, window='hamming')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "plt.figure()\n", "plt.title('Impulse Response Lowpass')\n", "dut2.s11.plot_s_time_impulse(pad=2000, window='hamming')\n", "dut_dc_rational.s11.plot_s_time_impulse(pad=2000, window='hamming')\n", "dut_dc_linear.s11.plot_s_time_impulse(pad=2000, window='hamming')\n", - "dut_dc_cubic.s11.plot_s_time_impulse(pad=2000, window='hamming')\n", - "\n", + "dut_dc_cubic.s11.plot_s_time_impulse(pad=2000, window='hamming')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "plt.figure()\n", "plt.title('Impulse Response Bandpass')\n", "dut2.s11.plot_s_time(pad=2000, window='hamming')\n", "(dut_dc_rational.s11.windowed()).plot_s_time()\n", "(dut_dc_linear.s11.windowed()).plot_s_time()\n", - "(dut_dc_cubic.s11.windowed()).plot_s_time()\n", - "\n", - "plt.show(block=True)" + "(dut_dc_cubic.s11.windowed()).plot_s_time()" ] }, { @@ -102,6 +135,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", + "version": "3.7.7" }, "toc": { "nav_menu": {}, diff --git a/doc/source/skrf_Network_symbols.svg b/doc/source/skrf_Network_symbols.svg index a11c7da7c..8dd9bd200 100644 --- a/doc/source/skrf_Network_symbols.svg +++ b/doc/source/skrf_Network_symbols.svg @@ -1,6 +1,4 @@ - - + version="1.1" + viewBox="0 0 519.87408 188.13292" + height="188.13292mm" + width="519.87408mm"> + refY="0" + refX="0" + id="marker5555" + style="overflow:visible" + inkscape:isstock="true"> + d="M 0,0 5,-5 -12.5,0 5,5 Z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(0.2,0,0,0.2,1.2,0)" /> + + + + refY="0" + refX="0" + id="marker12733" + style="overflow:visible" + inkscape:isstock="true"> + + + + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> + id="path5141" /> + id="path5144" /> + inkscape:isstock="true"> + inkscape:isstock="true"> - - - - - - + inkscape:window-height="1057" + inkscape:window-width="1920" + fit-margin-bottom="0" + fit-margin-right="0" + fit-margin-left="0" + fit-margin-top="0" + showgrid="false" + inkscape:current-layer="layer1" + inkscape:document-units="mm" + inkscape:cy="438.07" + inkscape:cx="1572.2711" + inkscape:zoom="0.49497475" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" /> @@ -176,672 +175,778 @@ + inkscape:groupmode="layer" + inkscape:label="Calque 1"> + transform="translate(-195.88704,-15.941279)" + id="g1750-7"> + width="41.357685" + height="38.711853" + x="62.75367" + y="29.982033" /> + cx="54.510117" + cy="35.030067" + r="1.1575521" /> - + cx="54.56134" + id="circle10783-6-2" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + + transform="matrix(1.4001426,0,0,1.4001426,-5.3828311,18.903646)" + id="g10764-0-8"> Z + x="62.699265" + y="22.861202" + style="stroke-width:1">Z L + x="66.820099" + id="tspan10756-1-6" + sodipodi:role="line">L Load + x="74.16803" + y="25.268456" + style="stroke-width:0.20199829px">Load + style="stroke-width:1.36991799;stroke-miterlimit:4;stroke-dasharray:none"> + d="M 4.4370386,836.41665 H 21" + id="path5497-5" + inkscape:connector-curvature="0" /> + d="M 55.999996,836.41665 H 84.64549" + id="path5499-9" + inkscape:connector-curvature="0" /> + width="34.999996" + height="13.999982" + x="21.000002" + y="829.41669" /> + id="path5545-6" + d="M 76.57946,35.03007 H 69.44979" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + transform="translate(-10.265402,-69.344541)" + id="g1906"> - + + cx="23.337408" + cy="191.58795" + r="1.1575521" /> + id="path1824" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> Shunted Shunted inductor + y="153.54039" + x="52.027096" + sodipodi:role="line">inductor + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="path1854" + inkscape:connector-curvature="0" /> + style="fill:#2c4d29;fill-opacity:1;stroke:none;stroke-width:0.45546275;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> L + x="62.699265" + id="tspan1856" + sodipodi:role="line">L + x="66.820099" + y="28.45998" /> + cy="-191.58795" + cx="-76.800652" + id="circle1876" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path1878-5" + d="M 43.263056,191.58795 H 76.29353" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="23.337408" + id="circle1880" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path1882-6" + d="M 45.890075,161.8988 H 23.844534" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="-76.800652" + cy="-161.89879" + r="1.1575521" + transform="scale(-1)" /> + id="path1886-2" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + id="g2034" + transform="translate(150.73056,-68.966557)"> + width="41.357685" + height="38.711853" + x="-58.428596" + y="156.89072" /> + cx="-66.620926" + id="circle1910" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path1912-6" + d="M -44.068258,191.58795 H -66.113799" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> Shunted Shunted capacitor + y="153.54039" + style="text-align:center;text-anchor:middle;stroke-width:0.20199829px" + id="tspan1916">capacitor - - + transform="scale(-1)" /> + sodipodi:nodetypes="cc" /> + id="circle1936" + cx="-66.620926" + cy="161.89879" + r="1.1575521" /> + + + d="m -41.916941,171.61644 v -9.53293" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + style="fill:#2c4d29;fill-opacity:1;stroke:none;stroke-width:0.45546275;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> C + x="62.699265" + id="tspan1990" + sodipodi:role="line">C + x="66.820099" + y="28.45998" /> + transform="matrix(0.26458333,0,0,0.26458333,-127.11277,-66.354218)"> - + inkscape:connector-curvature="0" /> + + d="m 335.99999,920.41665 h -28" + style="fill:none;stroke:#000000;stroke-width:1.88976383;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + transform="translate(213.84988,-141.50731)" + id="g2130"> + style="fill:#2c4d29;fill-opacity:1;stroke:none;stroke-width:0.45546275;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> C + x="62.699265" + id="tspan2036" + sodipodi:role="line">C + x="66.820099" + y="28.45998" /> + + d="m -100.5033,162.44695 23.081214,-0.0334" + id="path2048" + sodipodi:nodetypes="cc" /> - + id="path2052" + inkscape:connector-curvature="0" /> + width="41.357685" + height="38.711853" + x="-122.30657" + y="157.26869" /> + cx="-130.4989" + id="circle2058" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path2060" + d="m -107.94623,191.96593 h -22.04554" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> Series Series capacitor + y="153.91837" + style="text-align:center;text-anchor:middle;stroke-width:0.20199829px" + id="tspan2064">capacitor + cx="77.03566" + cy="-191.96593" + r="1.1575521" + transform="scale(-1)" /> + id="path2070-9" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + cx="-130.4989" + cy="162.27676" + r="1.1575521" /> + cy="-162.27676" + cx="77.03566" + id="circle2076" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + transform="translate(-6.3659716,-218.12261)" + id="g2225"> + d="m 24.45251,237.24901 20.353406,0.0276" + id="path2142" + sodipodi:nodetypes="cc" /> + d="m 63.303831,237.27661 14.290413,-0.0276" + id="path2144" + sodipodi:nodetypes="cc" /> + transform="translate(91.138354,75.213444)" + id="g2170"> + height="38.711853" + width="41.357685" + id="rect2150" + style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> + cx="-66.620926" + cy="191.58795" + r="1.1575521" /> + id="path2154" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> Series Series inductor + y="153.54039" + x="-37.931236" + sodipodi:role="line">inductor + cy="-191.58795" + cx="13.157681" + id="circle2162" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path2164" + d="m -46.695277,191.58795 h 33.030474" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="-66.620926" + id="circle2166" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="13.157681" + cy="-161.89879" + r="1.1575521" + transform="scale(-1)" /> + id="g2182"> L + x="62.699265" + y="22.861202" + id="text2176">L + x="66.820099" + id="tspan2178" + sodipodi:role="line" /> + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 67.007998,237.27661 h -3.704167 c -0.01114,-4.3389 -3.709733,-4.3389 -3.704166,0 -0.0056,-4.3389 -3.715232,-4.32348 -3.704167,0 -6.9e-5,-4.35431 -3.715375,-4.35431 -3.704167,0 7.4e-5,-4.32348 -3.6986,-4.3389 -3.704166,0 -0.01114,-4.3389 -3.681249,-4.3389 -3.681249,0 h -3.727085" + sodipodi:nodetypes="cccccccc" /> + transform="translate(9.7670284,-14.25665)" + id="g2944"> + width="41.357685" + height="38.711853" + x="160.9084" + y="29.447495" /> + id="path2808" + inkscape:connector-curvature="0" /> + id="path2810" + d="m 209.56694,64.65264 -55.1091,0.02362" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + + + + + + + + 0 + γ ,Z + θ + line + Line delay + + + id="path2876-6" + d="m 193.55881,43.005619 -24.98564,0.01983" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker5939);marker-end:url(#marker5979)" /> 0 @@ -850,37 +955,37 @@ style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:3.7112999px;line-height:3.89686465px;font-family:'CMU Sans Serif';-inkscape-font-specification:'CMU Sans Serif, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" x="180.64104" y="35.286743" - id="text2846" + id="text2884" transform="scale(0.9826566,1.0176495)">γ ,Z θ line + id="tspan2890" + x="181.605" + y="56.516262" /> Line delay - + id="tspan2894">Line delay + d="M 195.82154,37.861975 V 64.658531" + id="path5925" + inkscape:connector-curvature="0" /> - - - - - + - 0 - γ ,Z - θ - - Line delay + id="path2834-6" + d="M 210.03095,34.982019 197.3006,34.932138" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - - - - + transform="translate(357.93408,59.024281)" + id="g3045"> + height="38.711853" + width="41.357685" + id="rect2946" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> - + id="path2948" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + + d="m -171.05093,55.019274 3.19792,0.02939" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + width="15.430521" + height="4.0119357" + x="-53.244831" + y="-168.44829" + transform="rotate(-90.626266)" /> + cx="-53.210712" + cy="-166.44232" + rx="0.96624792" + ry="2.0023472" + transform="rotate(-90.626266)" /> - + id="path2964" + inkscape:connector-curvature="0" + sodipodi:nodetypes="csssc" /> + + + sodipodi:nodetypes="cc" /> - + d="m -160.72157,39.796574 -0.0895,15.391618" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker5555);marker-end:url(#marker5559)" /> + style="stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"> 0 + x="25.415678" + id="tspan2980" + sodipodi:role="line">0 γ ,Z + x="15.285666" + id="tspan2984" + sodipodi:role="line">γ ,Z θ + x="-158.09601" + y="49.67601" + style="stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none">θ + x="-153.9527" + y="55.765812" /> + cx="-165.85077" + cy="59.420849" + r="1.1575521" /> + id="path3000" + inkscape:connector-curvature="0" /> + id="path3002" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> Shunt delay Shunt delay short + x="-164.50783" + sodipodi:role="line" + id="tspan3008">short + transform="translate(-17.120512,-20.392497)" + id="g3080"> + transform="translate(-165.85795,0.64847438)" + id="g3067"> - + + id="path3049" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + cx="21.733206" + id="circle3051" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="21.78443" + cy="64.094612" + r="1.1575521" /> + id="path3055" + d="M 21.812121,71.119795 21.688855,27.123086" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.50000001, 1.00000001;stroke-dashoffset:0;stroke-opacity:1" /> + transform="translate(4.2763122)"> 0 + x="10.017295" + id="tspan3057" + sodipodi:role="line">0 γ ,Z + x="-3.6277833" + id="tspan3061" + sodipodi:role="line">γ ,Z + transform="matrix(0.26458333,0,0,0.26458333,-201.30779,-242.02059)" + id="g6475"> + style="stroke-width:1.88976383;stroke-miterlimit:4;stroke-dasharray:none"> + d="m 217,500.41665 v -14" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.88976383;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + d="m 238,521.1399 h -42 l 21,-21 z" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.88976383;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="111.10832" + id="circle3053-9" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.88976383;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + transform="matrix(0.26458333,0,0,0.26458333,-350.20126,-303.8213)" + id="g6674"> + height="146.31252" + width="156.31252" + id="rect6501" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:3.77952766;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> + + + + - - - - + d="m 1000.5718,1606.1873 -29.34754,0.1841" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.88976383;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 2 port2 portnetwork + id="tspan6655" + style="text-align:center;text-anchor:middle;stroke-width:0.68039173px">network + transform="translate(-80.668082,-143.26738)" + id="g6759"> + height="38.711853" + width="41.357685" + id="rect6676" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> + cx="23.337408" + cy="191.58795" + r="1.1575521" /> + id="path6680" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> Series Series impedance + y="153.54039" + x="52.027096" + sodipodi:role="line">impedance + style="fill:#2c4d29;fill-opacity:1;stroke:none;stroke-width:0.45546275;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> Z + x="62.699265" + id="tspan6690" + sodipodi:role="line">Z + x="66.820099" + y="28.45998" /> + cy="-191.58795" + cx="-76.800652" + id="circle6700" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path6702" + d="M 43.263056,191.58795 H 76.29353" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="23.337408" + id="circle6704" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path6706" + d="M 45.890075,161.8988 H 23.844534" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="-76.800652" + cy="-161.89879" + r="1.1575521" + transform="scale(-1)" /> + id="path6710" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + transform="matrix(0.36498535,0,0,0.36498535,38.773366,-143.38102)"> - + + d="M 55.999996,836.41665 H 84.64549" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.36991799;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + height="13.999982" + width="34.999996" + id="rect5501-3-2" + style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.36991799;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" /> + id="g6803" + transform="translate(-80.668082,-69.008888)"> + height="38.711853" + width="41.357685" + id="rect6761" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> + cx="23.337408" + cy="191.58795" + r="1.1575521" /> + id="path6765" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> Shunted Shunted impedance + y="153.54039" + x="52.027096" + sodipodi:role="line">impedance + style="fill:#2c4d29;fill-opacity:1;stroke:none;stroke-width:0.45546275;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> Z + x="62.699265" + id="tspan6773" + sodipodi:role="line">Z + x="66.820099" + y="28.45998" /> + cy="-191.58795" + cx="-76.800652" + id="circle6783" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path6785" + d="M 43.263056,191.58795 H 76.29353" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="23.337408" + id="circle6787" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path6789" + d="M 45.890075,161.8988 H 23.844534" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cx="-76.800652" + cy="-161.89879" + r="1.1575521" + transform="scale(-1)" /> + id="path6793" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + transform="matrix(0,0.36498535,-0.36498535,0,348.54288,160.69359)"> - + + d="M 55.999996,836.41665 H 84.64549" + style="fill:none;stroke:#000000;stroke-width:1.36991799;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + height="13.999982" + width="34.999996" + id="rect6799" + style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:1.36991799;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" /> port + x="-215.76909" + id="tspan6828" + sodipodi:role="line">port ground + x="-223.23643" + id="tspan6832" + sodipodi:role="line">ground + transform="matrix(0.26458333,0,0,0.26458333,-527.38142,-296.78103)" + id="g6859"> + cx="1340.3173" + id="circle3053-8" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.88976383;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + style="stroke-width:1.88976383;stroke-miterlimit:4;stroke-dasharray:none"> + d="m 211.93697,201.2579 h -42" + id="path6836" + inkscape:connector-curvature="0" /> + d="m 190.93697,187.2579 v 14" + id="path6838" + inkscape:connector-curvature="0" /> + d="m 204.93697,208.2579 h -28" + id="path6840" + inkscape:connector-curvature="0" /> + d="m 197.93697,215.2579 h -14" + id="path6842" + inkscape:connector-curvature="0" /> + id="g6923" + transform="translate(713.01488,55.281671)"> + width="41.357685" + height="38.711853" + x="-465.70145" + y="33.190113" /> - + id="path6863" + d="m -417.04292,68.395257 -55.1091,0.02362" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + + d="m -451.74721,58.761891 3.19792,0.02939" + id="path6869" + inkscape:connector-curvature="0" /> + x="-53.919174" + height="4.0119357" + width="15.430521" + id="rect6871" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> + rx="0.96624792" + cy="-447.16275" + cx="-53.885056" + id="ellipse6873" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> - + sodipodi:nodetypes="csssc" + inkscape:connector-curvature="0" + id="path6875" + d="m -448.72852,44.293828 c -0.0526,-0.89102 0.0175,-0.295653 0.0117,-0.829265 -0.006,-0.533613 0.88587,-0.975989 1.99167,-0.988077 1.1058,-0.01209 2.00696,0.410693 2.01279,0.944305 0.006,0.533612 -0.004,0.07476 0.0332,1.137403" + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> - + + id="path6883" + d="m -416.57891,38.724636 -11.91634,0.0226" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + + id="path6889" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + id="g6899"> 0 + x="25.415678" + y="37.363918" + style="stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none">0 γ ,Z + x="15.285666" + y="35.661594" + style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:4.99014997px;font-family:'CMU Sans Serif';-inkscape-font-specification:'CMU Sans Serif, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none">γ ,Z θ + x="-438.7923" + id="tspan6901" + sodipodi:role="line">θ + x="-434.64899" + id="tspan6905" + sodipodi:role="line" /> + cx="-446.54706" + id="circle6909" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + d="m -451.74721,58.761891 v 9.133313" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> Shunt delay Shunt delay open + y="30.368908" + style="text-align:center;text-anchor:middle;stroke-width:0.20199829px">open - - - + + cy="-159.2113" + r="1.1575521" + transform="scale(-1)" /> + id="circle6973" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + r="1.1575521" + transform="scale(-1)" /> + + + width="41.357685" + height="38.711853" + x="-135.05702" + y="143.21175" /> N portN portnetwork + y="193.35187" + x="-113.93257" + sodipodi:role="line">network + + + r="1.1575521" + cy="175.42068" + cx="-141.1425" + id="circle6987" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + cy="-175.58609" /> + cy="-170.29323" + cx="88.188042" + id="circle7003" + style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - - + ... ... + + + + + + + ... + style="stroke-width:0.20199829px" + y="25.268456" + x="74.16803" + sodipodi:role="line" + id="tspan17858">short + + + transform="translate(-45.975141,112.88263)" + id="g17894"> @@ -2150,18 +2206,18 @@ r="1.1575521" cy="64.67926" cx="54.56134" - id="circle17842" + id="circle17880" style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> short + style="stroke-width:0.20199829px">open - + id="g5802"> + id="rect2202" + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" /> + cy="146.84363" + cx="-140.09381" + id="circle2204" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + id="path2210" + d="m 125.15413,146.84363 h 14.43255" + style="fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + + Z + s + open + id="tspan2222">Source + + + + + + + + P + f + + diff --git a/doc/source/tutorials/Introduction.ipynb b/doc/source/tutorials/Introduction.ipynb index 996409623..a51ef0fc8 100644 --- a/doc/source/tutorials/Introduction.ipynb +++ b/doc/source/tutorials/Introduction.ipynb @@ -125,6 +125,13 @@ "\t..." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Other way to build Network are detailled in the [tutorial on Networks](Networks.ipynb)." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -704,9 +711,9 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [conda env:py35]", + "display_name": "Python 3", "language": "python", - "name": "conda-env-py35-py" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -718,9 +725,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2" + "version": "3.7.6" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/doc/source/tutorials/Networks.ipynb b/doc/source/tutorials/Networks.ipynb index 0f0ccaaee..25b2bb3b8 100644 --- a/doc/source/tutorials/Networks.ipynb +++ b/doc/source/tutorials/Networks.ipynb @@ -64,7 +64,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**skrf** provides an object for a N-port microwave [Network](../api/network.rst). A [Network](../api/network.rst) can be created in a number of ways. One way is from data stored in a touchstone file. " + "**skrf** provides an object for a N-port microwave [Network](../api/network.rst). A [Network](../api/network.rst) can be created in a number of ways:\n", + " - from a Touchstone file\n", + " - from S-parameters\n", + " - from Z-parameters\n", + " - from other RF parameters (Y, ABCD, T, etc.) \n", + " \n", + "Some examples for each situation is given below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating Network from Touchstone file\n", + "[Touchstone file](https://en.wikipedia.org/wiki/Touchstone_file) (`.sNp` files, with `N` being the number of ports) is a _de facto_ standard to export N-port network parameter data and noise data of linear active devices, passive filters, passive devices, or interconnect networks. Creating a Network from a Touchstone file is simple:" ] }, { @@ -78,6 +92,13 @@ "ring_slot = Network('data/ring slot.s2p')" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that some softwares, such as ANSYS HFSS, add additional information to the Touchstone standard, such as comments, simulation parameters, Port Impedance or Gamma (wavenumber). These data are also imported if detected. " + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -100,7 +121,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Networks can also be created by directly passing values for the `frequency`, `s`-parameters and port impedance `z0`. " + "### Creating Network from s-parameters\n", + "Networks can also be created by directly passing values for the `frequency`, `s`-parameters (and optionally the port impedance `z0`). \n", + "\n", + "The scattering matrix of a N-port Network is expected to be a Numpy array of shape `(nb_f, N, N)`, where `nb_f` is the number of frequency points and `N` the number of ports of the network. " ] }, { @@ -109,17 +133,140 @@ "metadata": {}, "outputs": [], "source": [ - "freq = Frequency(1,10,101,'ghz')\n", - "ntwk = Network(frequency=freq, s= [-1, 1j, 0], z0=50, name='slippy') \n", + "# dummy 2-port network from Frequency and s-parameters\n", + "freq = Frequency(1, 10, 101, 'ghz')\n", + "s = rand(101, 2, 2) + 1j*rand(101, 2, 2) # random complex numbers \n", + "# if not passed, will assume z0=50. name is optional but it's a good practice.\n", + "ntwk = Network(frequency=freq, s=s, name='random values 2-port') \n", "ntwk" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ntwk.plot_s_db()" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\t\n", - "See [Network](../api/network.rst) for more information on network creation." + "Often, s-parameters are stored in separate arrays. In such case, one needs to forge the s-matrix:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# let's assume we have separate arrays for the frequency and s-parameters\n", + "f = np.array([1, 2, 3, 4]) # in GHz\n", + "S11 = np.random.rand(4)\n", + "S12 = np.random.rand(4)\n", + "S21 = np.random.rand(4)\n", + "S22 = np.random.rand(4)\n", + "\n", + "# Before creating the scikit-rf Network object, one must forge the Frequency and S-matrix:\n", + "freq2 = rf.Frequency.from_f(f, unit='GHz')\n", + "\n", + "# forging S-matrix as shape (nb_f, 2, 2)\n", + "# there is probably smarter way, but less explicit for the purpose of this example:\n", + "s = np.zeros((len(f), 2, 2))\n", + "s[:,0,0] = S11\n", + "s[:,0,1] = S12\n", + "s[:,1,0] = S21\n", + "s[:,1,1] = S22\n", + "\n", + "# constructing Network object\n", + "ntw = rf.Network(frequency=freq2, s=s)\n", + "\n", + "print(ntw)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If necessary, the characteristic impedance can be passed as a scalar (same for all frequencies), as a list or an array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ntw2 = rf.Network(frequency=freq, s=s, z0=25, name='same z0 for all ports')\n", + "print(ntw2)\n", + "ntw3 = rf.Network(frequency=freq, s=s, z0=[20, 30], name='different z0 for each port')\n", + "print(ntw3)\n", + "ntw4 = rf.Network(frequency=freq, s=s, z0=rand(101,2), name='different z0 for each frequencies and ports')\n", + "print(ntw4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### from z-parameters " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As networks are also defined from their Z-parameters, there is `from_z()` method of the Network:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# 1-port network example\n", + "z = 10j\n", + "Z = np.full((len(freq), 1, 1), z) # replicate z for all frequencies\n", + "\n", + "ntw = rf.Network()\n", + "ntw = ntw.from_z(Z)\n", + "ntw.frequency = freq\n", + "print(ntw)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### from other network parameters (Z, Y, ABCD, T)\n", + "It is also possible to generate Networks from other kind of RF parameters, using the conversion functions: `z2s`, `y2s`, `a2s`, `t2s`, `h2s`. For example, the [ABCD parameters](https://en.wikipedia.org/wiki/Two-port_network#ABCD-parameters) of a serie-impedance is:\n", + "$$\n", + "\\left[\n", + "\\begin{array}{cc}\n", + "1 & Z \\\\\n", + "0 & 1\n", + "\\end{array}\n", + "\\right]\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = 20\n", + "abcd = array([[1, z],\n", + " [0, 1]])\n", + "\n", + "s = rf.a2s(tile(abcd, (len(freq),1,1)))\n", + "ntw = Network(frequency=freq, s=s)\n", + "print(ntw)" ] }, { @@ -323,10 +470,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "## Operators\n", - "\n", - "### Arithmetic Operations \n", + "## Arithmetic Operations \n", "\t\n", "Element-wise mathematical operations on the scattering parameter matrices are accessible through overloaded operators. To illustrate their usage, load a couple Networks stored in the `data` module. " ] @@ -448,7 +592,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Cascading and De-embedding\n", + "## Cascading and De-embedding\n", "\n", "Cascading and de-embeding 2-port Networks can also be done though operators. The `cascade` function can be called through the power operator, `**`. To calculate a new network which is the cascaded connection of the two individual Networks `line` and `short`, " ] @@ -486,20 +630,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The cascading operator also work for to 2N-port Networks. This is illustrated in [this example on balanced Networks](../examples/networktheory/Balanced%20Network%20De-embedding.ipynb). For example, assuming you want to cascade three 4-port Network `ntw1`, `ntw2` and `ntw3`, you can use:\n", - "`resulting_ntw = ntw1 ** ntw2 ** ntw3`\n", - " The port scheme assumed by the ** cascading operator with 4-port networks is:" + "The cascading operator also works for to 2N-port Networks. This is illustrated in [this example on balanced Networks](../examples/networktheory/Balanced%20Network%20De-embedding.ipynb). For example, assuming you want to cascade three 4-port Network `ntw1`, `ntw2` and `ntw3`, you can use:\n", + "`resulting_ntw = ntw1 ** ntw2 ** ntw3`. Note that the port scheme assumed by the `**` cascading operator with 4-port networks is:" ] }, { - "cell_type": "raw", - "metadata": {}, + "cell_type": "markdown", + "metadata": { + "raw_mimetype": "text/markdown" + }, "source": [ + "```\n", " ntw1 ntw2 ntw3\n", " +----+ +----+ +----+\n", "0-|0 2|--|0 2|--|0 2|-2\n", "1-|1 3|--|1 3|--|1 3|-3\n", - " +----+ +----+ +----+" + " +----+ +----+ +----+\n", + "```" ] }, { @@ -773,15 +920,6 @@ "ring_slot.plot_z_im(m=1,n=0)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Conclusion\n", - "\n", - "There are many more features of Networks that can be found in [networks](networks.rst)" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/doc/source/tutorials/develop.rst b/doc/source/tutorials/develop.rst deleted file mode 100644 index 869560ae4..000000000 --- a/doc/source/tutorials/develop.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _develop: - -*********************** -Developing skrf -*********************** - -.. contents:: - - -Introduction --------------- -Welcome to the skrf's developer docs! This page is for those who are interested in participating those who are interested in developing scikit-rf. - -Starting in February, 2012, skrf's codebase has been versioned using `git `_ , and hosted on github at https://github.com/scikit-rf/scikit-rf. The easiest way to contribute to any part of scikit-rf is to create an account on github, but if you are not familiar with git, dont hesitate to contact me directly by email at arsenovic@virginia.edu. - -Contributing Code ------------------ -skrf uses the `Fork + Pull` collaborative development model. -Please see github's page on this for more information http://help.github.com/send-pull-requests/ - - -Contribute Documentation -------------------------- -skrf's documentation is generated using `sphinx `_. The documentation source code is written using reStructed Text, and can be found in `docs/sphinx/source/`. The reference documentation for the submodules, classes, and functions are documented following the `conventions `_ put forth by Numpy/Scipy. Improvements or new documentation is welcomed, and can be submitted using github as well. - - - -Creating Tests --------------- -skrf employs the python module `unittest` for testing. The test's are located in `skrf/testCases/`. diff --git a/skrf/__init__.py b/skrf/__init__.py index 053f6e4bb..ee868200d 100644 --- a/skrf/__init__.py +++ b/skrf/__init__.py @@ -6,7 +6,7 @@ from __future__ import absolute_import, print_function, division from six.moves import xrange -__version__ = '0.15.3' +__version__ = '0.15.4' ## Import all module names for coherent reference of name-space #import io diff --git a/skrf/calibration/calibration.py b/skrf/calibration/calibration.py index 01c571d55..d32048f13 100644 --- a/skrf/calibration/calibration.py +++ b/skrf/calibration/calibration.py @@ -1,5 +1,6 @@ ''' .. module:: skrf.calibration.calibration + ================================================================ calibration (:mod:`skrf.calibration.calibration`) ================================================================ @@ -154,11 +155,11 @@ class Calibration(object): Base class for all Calibration objects. This class implements the common mechanisms for all calibration - algorithms. Specific calibration algorithms should inheret this + algorithms. Specific calibration algorithms should inherit this class and overide the methods: - * :func:`Calibration.run` - * :func:`Calibration.apply_cal` - * :func:`Calibration.embed` (optional) + * :func:`Calibration.run` + * :func:`Calibration.apply_cal` + * :func:`Calibration.embed` (optional) The family of properties prefixed `coefs` and @@ -809,6 +810,8 @@ def biased_error(self): ------- Mathematically, this is + .. math:: + mean_s(|mean_c(r)|) Where: @@ -882,8 +885,7 @@ def total_error(self): where: * r : complex residual errors - * std_cs : standard deviation taken across connections - and standards + * std_cs : standard deviation taken across connections and standards See Also --------- @@ -1395,7 +1397,7 @@ def __init__(self, measured, ideals, n_thrus=None, trans_thres=-40, Use the `n_thrus` argument to explicitly define the number of transmissive standards. Otherwise, if `n_thrus=None`, then we will try and guess which are transmissive, by comparing the mean - |s21| and |s12| responses (in dB) to `trans_thres`. + :math:`|s21|` and :math:`|s12|` responses (in dB) to `trans_thres`. Notes ------ @@ -1794,7 +1796,7 @@ def __init__(self, measured, ideals,n_thrus=None, source_port=1, Use the `n_thrus` argument to explicitly define the number of transmissive standards. Otherwise, if `n_thrus=None`, then we will try and guess which are transmissive, by comparing the mean - |s21| and |s12| responses (in dB) to `trans_thres`. + :math: `|s21|` and :math: `|s12|` responses (in dB) to `trans_thres`. Notes ------ @@ -1836,7 +1838,9 @@ def __init__(self, measured, ideals,n_thrus=None, source_port=1, def run(self): ''' - + run + ''' + ''' if self.sp !=0: raise NotImplementedError('not implemented yet. you can just flip() all your data though. ') n_thrus = self.n_thrus diff --git a/skrf/circuit.py b/skrf/circuit.py index 7b3dd8944..fcfa03012 100644 --- a/skrf/circuit.py +++ b/skrf/circuit.py @@ -164,7 +164,7 @@ def __init__(self, connections): for cnx in self.connections: for (ntw, _) in cnx: if not self._is_named(ntw): - raise AttributeError('All Networks must have a name.') + raise AttributeError('All Networks must have a name. Faulty network:', ntw) # list of networks for initial checks ntws = self.networks_list() @@ -775,4 +775,279 @@ def vswr_active(self, a): z_active : active Z-parameters y_active : active Y-parameters ''' - return self.network.vswr_active(a) \ No newline at end of file + return self.network.vswr_active(a) + + @property + def z0(self): + ''' + Characteristic impedances of "internal" ports + + Returns + ------- + z0 : complex array of shape (nfreqs, nports) + Characteristic impedances of both "inner" and "outer" ports + + ''' + z0s = [] + for cnx_idx, (ntw, ntw_port) in self.connections_list: + z0s.append(ntw.z0[:,ntw_port]) + return np.array(z0s).T + + @property + def connections_pair(self): + ''' + List the connections by pair. + + Each connection in the circuit is between a specific pair of two + (networks, port, z0). + + Returns + ------- + connections_pair : list + list of pair of connections + + ''' + return [self.connections_list[i:i+2] for i in range(0, len(self.connections_list), 2)] + + + @property + def _currents_directions(self): + ''' + Create a array of indices to define the sign of the current. + + The currents are defined positive when entering an internal network. + + + + Returns + ------- + directions : array of int (nports, 2) + + Note + ---- + This function is used in internal currents and voltages calculations. + + ''' + directions = np.zeros((self.dim,2), dtype='int') + for cnx_pair in self.connections_pair: + (cnx_idx_A, cnx_A), (cnx_idx_B, cnx_B) = cnx_pair + directions[cnx_idx_A,:] = cnx_idx_A, cnx_idx_B + directions[cnx_idx_B,:] = cnx_idx_B, cnx_idx_A + return directions + + def _a(self, a_external): + ''' + Wave input array at "internal" ports + + Parameters + ---------- + a_external : array + power-wave input vector at ports + + Returns + ------- + a_internal : array + Wave input array at internal ports + + ''' + # create a zero array and fill the values corresponding to ports + a_internal = np.zeros(self.dim, dtype='complex') + a_internal[self.port_indexes] = a_external + return a_internal + + def _a_external(self, power, phase): + ''' + Wave input array at Circuit's ports ("external" ports). + + The array is defined from power and phase by: + + .. math:: + + a = \sqrt(2 P_{in} ) e^{j \phi} + + The factor 2 is in order to deal with peak values. + + Parameters + ---------- + power : list or array + Input power at external ports in Watts [W] + phase : list or array + Input phase at external ports in radian [rad] + + NB: the size of the power and phase array should match the number of ports + + Returns + ------- + a_external: array + Wave input array at Circuit's ports + + ''' + if len(power) != len(self.port_indexes): + raise ValueError('Length of power array does not match the number of ports of the circuit.') + if len(phase) != len(self.port_indexes): + raise ValueError('Length of phase array does not match the number of ports of the circuit.') + return np.sqrt(2*np.array(power))*np.exp(1j*np.array(phase)) + + def _b(self, a_internal): + ''' + Wave output array at "internal" ports + + Parameters + ---------- + a_internal : array + Wave input array at internal ports + + Returns + ------- + b_internal : array + Wave output array at internal ports + + Note + ---- + Wave input array at internal ports can be derived from power and + phase excitation at "external" ports using `_a(power, phase)` method. + + ''' + # return self.s @ a_internal + return np.matmul(self.s, a_internal) + + def currents(self, power, phase): + ''' + Currents at internal ports. + + NB: current direction is defined as positive when entering a node. + + NB: external current sign are opposite than corresponding internal ones, + as the internal currents are actually flowing into the "port" networks + + Parameters + ---------- + power : list or array + Input power at external ports in Watts [W] + phase : list or array + Input phase at external ports in radian [rad] + + Returns + ------- + I : complex array of shape (nfreqs, nports) + Currents in Amperes [A] (peak) at internal ports. + + ''' + # It is possible with Circuit to define connections between + # multiple (>2) ports at the same time in the connection setup, like : + # cnx = [ + # [(ntw1, portA), (ntw2, portB), (ntw3, portC)], ... + #] + # Such a case is not supported with the present calculation method + # which only works with pair connections between ports, ie like: + # cnx = [ + # [(ntw1, portA), (ntw2, portB)], + # [(ntw2, portD), (ntw3, portC)], ... + #] + # It should not be a huge limitation (?), since it should be always possible + # to add the proper splitting Network (such a "T" or hybrid or more) + # and connect this splitting Network ports to other Network ports. + # ie going from: + # [ntwA] ---- [ntwB] + # | + # | + # [ntwC] + # to: + # [ntwA] ------ [ntwD] ------ [ntwB] + # | + # | + # [ntwC] + for inter_idx, inter in self.intersections_dict.items(): + if len(inter) > 2: + raise NotImplementedError('Connections between more than 2 ports are not supported (yet?)') + + a = self._a(self._a_external(power, phase)) + b = self._b(a) + z0s = self.z0 + directions = self._currents_directions + Is = (b[:,directions[:,0]] - b[:,directions[:,1]])/np.sqrt(z0s) + return Is + + + def voltages(self, power, phase): + ''' + Voltages at internal ports. + + NB: + + Parameters + ---------- + power : list or array + Input power at external ports in Watts [W] + phase : list or array + Input phase at external ports in radian [rad] + + Returns + ------- + V : complex array of shape (nfreqs, nports) + Voltages in Amperes [A] (peak) at internal ports. + + ''' + # cf currents() for more details + for inter_idx, inter in self.intersections_dict.items(): + if len(inter) > 2: + raise NotImplementedError('Connections between more than 2 ports are not supported (yet?)') + + a = self._a(self._a_external(power, phase)) + b = self._b(a) + z0s = self.z0 + directions = self._currents_directions + Vs = (b[:,directions[:,0]] + b[:,directions[:,1]])*np.sqrt(z0s) + return Vs + + def currents_external(self, power, phase): + ''' + Currents at external ports. + + NB: current direction is defined positive when "entering" into port. + + Parameters + ---------- + power : list or array + Input power at external ports in Watts [W] + phase : list or array + Input phase at external ports in radian [rad] + + Returns + ------- + I : complex array of shape (nfreqs, nports) + Currents in Amperes [A] (peak) at external ports. + + ''' + a = self._a(self._a_external(power, phase)) + b = self._b(a) + z0s = self.z0 + Is = [] + for port_idx in self.port_indexes: + Is.append((a[port_idx] - b[:,port_idx])/np.sqrt(z0s[:,port_idx])) + return np.array(Is).T + + def voltages_external(self, power, phase): + ''' + Voltages at external ports + + Parameters + ---------- + power : list or array + Input power at external ports in Watts [W] + phase : list or array + Input phase at external ports in radian [rad] + + Returns + ------- + V : complex array of shape (nfreqs, nports) + Voltages in Volt [V] (peak) at ports + + ''' + a = self._a(self._a_external(power, phase)) + b = self._b(a) + z0s = self.z0 + Vs = [] + for port_idx in self.port_indexes: + Vs.append((a[port_idx] + b[:,port_idx])*np.sqrt(z0s[:,port_idx])) + return np.array(Vs).T diff --git a/skrf/constants.py b/skrf/constants.py index 3e139e230..05f5f949d 100644 --- a/skrf/constants.py +++ b/skrf/constants.py @@ -10,6 +10,38 @@ This module contains constants, numerical approximations, and unit conversions +.. data:: INF + + A very very large value (1e99) + +.. data:: ONE + + 1 + epsilon where epsilon is small. Used to avoid numerical error. + +.. data:: ZERO + + 0 + epsilon where epsilon is small. Used to avoid numerical error. + +.. data:: K_BOLTZMANN + + Boltzmann constant (1.38064852e-23) + +.. data:: S_DEFINITIONS + + S-parameter definition labels: + - 'power' for power-waves definition, + - 'pseudo' for pseudo-waves definition. + - 'traveling' corresponds to the initial implementation. + +.. data:: S_DEF_DEFAULT + + Default S-parameter definition: 'power', for power-wave definition. + +.. autosummary:: + :toctree: generated/ + + to_meters + ''' from scipy.constants import c, micron, mil, inch, centi, milli, nano, micro,pi diff --git a/skrf/io/__init__.py b/skrf/io/__init__.py index c7ccb03fc..db929b65c 100644 --- a/skrf/io/__init__.py +++ b/skrf/io/__init__.py @@ -19,7 +19,9 @@ .. automodule:: skrf.io.general + .. automodule:: skrf.io.touchstone + .. automodule:: skrf.io.csv @@ -27,4 +29,4 @@ from .general import * from .csv import * -from .touchstone import * \ No newline at end of file +from .touchstone import * diff --git a/skrf/io/csv.py b/skrf/io/csv.py index 9ecac7eb3..18d283e59 100644 --- a/skrf/io/csv.py +++ b/skrf/io/csv.py @@ -1,17 +1,52 @@ ''' .. module:: skrf.io.csv + ======================================== csv (:mod:`skrf.io.csv`) ======================================== Functions for reading and writing standard csv files +---------------------------------------------------- + +.. autosummary:: + :toctree: generated/ + + read_all_csv + AgilentCSV + + +Reading/Writing Agilent +------------------------ + +.. autosummary:: + :toctree: generated/ + + read_pna_csv + pna_csv_2_ntwks + pna_csv_2_ntwks3 + pna_csv_2_df + +Reading/Writing R&S +-------------------- + +.. autosummary:: + :toctree: generated/ + + read_zva_dat + read_all_zva_dat + zva_dat_2_ntwks + +Reading/Writing Anritsu VectorStar +----------------------------------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + vectorstar_csv_2_ntwks + read_vectorstar_csv + - read_pna_csv - pna_csv_2_ntwks ''' import numpy as npy import os diff --git a/skrf/io/general.py b/skrf/io/general.py index eb596d94e..80e644cee 100644 --- a/skrf/io/general.py +++ b/skrf/io/general.py @@ -1,31 +1,44 @@ ''' .. module:: skrf.io.general + ======================================== general (:mod:`skrf.io.general`) ======================================== -General io functions for reading and writing skrf objects +General input/output functions for reading and writing skrf objects + + +General functions +------------------ .. autosummary:: - :toctree: generated/ + :toctree: generated/ - read - read_all - read_all_networks - write - write_all - save_sesh + read + read_all + read_all_networks + write + write_all + save_sesh Writing output to spreadsheet +----------------------------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ - network_2_spreadsheet - networkset_2_spreadsheet + network_2_spreadsheet + networkset_2_spreadsheet + +Writing output to pandas dataframe +---------------------------------- + +.. autosummary:: + :toctree: generated/ + network_2_dataframe ''' import sys @@ -274,7 +287,7 @@ def read_all(dir='.', contains = None, f_unit = None, obj_type=None, files=None) filelist = files if files == None: - filelist = os.listdir(dir) + filelist = sorted(os.listdir(dir)) for filename in filelist: if contains is not None and contains not in filename: @@ -762,8 +775,8 @@ def __enter__(self): def __exit__(self, *args): self.close() else: - import io - StringBuffer = io.StringIO + from io import StringIO + StringBuffer = StringIO class TouchstoneEncoder(json.JSONEncoder): diff --git a/skrf/io/metas.py b/skrf/io/metas.py index 59b83c8ad..7fa575f00 100644 --- a/skrf/io/metas.py +++ b/skrf/io/metas.py @@ -9,7 +9,7 @@ http://www.metas.ch/metas/en/home/fabe/hochfrequenz/vna-tools.html .. autosummary:: - :toctree: generated/ + :toctree: generated/ ''' diff --git a/skrf/io/touchstone.py b/skrf/io/touchstone.py index a76c98f46..2bdb35c0e 100644 --- a/skrf/io/touchstone.py +++ b/skrf/io/touchstone.py @@ -1,5 +1,6 @@ """ .. module:: skrf.io.touchstone + ======================================== touchstone (:mod:`skrf.io.touchstone`) ======================================== @@ -7,19 +8,21 @@ Touchstone class .. autosummary:: - :toctree: generated/ - - Touchstone + :toctree: generated/ + Touchstone Functions related to reading/writing touchstones. +------------------------------------------------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + hfss_touchstone_2_gamma_z0 + hfss_touchstone_2_media + hfss_touchstone_2_network + read_zipped_touchstones - hfss_touchstone_2_gamma_z0 - hfss_touchstone_2_media - hfss_touchstone_2_network """ import re import os @@ -301,11 +304,19 @@ def get_format(self, format="ri"): def get_sparameter_names(self, format="ri"): """ - generate a list of column names for the s-parameter data + Generate a list of column names for the s-parameter data. The names are different for each format. - posible format parameters: - ri, ma, db, orig (where orig refers to one of the three others) - returns a list of strings. + + Parameters + ---------- + format : str + Format: ri, ma, db, orig (where orig refers to one of the three others) + + Returns + ------- + names : list + list of strings + """ names = ['frequency'] if format == 'orig': @@ -320,12 +331,23 @@ def get_sparameter_names(self, format="ri"): def get_sparameter_data(self, format='ri'): """ get the data of the s-parameter with the given format. + + Parameters + ---------- + format : str + Format: ri, ma, db, orig + supported formats are: orig: unmodified s-parameter data ri: data in real/imaginary ma: data in magnitude and angle (degree) db: data in log magnitute and angle (degree) - Returns a list of numpy.arrays + + Returns + ------- + ret: list + list of numpy.arrays + """ ret = {} if format == 'orig': @@ -371,12 +393,16 @@ def get_sparameter_data(self, format='ri'): def get_sparameter_arrays(self): """ - Returns the s-parameters as a tuple of arrays, where the first element is - the frequency vector (in Hz) and the s-parameters are a 3d numpy array. + Returns the s-parameters as a tuple of arrays. + + The first element is the frequency vector (in Hz) and the s-parameters are a 3d numpy array. The values of the s-parameters are complex number. - usage: + + Example + ------- f,a = self.sgetparameter_arrays() s11 = a[:,0,0] + """ v = self.sparameters @@ -489,7 +515,7 @@ def line2ComplexVector(s): # If the file does not contain valid port impedance comments, set to default one if len(z0) == 0: - z0 = self.resistance + z0 = npy.complex(self.resistance) #raise ValueError('Touchstone does not contain valid gamma, port impedance comments') diff --git a/skrf/media/__init__.py b/skrf/media/__init__.py index cf219a1d0..6b022505c 100644 --- a/skrf/media/__init__.py +++ b/skrf/media/__init__.py @@ -25,28 +25,18 @@ Media base-class ------------------------- .. autosummary:: - :toctree: generated/ - :nosignatures: + :toctree: generated/ + :nosignatures: + + ~media.Media + + - ~media.Media -Transmission Line Classes -------------------------- -.. autosummary:: - :toctree: generated/ - :nosignatures: - - ~media.DefinedGammaZ0 - ~distributedCircuit.DistributedCircuit - ~rectangularWaveguide.RectangularWaveguide - ~cpw.CPW - ~freespace.Freespace - ~coaxial.Coaxial - ~mline.MLine ''' -from .media import Media, DefinedGammaZ0 +from .media import * from .distributedCircuit import DistributedCircuit from .freespace import Freespace from .cpw import CPW diff --git a/skrf/media/coaxial.py b/skrf/media/coaxial.py index ad57cac05..3fa7aad7c 100644 --- a/skrf/media/coaxial.py +++ b/skrf/media/coaxial.py @@ -1,11 +1,18 @@ # -*- coding: utf-8 -*- ''' .. module:: skrf.media.coaxial + ============================================================ coaxial (:mod:`skrf.media.coaxial`) ============================================================ A coaxial transmission line defined from its electrical or geometrical/physical properties + +.. autosummary:: + :toctree: generated/ + + Coaxial + ''' #from copy import deepcopy @@ -176,34 +183,97 @@ def from_Z0_Dout(cls, frequency=None, z0=None,Z0=50, epsilon_r=1, @property def Rs(self): + ''' + Surface resistivity in Ohm/area + + Returns + ------- + Rs : number or array + surface resistivity + + ''' f = self.frequency.f rho = 1./self.sigma mu_r =1 return surface_resistivity(f=f,rho=rho, mu_r=mu_r) + @property def a(self): + ''' + Inner radius of the coaxial line + + Returns + ------- + a : float + Inner radius + + ''' return self.Dint/2. @property def b(self): + ''' + Outer radius of the coaxial line + + Returns + ------- + b : float + Outer radius + ''' return self.Dout/2. # derivation of distributed circuit parameters @property def R(self): + ''' + Distributed resistance R, in Ohm/m + + Returns + ------- + R : number, or array-like + distributed resistance, in Ohm/m + + ''' return self.Rs/(2.*pi)*(1./self.a + 1./self.b) @property def L(self): + ''' + Distributed inductance L, in H/m + + Returns + ------- + L : number, or array-like + distributed inductance, in H/m + + ''' return mu_0/(2.*pi)*log(self.b/self.a) @property def C(self): + ''' + Distributed capacitance C, in F/m + + Returns + ------- + C : number, or array-like + distributed capacitance, in F/m + + ''' return 2.*pi*self.epsilon_prime/log(self.b/self.a) @property def G(self): + ''' + Distributed conductance G, in S/m + + Returns + ------- + G : number, or array-like + distributed conductance, in S/m + + ''' f = self.frequency.f return f*self.epsilon_second/log(self.b/self.a) diff --git a/skrf/media/cpw.py b/skrf/media/cpw.py index 1b45951b6..ca61b8ab4 100644 --- a/skrf/media/cpw.py +++ b/skrf/media/cpw.py @@ -2,13 +2,13 @@ ''' .. module:: skrf.media.cpw + ======================================== cpw (:mod:`skrf.media.cpw`) ======================================== Coplanar waveguide class - This class was made from the technical documentation [#]_ provided by the qucs project [#]_ . The variables and properties of this class are coincident with @@ -16,6 +16,12 @@ .. [#] http://qucs.sourceforge.net/docs/technical.pdf .. [#] http://www.qucs.sourceforge.net/ + +.. autosummary:: + :toctree: generated/ + + CPW + ''' from scipy.constants import epsilon_0, mu_0 from scipy.special import ellipk diff --git a/skrf/media/definedAEpTandZ0.py b/skrf/media/definedAEpTandZ0.py index c7746b199..d1e7263d2 100644 --- a/skrf/media/definedAEpTandZ0.py +++ b/skrf/media/definedAEpTandZ0.py @@ -3,9 +3,9 @@ ''' .. module:: skrf.media.definedAEpTandZ0 -======================================== +====================================================== DefinedAEpTandZ0 (:mod:`skrf.media.definedAEpTandZ0`) -======================================== +====================================================== Transmission line medium defined by A, Ep, Tand and Z0. @@ -14,6 +14,11 @@ Djirdjevic/Svennson dispersion model is provided for dielectric, default behaviour is frequency invariant. + +.. autosummary:: + :toctree: generated/ + + DefinedAEpTandZ0 ''' from scipy.constants import epsilon_0, c from numpy import real, imag, sqrt, ones, zeros, pi, log diff --git a/skrf/media/circuit.py b/skrf/media/device.py similarity index 88% rename from skrf/media/circuit.py rename to skrf/media/device.py index 4d3f10562..6de56129f 100644 --- a/skrf/media/circuit.py +++ b/skrf/media/device.py @@ -1,20 +1,32 @@ ''' -.. currentmodule:: skrf.media.circuit +.. currentmodule:: skrf.media.device + ======================================== -frequency (:mod:`skrf.media.circuit`) +device (:mod:`skrf.media.device`) ======================================== +Device is a generic n-port microwave device class to create common Network. +Device Class +--------------- +.. autosummary:: + :toctree: generated/ + Device -Circuit Class -=============== +Example Devices +--------------- .. autosummary:: - :toctree: generated/ + :toctree: generated/ + + MatchedSymmetricCoupler + Hybrid + QuadratureHybrid + Hybrid180 + DualCoupler - Circuit ''' @@ -25,9 +37,9 @@ from numpy import sqrt,exp -class Circuit(object): +class Device(object): ''' - A n-port microwave circuit + A n-port microwave device Parameters ----------- @@ -41,12 +53,12 @@ def __init__(self, media): @abstractproperty def ntwk(self): ''' - the network representation of a given circuit + the network representation of a given device ''' return None -class MatchedSymmetricCoupler(Circuit): +class MatchedSymmetricCoupler(Device): ''' A Matched Symmetric Coupler @@ -58,7 +70,7 @@ class MatchedSymmetricCoupler(Circuit): ''' def __init__(self, media, c=None, t=None, t_phase=0, phase_diff=0, nports=4, *args, **kw): - Circuit.__init__(self, media=media, *args, **kw) + Device.__init__(self, media=media, *args, **kw) if c is None and t is None: raise ValueError('Must pass either `c` or `t`') @@ -158,7 +170,7 @@ def __init__(self, media,t_phase=0, *args, **kw): phase_diff=-90, *args, **kw) -class Hybrid180(Circuit): +class Hybrid180(Device): ''' 180degree hybrid @@ -175,7 +187,7 @@ class Hybrid180(Circuit): http://www.microwaves101.com/encyclopedias/hybrid-couplers ''' def __init__(self, media, nports=4, *args, **kw): - Circuit.__init__(self, media=media, *args, **kw) + Device.__init__(self, media=media, *args, **kw) self.nports = nports @property def ntwk(self): @@ -191,7 +203,7 @@ def ntwk(self): a = connect(a,3,match,0) return a -class DualCoupler(Circuit): +class DualCoupler(Device): ''' Pair of back-to-back directional couplers @@ -202,7 +214,7 @@ class DualCoupler(Circuit): * 3 : coupled on coupler 2 ''' def __init__(self, media, c1=1/sqrt(2), c2=None, c1kw={},c2kw ={}): - Circuit.__init__(self,media=media) + Device.__init__(self,media=media) if c2 is None: c2= c1 self.c1 = MatchedSymmetricCoupler(media=media,c=c1,nports=3,**c1kw) diff --git a/skrf/media/distributedCircuit.py b/skrf/media/distributedCircuit.py index d81628df3..bc877e99f 100644 --- a/skrf/media/distributedCircuit.py +++ b/skrf/media/distributedCircuit.py @@ -2,11 +2,17 @@ ''' .. module:: skrf.media.distributedCircuit + ============================================================ distributedCircuit (:mod:`skrf.media.distributedCircuit`) ============================================================ +A transmission line mode defined in terms of distributed impedance and admittance values. + +.. autosummary:: + :toctree: generated/ + DistributedCircuit ''' @@ -24,8 +30,7 @@ class DistributedCircuit(Media): ''' - A transmission line mode defined in terms of distributed impedance - and admittance values. + A transmission line mode defined in terms of distributed impedance and admittance values. Parameters ------------ diff --git a/skrf/media/freespace.py b/skrf/media/freespace.py index 8afe6b16c..f33655ee1 100644 --- a/skrf/media/freespace.py +++ b/skrf/media/freespace.py @@ -12,6 +12,10 @@ Represents a plane-wave in a homogeneous freespace, defined by the space's relative permittivity and relative permeability. +.. autosummary:: + :toctree: generated/ + + Freespace ''' diff --git a/skrf/media/media.py b/skrf/media/media.py index 123b67584..e27cfdfa0 100644 --- a/skrf/media/media.py +++ b/skrf/media/media.py @@ -5,8 +5,15 @@ media (:mod:`skrf.media.media`) ======================================== -Contains Media class. +Media class. +.. autosummary:: + :toctree: generated/ + + Media + DefinedGammaZ0 + + ''' import warnings @@ -1224,8 +1231,7 @@ def write_csv(self, filename='f,gamma,Z0,z0.csv'): class DefinedGammaZ0(Media): ''' - A media directly defined by its propagation constant and - characteristic impedance + A media directly defined by its propagation constant and characteristic impedance Parameters -------------- diff --git a/skrf/media/mline.py b/skrf/media/mline.py index eb52db5d8..92efc4533 100644 --- a/skrf/media/mline.py +++ b/skrf/media/mline.py @@ -1,7 +1,7 @@ ''' -.. module:: skrf.media.MLine +.. module:: skrf.media.mline ======================================== MLine (:mod:`skrf.media.MLine`) ======================================== @@ -41,6 +41,12 @@ .. Djordjevic, R.M. Biljic, V.D. Likar-Smiljanic, T.K. Sarkar, Wideband frequency-domain characterization of FR-4 and time-domain causality, IEEE Trans. on EMC, vol. 43, N4, 2001, p. 662-667. + +.. autosummary:: + :toctree: generated/ + + MLine + ''' import numpy as npy from scipy.constants import epsilon_0, mu_0, c diff --git a/skrf/media/rectangularWaveguide.py b/skrf/media/rectangularWaveguide.py index e16568748..be6eb2cb7 100644 --- a/skrf/media/rectangularWaveguide.py +++ b/skrf/media/rectangularWaveguide.py @@ -1,5 +1,6 @@ ''' .. module:: skrf.media.rectangularWaveguide + ================================================================ rectangularWaveguide (:mod:`skrf.media.rectangularWaveguide`) ================================================================ @@ -20,6 +21,11 @@ Characteristic Impedance :math:`z_0` :attr:`Z0` ==================================== ============= =============== +.. autosummary:: + :toctree: generated/ + + RectangularWaveguide + ''' from scipy.constants import epsilon_0, mu_0,pi,c from numpy import sqrt, exp, sinc,where diff --git a/skrf/network.py b/skrf/network.py index ca43daf46..cfc79a9e0 100644 --- a/skrf/network.py +++ b/skrf/network.py @@ -20,6 +20,14 @@ Network +Building Network +---------------- + +.. autosummary:: + :toctree: generated/ + + Network.from_z + Network Representations ============================ @@ -342,9 +350,11 @@ def __init__(self, file=None, name=None, comments=None, f_unit=None, s_def=S_DEF its a str comments : str Comments associated with the Network - s_def : str -> s_def : ['power','pseudo'] + s_def : str -> s_def : can be: 'power', 'pseudo' or 'traveling' Scattering parameter definition : 'power' for power-waves definition, - 'pseudo' for pseudo-waves definition. Default is 'power'. + 'pseudo' for pseudo-waves definition. + 'traveling' corresponds to the initial implementation. + Default is 'power'. NB: results are the same for real-valued characteristic impedances. \*\*kwargs : key word arguments can be used to assign properties of the @@ -2625,9 +2635,11 @@ def renormalize(self, z_new, s_def=S_DEF_DEFAULT): z_new : complex array of shape FxN, F, N or a scalar new port impedances - s_def : str -> s_def : ['power','pseudo'] + s_def : str -> s_def : can be: 'power', 'pseudo' or 'traveling' Scattering parameter definition : 'power' for power-waves definition, - 'pseudo' for pseudo-waves definition. Default is 'power'. + 'pseudo' for pseudo-waves definition. + 'traveling' corresponds to the initial implementation. + Default is 'power'. NB: results are the same for real-valued characteristic impedances. See Also @@ -3036,7 +3048,7 @@ def _P(self, p): # (27) (28) Pca[l, 4 * (l + 1) - 1 - 1] = True Pdb[l, 4 * (l + 1) - 2 - 1] = True Pcb[l, 4 * (l + 1) - 1] = True - if Pa.shape[0] is not 0: + if Pa.shape[0] != 0: Pa[l, 4 * p + 2 * (l + 1) - 1 - 1] = True Pb[l, 4 * p + 2 * (l + 1) - 1] = True return npy.concatenate((Pda, Pca, Pa, Pdb, Pcb, Pb)) @@ -3382,7 +3394,7 @@ def connect(ntwkA, k, ntwkB, l, num=1): check_frequency_equal(ntwkA, ntwkB) except IndexError as e: common_freq = npy.intersect1d(ntwkA.frequency.f, ntwkB.frequency.f, return_indices=True) - if common_freq[0].size is 0: + if common_freq[0].size == 0: raise e else: ntwkA = ntwkA[common_freq[1]] @@ -3670,7 +3682,8 @@ def cascade(ntwkA, ntwkB): Notes ------ - connection diagram:: + connection diagram: + :: A B +---------+ +---------+ -|0 N |---|0 N |- @@ -4468,9 +4481,11 @@ def s2z(s, z0=50, s_def=S_DEF_DEFAULT): scattering parameters z0 : complex array-like or number port impedances. - s_def : str -> s_def : ['power','pseudo'] + s_def : str -> s_def : can be: 'power', 'pseudo' or 'traveling' Scattering parameter definition : 'power' for power-waves definition [3], - 'pseudo' for pseudo-waves definition [4]. Default is 'power'. + 'pseudo' for pseudo-waves definition [4]. + 'traveling' corresponds to the initial implementation. + Default is 'power'. Returns --------- @@ -4551,9 +4566,11 @@ def s2y(s, z0=50, s_def=S_DEF_DEFAULT): scattering parameters z0 : complex array-like or number port impedances - s_def : str -> s_def : ['power','pseudo'] + s_def : str -> s_def : can be: 'power', 'pseudo' or 'traveling' Scattering parameter definition : 'power' for power-waves definition [3], - 'pseudo' for pseudo-waves definition [4]. Default is 'power'. + 'pseudo' for pseudo-waves definition [4]. + 'traveling' corresponds to the initial implementation. + Default is 'power'. Returns --------- @@ -4731,9 +4748,11 @@ def z2s(z, z0=50, s_def=S_DEF_DEFAULT): impedance parameters z0 : complex array-like or number port impedances - s_def : str -> s_def : ['power','pseudo'] + s_def : str -> s_def : can be: 'power', 'pseudo' or 'traveling' Scattering parameter definition : 'power' for power-waves definition [3], - 'pseudo' for pseudo-waves definition [4]. Default is 'power'. + 'pseudo' for pseudo-waves definition [4]. + 'traveling' corresponds to the initial implementation. + Default is 'power'. Returns --------- @@ -5095,9 +5114,11 @@ def y2s(y, z0=50, s_def=S_DEF_DEFAULT): z0 : complex array-like or number port impedances - s_def : str -> s_def : ['power','pseudo'] + s_def : str -> s_def : can be: 'power', 'pseudo' or 'traveling' Scattering parameter definition : 'power' for power-waves definition [3], - 'pseudo' for pseudo-waves definition [4]. Default is 'power'. + 'pseudo' for pseudo-waves definition [4]. + 'traveling' corresponds to the initial implementation. + Default is 'power'. Returns --------- @@ -5681,9 +5702,11 @@ def renormalize_s(s, z_old, z_new, s_def=S_DEF_DEFAULT): z_new : complex array of shape FxN, F, N or a scalar new port impedances - s_def : str -> s_def : ['power','pseudo'] + s_def : str -> s_def : can be: 'power', 'pseudo' or 'traveling' Scattering parameter definition : 'power' for power-waves definition, - 'pseudo' for pseudo-waves definition. Default is 'power'. + 'pseudo' for pseudo-waves definition. + 'traveling' corresponds to the initial implementation. + Default is 'power'. NB: results are the same for real-valued characteristic impedances. Notes diff --git a/skrf/network2.py b/skrf/network2.py index fb0c60175..9185d49b8 100644 --- a/skrf/network2.py +++ b/skrf/network2.py @@ -11,7 +11,7 @@ from numpy import fft import matplotlib.pyplot as plb -from IPython.display import Image, SVG, Math +from IPython.display import Image from IPython.core.pylabtools import print_figure from abc import ABCMeta, abstractmethod diff --git a/skrf/networkSet.py b/skrf/networkSet.py index 56db0246b..baac62a31 100644 --- a/skrf/networkSet.py +++ b/skrf/networkSet.py @@ -2,13 +2,12 @@ ''' .. module:: skrf.networkSet + ======================================== networkSet (:mod:`skrf.networkSet`) ======================================== - -Provides a class representing an un-ordered set of n-port -microwave networks. +Provides a class representing an un-ordered set of n-port microwave networks. Frequently one needs to make calculations, such as mean or standard @@ -16,6 +15,9 @@ calculations the :class:`NetworkSet` class provides convenient ways to make such calculations. +Another usage is to interpolate a set of Networks which depend of +an parameter (like a knob, or a geometrical parameter). + The results are returned in :class:`~skrf.network.Network` objects, so they can be plotted and saved in the same way one would do with a :class:`~skrf.network.Network`. @@ -31,6 +33,14 @@ NetworkSet +NetworkSet Utilities +==================== + +.. autosummary:: + :toctree: generated/ + + func_on_networks + getset ''' @@ -384,7 +394,7 @@ def __add_a_plot_uncertainty(self,network_property_name): ''' def plot_func(self,*args, **kwargs): kwargs.update({'attribute':network_property_name}) - self.plot_uncertainty_bounds_component(*args,**kwargs) + plot_uncertainty_bounds_component(*args,**kwargs) setattr(self.__class__,'plot_uncertainty_bounds_'+\ network_property_name,plot_func) @@ -630,61 +640,7 @@ def set_wise_function(self, func, a_property, *args, **kwargs): ''' return fon(self.ntwk_set, func, a_property, *args, **kwargs) - # plotting functions - #def plot_uncertainty_bounds(self,attribute='s_mag',m=0,n=0,\ - #n_deviations=3, alpha=.3,fill_color ='b',std_attribute=None,*args,**kwargs): - #''' - #plots mean value with +- uncertainty bounds in an Network attribute, - #for a list of Networks. - - #takes: - #attribute: attribute of Network type to analyze [string] - #m: first index of attribute matrix [int] - #n: second index of attribute matrix [int] - #n_deviations: number of std deviations to plot as bounds [number] - #alpha: passed to matplotlib.fill_between() command. [number, 0-1] - #*args,**kwargs: passed to Network.plot_'attribute' command - - #returns: - #None - - - #Caution: - #if your list_of_networks is for a calibrated short, then the - #std dev of deg_unwrap might blow up, because even though each - #network is unwrapped, they may fall on either side fo the pi - #relative to one another. - #''' - - ## calculate mean response, and std dev of given attribute - #ntwk_mean = average(self.ntwk_set) - #if std_attribute is None: - ## they want to calculate teh std deviation on a different attribute - #std_attribute = attribute - #ntwk_std = func_on_networks(self.ntwk_set,npy.std, attribute=std_attribute) - - ## pull out port of interest - #ntwk_mean.s = ntwk_mean.s[:,m,n] - #ntwk_std.s = ntwk_std.s[:,m,n] - - ## create bounds (the s_mag here is confusing but is realy in units - ## of whatever 'attribute' is. read the func_on_networks call to understand - #upper_bound = ntwk_mean.__getattribute__(attribute) +\ - #ntwk_std.s_mag*n_deviations - #lower_bound = ntwk_mean.__getattribute__(attribute) -\ - #ntwk_std.s_mag*n_deviations - - ## find the correct ploting method - #plot_func = ntwk_mean.__getattribute__('plot_'+attribute) - - ##plot mean response - #plot_func(*args,**kwargs) - - ##plot bounds - #plb.fill_between(ntwk_mean.frequency.f_scaled, \ - #lower_bound.squeeze(),upper_bound.squeeze(), alpha=alpha, color=fill_color) - #plb.axis('tight') - #plb.draw() + def uncertainty_ntwk_triplet(self, attribute,n_deviations=3): ''' @@ -831,9 +787,6 @@ def interpolate_from_network(self, ntw_param, x, interp_kind='linear'): return ntw -def plot_uncertainty_bounds_s_db(ntwk_list, *args, **kwargs): - NetworkSet(ntwk_list).plot_uncertainty_bounds_s_db(*args, **kwargs) - def func_on_networks(ntwk_list, func, attribute='s',name=None, *args,\ **kwargs): ''' diff --git a/skrf/plotting.py b/skrf/plotting.py index 8c4a94591..730c19e69 100644 --- a/skrf/plotting.py +++ b/skrf/plotting.py @@ -19,6 +19,25 @@ plot_polar plot_complex_rectangular plot_complex_polar + plot_v_frequency + plot_it_all + + plot_minmax_bounds_component + plot_minmax_bounds_s_db + plot_minmax_bounds_s_db10 + plot_minmax_bounds_s_time_db + + plot_uncertainty_bounds_component + plot_uncertainty_bounds_s + plot_uncertainty_bounds_s_db + plot_uncertainty_bounds_s_time_db + + plot_passivity + plot_logsigma + + plot_circuit_graph + + plot_contour Misc Functions ----------------- @@ -26,11 +45,13 @@ .. autosummary:: :toctree: generated/ + stylely save_all_figs add_markers_to_lines legend_off func_on_all_figs scrape_legend + signature ''' import os @@ -216,7 +237,7 @@ def smith(smithR=1, chart_type = 'z', draw_labels = False, border=False, spine.set_color('none') # Make annotations only if the radius is 1 - if smithR is 1: + if smithR == 1: #Make room for annotation ax1.plot(npy.array([-1.25, 1.25]), npy.array([-1.1, 1.1]), 'w.', markersize = 0) ax1.axis('image') @@ -227,11 +248,11 @@ def smith(smithR=1, chart_type = 'z', draw_labels = False, border=False, # chart, y_flip_sign == 1) or right (Y chart, y_flip_sign == -1) # so label doesn't overlap chart's circles rho = (value - 1)/(value + 1) - y_flip_sign*0.01 - if y_flip_sign is 1: + if y_flip_sign == 1: halignstyle = "right" else: halignstyle = "left" - if y_flip_sign is -1: # 'y' and 'yz' charts + if y_flip_sign == -1: # 'y' and 'yz' charts value = 1/value ax1.annotate(str(value*ref_imm), xy=(rho*smithR, 0.01), xytext=(rho*smithR, 0.01), ha = halignstyle, va = "baseline") @@ -259,14 +280,14 @@ def smith(smithR=1, chart_type = 'z', draw_labels = False, border=False, valignstyle = "top" else: valignstyle = "bottom" - if y_flip_sign is -1: # 'y' and 'yz' charts + if y_flip_sign == -1: # 'y' and 'yz' charts value = 1/value #Annotate value ax1.annotate(str(value*ref_imm) + 'j', xy=(rhox, rhoy), xytext=(rhox, rhoy), ha = halignstyle, va = valignstyle) #Annotate 0 and inf - if y_flip_sign is 1: # z and zy charts + if y_flip_sign == 1: # z and zy charts label_left, label_right = '0.0', '$\infty$' else: # y and yz charts label_left, label_right = '$\infty$', '0.0' @@ -1175,7 +1196,7 @@ def plot_v_frequency(self, y, *args, **kwargs): ## specific ploting functions def plot(self, *args, **kw): ''' - plot somthing vs frequency + Plot something vs frequency ''' return self.frequency.plot(*args, **kw) @@ -1567,46 +1588,63 @@ def animate(self, attr='s_deg', ylims=(-5, 5), xlims=None, show=True, plb.ion() +#------------------------------ +# +# NetworkSet plotting functions +# +#------------------------------ + def plot_uncertainty_bounds_component( self, attribute, m=None, n=None, type='shade', n_deviations=3, alpha=.3, color_error=None, markevery_error=20, ax=None, ppf=None, kwargs_error={}, *args, **kwargs): ''' - plots mean value of the NetworkSet with +- uncertainty bounds - in an Network's attribute. This is designed to represent - uncertainty in a scalar component of the s-parameter. for example - plotting the uncertainty in the magnitude would be expressed by, - + plots mean value of a NetworkSet with +/- uncertainty bounds in an Network's attribute. + + This is designed to represent uncertainty in a scalar component of the s-parameter. + for example plotting the uncertainty in the magnitude would be expressed by, + .. maths:: mean(abs(s)) +- std(abs(s)) the order of mean and abs is important. - takes: - attribute: attribute of Network type to analyze [string] - m: first index of attribute matrix [int] - n: second index of attribute matrix [int] - type: ['shade' | 'bar'], type of plot to draw - n_deviations: number of std deviations to plot as bounds [number] - alpha: passed to matplotlib.fill_between() command. [number, 0-1] - color_error: color of the +- std dev fill shading - markevery_error: if type=='bar', this controls frequency - of error bars - ax: Axes to plot on - ppf: post processing function. a function applied to the - upper and lower bounds - *args,**kwargs: passed to Network.plot_s_re command used - to plot mean response - kwargs_error: dictionary of kwargs to pass to the fill_between - or errorbar plot command depending on value of type. - - returns: - None - - - Note: - for phase uncertainty you probably want s_deg_unwrap, or - similar. uncerainty for wrapped phase blows up at +-pi. + Parameters + ---------- + attribute: str + attribute of Network type to analyze + m: int + first index of attribute matrix + n: int + second index of attribute matrix + type: str + ['shade' | 'bar'], type of plot to draw + n_deviations: float + number of std deviations to plot as bounds + alpha: float + passed to matplotlib.fill_between() command. [number, 0-1] + color_error: str + color of the +- std dev fill shading. Default is None. + markevery_error: float + tbd + type: str + if type=='bar', this controls frequency of error bars + ax: matplotlib axe object + Axes to plot on. Default is None. + ppf: function + post processing function. a function applied to the + upper and lower bounds. Default is None + *args,**kwargs: + passed to Network.plot_s_re command used to plot mean response + kwargs_error: dict + dictionary of kwargs to pass to the fill_between or + errorbar plot command depending on value of type. + + + Note + ---- + for phase uncertainty you probably want s_deg_unwrap, or + similar. uncerainty for wrapped phase blows up at +-pi. ''' @@ -1642,9 +1680,9 @@ def plot_uncertainty_bounds_component( lower_bound = ppf(lower_bound) lower_bound[npy.isnan(lower_bound)] = min(lower_bound) if ppf in [mf.magnitude_2_db, mf.mag_2_db]: # quickfix of wrong ylabels due to usage of ppf for *_db plots - if attribute is 's_mag': + if attribute == 's_mag': plot_attribute = 's_db' - elif attribute is 's_time_mag': + elif attribute == 's_time_mag': plot_attribute = 's_time_db' if type == 'shade': @@ -1677,41 +1715,51 @@ def plot_minmax_bounds_component(self, attribute, m=0, n=0, type='shade', alpha=.3, color_error=None, markevery_error=20, ax=None, ppf=None, kwargs_error={}, *args, **kwargs): ''' - plots mean value of the NetworkSet with +- uncertainty bounds - in an Network's attribute. This is designed to represent - uncertainty in a scalar component of the s-parameter. for example + plots mean value of the NetworkSet with +/- uncertainty bounds in an Network's attribute. + + This is designed to represent uncertainty in a scalar component of the s-parameter. for example plotting the uncertainty in the magnitude would be expressed by, - + .. maths:: mean(abs(s)) +- std(abs(s)) the order of mean and abs is important. - - takes: - attribute: attribute of Network type to analyze [string] - m: first index of attribute matrix [int] - n: second index of attribute matrix [int] - type: ['shade' | 'bar'], type of plot to draw - n_deviations: number of std deviations to plot as bounds [number] - alpha: passed to matplotlib.fill_between() command. [number, 0-1] - color_error: color of the +- std dev fill shading - markevery_error: if type=='bar', this controls frequency - of error bars - ax: Axes to plot on - ppf: post processing function. a function applied to the - upper and low - *args,**kwargs: passed to Network.plot_s_re command used - to plot mean response - kwargs_error: dictionary of kwargs to pass to the fill_between - or errorbar plot command depending on value of type. - - returns: - None - - - Note: - for phase uncertainty you probably want s_deg_unwrap, or - similar. uncertainty for wrapped phase blows up at +-pi. + Parameters + ---------- + attribute: str + attribute of Network type to analyze + m: int + first index of attribute matrix + n: int + second index of attribute matrix + type: str + ['shade' | 'bar'], type of plot to draw + n_deviations: float + number of std deviations to plot as bounds + alpha: float + passed to matplotlib.fill_between() command. [number, 0-1] + color_error: str + color of the +- std dev fill shading. Default is None. + markevery_error: float + tbd + type: str + if type=='bar', this controls frequency of error bars + ax: matplotlib axe object + Axes to plot on. Default is None. + ppf: function + post processing function. a function applied to the + upper and lower bounds. Default is None + *args,**kwargs: + passed to Network.plot_s_re command used to plot mean response + kwargs_error: dict + dictionary of kwargs to pass to the fill_between or + errorbar plot command depending on value of type. + + + Note + ---- + for phase uncertainty you probably want s_deg_unwrap, or + similar. uncertainty for wrapped phase blows up at +-pi. ''' @@ -1731,9 +1779,9 @@ def plot_minmax_bounds_component(self, attribute, m=0, n=0, lower_bound = ppf(lower_bound) lower_bound[npy.isnan(lower_bound)]=min(lower_bound) if ppf in [mf.magnitude_2_db, mf.mag_2_db]: # quickfix of wrong ylabels due to usage of ppf for *_db plots - if attribute is 's_mag': + if attribute == 's_mag': attribute = 's_db' - elif attribute is 's_time_mag': + elif attribute == 's_time_mag': attribute = 's_time_db' if type == 'shade': @@ -1763,18 +1811,18 @@ def plot_minmax_bounds_component(self, attribute, m=0, n=0, def plot_uncertainty_bounds_s_db(self, *args, **kwargs): ''' - this just calls - plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs) + Calls ``plot_uncertainty_bounds(attribute='s_mag','ppf':mf.magnitude_2_db*args,**kwargs)`` + see plot_uncertainty_bounds for help ''' kwargs.update({'attribute':'s_mag','ppf':mf.magnitude_2_db}) self.plot_uncertainty_bounds_component(*args,**kwargs) -def plot_minmax_bounds_s_db(self,*args, **kwargs): +def plot_minmax_bounds_s_db(self, *args, **kwargs): ''' - this just calls - plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs) + Calls ``plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs)`` + see plot_uncertainty_bounds for help ''' @@ -1783,8 +1831,8 @@ def plot_minmax_bounds_s_db(self,*args, **kwargs): def plot_minmax_bounds_s_db10(self,*args, **kwargs): ''' - this just calls - plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs) + Calls ``plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs)`` + see plot_uncertainty_bounds for help ''' @@ -1793,8 +1841,8 @@ def plot_minmax_bounds_s_db10(self,*args, **kwargs): def plot_uncertainty_bounds_s_time_db(self,*args, **kwargs): ''' - this just calls - plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs) + Calls ``plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs)`` + see plot_uncertainty_bounds for help ''' @@ -1803,8 +1851,8 @@ def plot_uncertainty_bounds_s_time_db(self,*args, **kwargs): def plot_minmax_bounds_s_time_db(self,*args, **kwargs): ''' - this just calls - plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs) + Calls ``plot_uncertainty_bounds(attribute= 's_mag','ppf':mf.magnitude_2_db*args,**kwargs)`` + see plot_uncertainty_bounds for help ''' @@ -1887,19 +1935,20 @@ def plot_uncertainty_bounds_s(self, multiplier =200, *args, **kwargs): plb.show() def plot_logsigma(self, label_axis=True, *args,**kwargs): - ''' - plots the uncertainty for the set in units of log-sigma. - Log-sigma is the complex standard deviation, plotted in units - of dB's. - - Parameters - ------------ - \\*args, \\*\\*kwargs : arguments - passed to self.std_s.plot_s_db() - ''' - self.std_s.plot_s_db(*args,**kwargs) - if label_axis: - plb.ylabel('Standard Deviation(dB)') + ''' + plots the uncertainty for the set in units of log-sigma. + + Log-sigma is the complex standard deviation, plotted in units + of dB's. + + Parameters + ------------ + \\*args, \\*\\*kwargs : arguments + passed to self.std_s.plot_s_db() + ''' + self.std_s.plot_s_db(*args,**kwargs) + if label_axis: + plb.ylabel('Standard Deviation(dB)') def signature(self, m=0, n=0, component='s_mag', vmax=None, vs_time=False, cbar_label=None, @@ -2096,7 +2145,39 @@ def plot_circuit_graph(self, **kwargs): -def plot_contour(freq, x,y,z,min0max1, graph=True, cmap='plasma_r',title='', **kw) : +def plot_contour(freq, x, y, z, min0max1, graph=True, cmap='plasma_r', title='', **kwargs): + ''' + Countour plot + + Parameters + ---------- + freq : :skrf.Frequency: + Frequency object. + x : array + x points + y : array + y points. + z : array + z points. + min0max1 : int + 0 for min, 1 for max. + graph : bool, optional + plot graph if True. The default is True. + cmap : str, optional + Colormap label. The default is 'plasma_r'. + title : str, optional + Figure title. The default is ''. + **kwargs : dict + Other parameters passed to `matplotlib.plot()`. + + Returns + ------- + GAMopt : :skrf.Network: + Network + VALopt : float + min or max. + + ''' ri = npy.linspace(0,1, 50); ti = npy.linspace(0,2*npy.pi, 150); Ri , Ti = npy.meshgrid(ri, ti) @@ -2112,11 +2193,11 @@ def plot_contour(freq, x,y,z,min0max1, graph=True, cmap='plasma_r',title='', ** GAMopt = network.Network(f=[freq], s=x[z==VALopt] +1j*y[z==VALopt]) if graph : - fig, ax = plb.subplots(**kw) + fig, ax = plb.subplots(**kwargs) an = npy.linspace(0, 2*npy.pi, 50) - cs,sn=npy.cos(an), npy.sin(an) - plb.plot(cs,sn, color='k', lw=0.25) - plb.plot(cs,sn*0, color='g', lw=0.25) + cs, sn = npy.cos(an), npy.sin(an) + plb.plot(cs, sn, color='k', lw=0.25) + plb.plot(cs, sn*0, color='g', lw=0.25) plb.plot((1+cs)/2, sn/2, color='k', lw=0.25) plb.axis('equal') ax.set_axis_off() diff --git a/skrf/tests/test_circuit.py b/skrf/tests/test_circuit.py index 4878f3288..375164e5f 100644 --- a/skrf/tests/test_circuit.py +++ b/skrf/tests/test_circuit.py @@ -870,6 +870,53 @@ def test_complexz0_s_vs_powerwaves(self): ' Check complex z0 circuit vs pseudo-waves renormalization ' np.testing.assert_allclose(self.cir_complex.network.s, self.s_pseudo, atol=1e-4) +class CircuitTestVoltagesCurrents(unittest.TestCase): + def setUp(self): + # setup a test transmission line randomly excited + self.P_f = np.random.rand() # forward power in Watt + self.phase_f = np.random.rand() # forward phase in rad + self.Z = np.random.rand() # source internal impedance, line characteristic impedance and load impedance + self.L = np.random.rand() # line length in [m] + self.freq = rf.Frequency(1, 10, 10, unit='GHz') + self.line_media = rf.media.DefinedGammaZ0(self.freq, z0=self.Z) # lossless line medium + self.line = self.line_media.line(d=self.L, unit='m', name='line') # transmisison line Network + + # forward voltages and currents at the input of the test line + self.V_in = np.sqrt(2*self.Z*self.P_f)*np.exp(1j*self.phase_f) + self.I_in = np.sqrt(2*self.P_f/self.Z)*np.exp(1j*self.phase_f) + # forward voltages and currents at the output of the test line + theta = rf.theta(self.line_media.gamma, self.freq.f, self.L) # electrical length + self.V_out, self.I_out = rf.tlineFunctions.voltage_current_propagation(self.V_in, self.I_in, self.Z, theta) + + # Equivalent model with Circuit + port1 = rf.Circuit.Port(frequency=self.freq, name='port1', z0=self.Z) + port2 = rf.Circuit.Port(frequency=self.freq, name='port2', z0=self.Z) + cnx = [ + [(port1, 0), (self.line, 0)], + [(port2, 0), (self.line, 1)] + ] + self.crt = rf.Circuit(cnx) + # power and phase arrays for Circuit.voltages() and currents() + self.power = [self.P_f, 0] + self.phase = [self.phase_f, 0] + + def test_tline_voltages(self): + ' Test voltages for a simple transmission line ' + V_ports = self.crt.voltages_external(self.power, self.phase) + + np.testing.assert_allclose(self.V_in, V_ports[:,0]) + np.testing.assert_allclose(self.V_out, V_ports[:,1]) + + def test_tline_currents(self): + ' Test currents for a simple transmission line ' + I_ports = self.crt.currents_external(self.power, self.phase) + + np.testing.assert_allclose(self.I_in, I_ports[:,0]) + # output current is * -1 as Circuit definition is opposite + # (toward the Circuit's Port) + np.testing.assert_allclose(self.I_out, -1*I_ports[:,1]) + + if __name__ == "__main__": # Launch all tests run_module_suite() diff --git a/skrf/time.py b/skrf/time.py index 400e5cadc..be9369c2d 100644 --- a/skrf/time.py +++ b/skrf/time.py @@ -262,8 +262,8 @@ def time_gate(ntwk, start=None, stop=None, center=None, span=None, window, npy.zeros(len(t) - stop_idx)] - #IFFT the gate, so we have it's frequency response, aka kernel - kernel=fft.fftshift(fft.ifft(fft.ifftshift(gate, axes=0), axis=0)) + #FFT the gate, so we have it's frequency response, aka kernel + kernel=fft.ifftshift(fft.fft(fft.fftshift(gate, axes=0), axis=0)) kernel =abs(kernel).flatten() # take mag and flatten kernel=kernel/sum(kernel) # normalize kernel diff --git a/skrf/vi/__init__.py b/skrf/vi/__init__.py index dde570d5b..f55de32e7 100644 --- a/skrf/vi/__init__.py +++ b/skrf/vi/__init__.py @@ -1,6 +1,7 @@ ''' .. module:: skrf.vi + ======================================================== virtual instruments (:mod:`skrf.vi`) ======================================================== @@ -9,7 +10,9 @@ .. automodule:: skrf.vi.vna + .. automodule:: skrf.vi.sa + .. automodule:: skrf.vi.stages diff --git a/skrf/vi/vna/keysight_pna.py b/skrf/vi/vna/keysight_pna.py index 23ffe17cd..3c74ef2e4 100644 --- a/skrf/vi/vna/keysight_pna.py +++ b/skrf/vi/vna/keysight_pna.py @@ -267,7 +267,7 @@ def get_snp_network(self, ports, **kwargs): self.scpi.set_snp_format(snp_fmt) # restore the value before we got the RI data nrows = int(len(data) / npoints) - nports = int(np.sqrt(nrows - 1)) + nports = int(np.sqrt((nrows - 1)/2)) data = data.reshape([nrows, -1]) fdata = data[0]