Commit e244921b authored by Sean Leavey's avatar Sean Leavey

Merge branch 'release/0.6.0'

parents b94ee4f3 e866e8d0
Pipeline #62526 passed with stage
in 12 minutes and 39 seconds
......@@ -2,7 +2,10 @@
zero/_version.py
# Autogenerated API documentation
docs/api
docs/developers/api
# Autogenerated static SVGs
docs/_static/*.svg
# Byte-compiled / optimized / DLL files
__pycache__/
......
......@@ -68,8 +68,8 @@ test unit:3.6:
stage: test
<<: *template-test-unit
test unit:3.5:
image: python:3.5
test unit:3.7:
image: python:3.7
stage: test
<<: *template-test-unit
......@@ -83,8 +83,8 @@ test integration:3.6:
stage: test
<<: *template-test-integration
test integration:3.5:
image: python:3.5
test integration:3.7:
image: python:3.7
stage: test
<<: *template-test-integration
......@@ -98,14 +98,14 @@ test validation:3.6:
stage: test
<<: *template-test-validation
test validation:3.5:
image: python:3.5
test validation:3.7:
image: python:3.7
stage: test
<<: *template-test-validation
# generate the documentation only on creation of new tags or pushes to master branch
# Generate the documentation only on creation of new tags or pushes to master branch.
pages:
image: python:3.6
image: python:3.7
stage: deploy
only:
- tag
......
......@@ -4,5 +4,7 @@
"editor.rulers": [100],
"editor.tabSize": 4,
"editor.insertSpaces": true,
"python.pythonPath": "/home/sean/conda/envs/circuit/bin/python"
"[markdown]": {
"files.trimTrailingWhitespace": false
}
}
# Zero
Linear electronic circuit utility. This package provides tools to
simulate transfer functions and noise in linear electronic circuits, SI unit
parsing and formatting, datasheet grabbing, and more.
Linear electronic circuit utility. This package provides tools to simulate responses and noise in
linear electronic circuits, SI unit parsing and formatting, datasheet grabbing, and more.
This tool's simulator is inspired by [LISO](https://wiki.projekt.uni-hannover.de/aei-geo-q/start/software/liso), and comes bundled
with its op-amp library ([including tools to search it](https://docs.ligo.org/sean-leavey/zero/cli/library.html#search-queries)).
It also (somewhat) understands LISO input and output files, and can plot or re-simulate their
contents.
This tool's simulator is inspired by [LISO](https://wiki.projekt.uni-hannover.de/aei-geo-q/start/software/liso),
and comes bundled with its op-amp library ([including tools to search it](https://docs.ligo.org/sean-leavey/zero/cli/library.html#search-queries)).
It also ([somewhat](https://docs.ligo.org/sean-leavey/zero/liso/input.html#known-incompatibilities))
understands LISO input and output files, and can plot or re-simulate their contents.
## Documentation
See the [online documentation](https://docs.ligo.org/sean-leavey/zero/).
## Installation
This library requires that Python 3 is installed. It has been tested on 3.5, 3.6 and 3.7,
but may work on earlier versions of Python 3. Python 2 is not supported. You may wish to use
`virtualenv` or `conda` to manage a separate environment with Python 3.
This library requires at least Python 3.6. It will not work on earlier versions of Python 3, nor
Python 2. You may wish to use `virtualenv` or `conda` to manage a separate environment with Python
3.
This library contains a `setup.py` file which tells Python how it should be
installed. Installation can be automated using `pip`. Open up a terminal or
command prompt (Windows) and type:
This library contains a `setup.py` file which tells Python how it should be installed. Installation
can be automated using `pip`. Open up a terminal or command prompt (Windows) and type:
```bash
pip install git+https://git.ligo.org/sean-leavey/zero.git
pip install zero
```
This installs the library and adds a console script `zero` which provides
access to the package's command line utility.
This installs the library and adds a console script `zero` which provides access to the package's
command line utility.
If you want to update the library to a later version after having previously
installed it, run:
If you want to update the library to a later version after having previously installed it, run:
```bash
pip install git+https://git.ligo.org/sean-leavey/zero.git --upgrade
pip install zero --upgrade
```
## Contributing
......@@ -36,36 +33,20 @@ Bug reports and feature requests are always welcome, as are code contributions.
project's [issue tracker](https://git.ligo.org/sean-leavey/zero/issues).
## Future ideas
- Return plot objects to allow user to modify them
- Allow arbitrary op-amp noise spectra (interpolate to the frequency vector
actually used)
- Allow arbitrary op-amp noise spectra (interpolate to the frequency vector actually used)
- Split op-amp families into their own library files
- Some sort of system for sharing op-amp, regulator, resistor, etc. library
data across the web
- Breakout data classes into separate project (TFs, noise and data handling
are probably useful for other purposes)
- Some sort of system for sharing op-amp, regulator, resistor, etc. library data across the web
- A standardised export file format (XML?)
- Other types of noise, e.g. resistor excess noise
- SciPy/Matlab system object export?
- Visualise circuit node network with graphviz
- Op-amp noise optimisation: here's my circuit, this is the frequency band I
care about, now what's the best op-amp to use?
- Multiple voltage/current inputs?
- Grouped components that are represented as a single component in the input
definition:
- Op-amp noise optimisation: here's my circuit, this is the frequency band I care about, now
what's the best op-amp to use?
- Grouped components that are represented as a single component in the input definition:
- filters, e.g. whitening filters
- real passive components: capacitors with ESR, resistors with stray
inductance, etc.
- Parallelised solving (need to be careful about thread safety)
- Warn user if numerical precision might prevent LISO agreement (e.g. for
magnitudes <100 dB)
- Other analyses, e.g. DC operating point (linearises circuits for AC analyses,
thereby allowing nonlinear components like diodes to be modelled)
- real passive components: capacitors with ESR, resistors with stray inductance, etc.
## Credits
Sean Leavey
Sean Leavey
<sean.leavey@ligo.org>
Invaluable insight into LISO's workings provided by Gerhard Heinzel.
The author is grateful for additional contributions by Sebastian Steinlechner.
Invaluable insight into LISO's workings provided by Gerhard Heinzel. The author is also grateful for
contributions by Sebastian Steinlechner.
......@@ -13,6 +13,16 @@ PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# Zero static directory
STATICDIR = _static
### Dynamic plot dependencies
# Static files
ZEROSTATICDEPS = $(STATICDIR)/liso-input-node-graph.svg
# Zero Python files.
ZEROPYTHONDEPS = $(STATICDIR)/liso-input-response.svg $(STATICDIR)/solution-combination.svg
# LISO script comparisons.
ZEROLISODEPS = $(STATICDIR)/liso-compare-response.svg
.PHONY: help
help:
......@@ -51,16 +61,32 @@ clean:
.PHONY: apidoc
apidoc:
sphinx-apidoc -o api -e ../zero
sphinx-apidoc -o developers/api -e ../zero
.PHONY: static
static: plots
.PHONY: plots
plots: $(ZEROSTATICDEPS) $(ZEROPYTHONDEPS) $(ZEROLISODEPS)
# Generate SVG plots of Zero output using Python script.
$(STATICDIR)/%.svg: $(STATICDIR)/zero-python/%.py
@echo "Generating $@ from $<"
python $< $@
# Generate SVG plots comparing Zero to LISO using LISO files.
$(STATICDIR)/%.svg: $(STATICDIR)/liso-compare/%.fil
@echo "Generating $@ from $<"
zero liso $< --compare --no-plot --save-figure $@
.PHONY: html
html: apidoc
html: apidoc static
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: latex
latex: apidoc
latex: apidoc static
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
......@@ -68,14 +94,14 @@ latex: apidoc
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf: apidoc
latexpdf: apidoc static
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: man
man: apidoc
man: apidoc static
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
This diff is collapsed.
r r1 100 nin nsum
r r3 1.075k no nsum
r r4 42.2 nsum nm
r r6 65 nin gnd
c c2 4.7n nsum gnd
c c5 122p no nm
op op1 op27 gnd nm no
freq log 10k 10M 100
uinput nin 50
ioutput allop
uoutput allop
This diff is collapsed.
This diff is collapsed.
"""Documentation example. Requires target figure filename as argument."""
import sys
from zero.liso import LisoInputParser
parser = LisoInputParser()
parser.parse("""
c c1 10u gnd n1
r r1 430 n1 nm
r r2 43k nm nout
c c2 47p nm nout
op o1 lt1124 nin nm nout
freq log 1 100k 100
uinput nin 0
uoutput nout:db:deg
""")
solution = parser.solution()
plot = solution.plot_responses()
solution.save_figure(plot, sys.argv[1])
"""Documentation example. Requires target figure filename as argument."""
import sys
from zero.liso import LisoInputParser
# create parser
parser = LisoInputParser()
base_circuit = """
l l2 420n nlf nout
c c4 47p nlf nout
c c1 1n nrf gnd
r r1 1k nrf gnd
l l1 600n nrf n_l1_c2
c c2 330p n_l1_c2 n_c2_c3
c c3 33p n_c2_c3 nout
c load 20p nout gnd
freq log 100k 100M 1000
uoutput nout
"""
# parse base circuit
parser.parse(base_circuit)
# set input to low frequency port
parser.parse("uinput nlf 50")
# ground unused input
parser.parse("r nrfsrc 5 nrf gnd")
# calculate solution
solutionlf = parser.solution()
solutionlf.name = "LF Circuit"
# reset parser state
parser.reset()
# parse base circuit
parser.parse(base_circuit)
# set input to radio frequency port
parser.parse("uinput nrf 50")
# ground unused input
parser.parse("r nlfsrc 5 nlf gnd")
# calculate solution
solutionrf = parser.solution()
solutionrf.name = "RF Circuit"
# combine solutions
solution = solutionlf.combine(solutionrf)
# plot
plot = solution.plot_responses()
solution.save_figure(plot, sys.argv[1])
......@@ -18,8 +18,8 @@ circumstances it is possible to approximate a linear relationship between a comp
current around the operating point, allowing the component to be simulated in the LTI regime, and
this property is exploited in the case of :class:`op-amps <.OpAmp>`.
The small-signal AC transfer function of a circuit input to any of its components or nodes can
be computed with the :ref:`AC small signal analysis <analyses/ac/signal:Small AC signal analysis>`.
The small-signal AC response of a circuit input to any of its components or nodes can be computed
with the :ref:`AC small signal analysis <analyses/ac/signal:Small AC signal analysis>`.
The noise spectral density at a node arising from components and nodes elsewhere in the circuit can
be computed using the :ref:`AC small signal noise analysis <analyses/ac/noise:Small AC noise analysis>`.
......@@ -60,7 +60,7 @@ Consider the following voltage divider, defined in :ref:`LISO syntax <liso/input
uoutput n2
The following circuit matrix is generated for this circuit (using
``zero liso /path/to/script.fil --print-matrix --no-prescale``):
``zero liso /path/to/script.fil --print-matrix``):
.. code-block:: text
......@@ -79,7 +79,7 @@ The following circuit matrix is generated for this circuit (using
╘═══════╧═════════╧═════════╧════════════╧═════════╧═════════╧═══════╛
The entries containing ``---`` represent zero in sparse matrix form. The equations this matrix
represents look like this (using ``zero liso /path/to/script.fil --print-equations --no-prescale``):
represents look like this (using ``zero liso /path/to/script.fil --print-equations``):
.. code-block:: text
......@@ -112,18 +112,6 @@ circuit is solved with the constraint that the voltage between ``n1`` and ground
``1``. The solver can adjust all of the other non-zero matrix elements in the left hand side until
this condition is met within some level of tolerance.
Prescaling
~~~~~~~~~~
By default, |Zero| prescales matrices used in the computation of the solution, in order to improve
numerical precision. This behaviour is currently only implemented for signal analyses and not for
noise.
.. warning::
When prescaling is switched on, any functions which output the circuit matrix (such as the
``--no-prescale`` :ref:`CLI flag <cli/liso:Prescaling>`) will not match the underlying values they represent, but instead
those of the prescaled matrix.
Available analyses
~~~~~~~~~~~~~~~~~~
......@@ -140,7 +128,7 @@ Noise
Noise analysis requires an essentially identical approach to building the circuit matrix, except
that the matrix is transposed and the right hand side is given a ``1`` in the row corresponding to
the chosen noise output node instead of the input. This results in the solution ``x`` in the matrix
equation ``Ax = b`` instead providing what amounts to the reverse transfer functions between the
component and nodes in the circuit and the chosen noise output node. These reverse transfer
functions are as a last step multiplied by the noise at each component and node to infer the noise
at the noise output node.
equation ``Ax = b`` instead providing what amounts to the reverse responses between the component
component and nodes in the circuit and the chosen noise output node. These reverse responses are
as a last step multiplied by the noise at each component and node to infer the noise at the noise
output node.
......@@ -3,4 +3,4 @@
Small AC signal analysis
========================
Linear AC transfer function analysis.
Linear AC response analysis.
......@@ -5,13 +5,12 @@ Analyses
>>> from zero.analysis import AcSignalAnalysis, AcNoiseAnalysis
The circuit can be solved in order to compute transfer functions or noise in a
single run. If both transfer functions *and* noise are required, then these
must be obtained in separate calls.
The circuit can be solved in order to compute responses or noise in a single run. If both responses
*and* noise are required, then these must be obtained in separate calls.
Transfer functions between the circuit input and an output (or outputs) can be
computed with :class:`.AcSignalAnalysis`. Noise from components and nodes in the
circuit at a particular node can be calculated with :class:`.AcNoiseAnalysis`.
Responses between the circuit input and an output (or outputs) can be computed with
:class:`.AcSignalAnalysis`. Noise from components and nodes in the circuit at a particular node can
be calculated with :class:`.AcNoiseAnalysis`.
.. toctree::
:maxdepth: 2
......
......@@ -15,3 +15,20 @@ connected at :class:`nodes <.Node>`. It may contain :class:`resistors <.Resistor
:class:`capacitors <.Capacitor>`, :class:`inductors <.Inductor>` and
:class:`op-amps <.OpAmp>`, and the circuit can be supplied with an :class:`input <.Input>`
in order to produce a current through and voltage across these components.
A circuit can be instantiated without arguments:
.. code-block:: python
>>> circuit = Circuit()
You can print the circuit to retrieve a list of its constituents:
.. code-block:: python
>>> print(circuit)
Circuit with 0 components and 0 nodes
Circuits are only useful once you add components. This is achieved using the various ``add_``
methods, such as :meth:`.add_resistor`, :meth:`.add_capacitor`, :meth:`.add_inductor` and
:meth:`.add_opamp`.
......@@ -67,7 +67,7 @@ arbitrarily long and complex, e.g.:
The expression must be defined on one line. Whitespace is ignored. Where values are specified,
such as "1n", these are parsed by :class:`.Quantity`
(see :ref:`Formatting and parsing quantities <format/index:Formatting and parsing quantities>`).
(see :ref:`Parsing and displaying quantities <format/index:Parsing and displaying quantities>`).
Where a string comparison is made, e.g. with ``model``, wildcards are supported:
......
......@@ -91,7 +91,7 @@ input file itself and with LISO, then it will parse the LISO results and combine
The resulting plot then contains each function, with the native results with solid lines and the
LISO results with dashed lines:
.. image:: /_static/liso-compare-tf.svg
.. image:: /_static/liso-compare-response.svg
A textual representation of the differences can also be displayed by specifying ``--diff``. This
must be provided in addition to ``--compare``. When specified, this prints a table containing
......@@ -108,27 +108,19 @@ they occur:
│ nin to no (V/V) │ 1.04e-08 (f = 79.433 kHz) │ 9.54e-10 (f = 79.433 kHz) │
╘══════════════════╧═══════════════════════════════╧═══════════════════════════════╛
Prescaling
----------
|Zero| can prescale its circuit matrices in the same way that LISO does, to help improve numerical
precision (see :ref:`Prescaling <analyses/ac/index:Prescaling>` for more details). By default,
this behaviour is switched on, but can be disabled with the ``--no-prescale`` flag. This option is
only available when a native simulation is being performed.
Saving figures
--------------
Figures can be saved using the ``--save-figure`` option, which must be followed by a file path.
The format of the figure is controlled by the specified file extension. For example, save PNGs, PDFs
and SVGs with ``--save-figure tf.png``, ``--save-figure tf.pdf`` and ``--save-figure tf.svg``,
and SVGs with ``--save-figure response.png``, ``--save-figure response.pdf`` and ``--save-figure response.svg``,
respectively.
The ``--save-figure`` option can be specified multiple times to save multiple figures, e.g.:
.. code-block:: bash
$ zero liso /path/to/liso/script.fil --save-figure tf.png --save-figure tf.pdf
$ zero liso /path/to/liso/script.fil --save-figure response.png --save-figure response.pdf
Command reference
-----------------
......
......@@ -3,11 +3,80 @@
Passive components
------------------
Passive components do not produce or amplify signals, but only apply an impedance to their input.
They have two nodes, :attr:`~.PassiveComponent.node1` and :attr:`~.PassiveComponent.node2`. The node
order does not matter. Passive components have a complex, frequency dependent
:meth:`~.PassiveComponent.impedance`; the specific component type - resistor, capacitor or inductor
- governs how this impedance behaves as a function of frequency.
Resistors
=========
.. code-block:: python
>>> from zero.components import Resistor
Resistors have a real impedance, i.e. a resistance, with no frequency dependence. This resistance
has units of ohm (Ω). A resistor object can be instantiated by providing the resistance and the name
of two nodes:
.. code-block:: python
>>> r = Resistor(value="430k", node1="n1", node2="n2")
The resistance can be changed using the resistor's :meth:`~Resistor.resistance` property:
.. code-block:: python
>>> r.resistance = "1.1M"
In a circuit, resistor produce :class:`Johnson noise <.JohnsonNoise>`.
Capacitors
==========
.. code-block:: python
>>> from zero.components import Capacitor
Capacitors have an imaginary, frequency dependent impedance determined by its capacitance in units
of farad (F). A capacitor object can be instantiated by providing the capacitance and the name of
two nodes:
.. code-block:: python
>>> c = Capacitor(value="47n", node1="n1", node2="n2")
The capacitance can be changed using the capacitor's :meth:`~Capacitor.capacitance` property:
.. code-block:: python
>>> c.capacitance = "100n"
Capacitors are considered ideal and do not produce noise.
Inductors
=========
.. code-block:: python
>>> from zero.components import Inductor
Inductors have an imaginary, frequency dependent impedance determined by its inductance in units of
henry (H). An inductor object can be instantiated by providing the inductance and the name of two
nodes:
.. code-block:: python
>>> l = Inductor(value="1.6u", node1="n1", node2="n2")
The inductance can be changed using the inductor's :meth:`~Inductor.inductance` property:
.. code-block:: python
>>> l.inductance = "2.2u"
Inductors are considered ideal and do not produce noise.
A pair of inductors can also be configured as mutual inductors, allowing for transformers to be
simulated.
......@@ -17,20 +17,6 @@ URL and any measured data from which your op-amp parameters have been derived.
Code contributions
------------------
Submission of small bug fixes and features is encouraged. For larger features, please discuss these
first with the author to discuss feasibility and structure.
Code style
~~~~~~~~~~
Follow `PEP 8`_ where possible.
Documentation style
~~~~~~~~~~~~~~~~~~~
Use `NumPy docstring format`_. Language and grammar should follow `Google style`_.
Please see :ref:`developers/index:Information for developers`.
.. _issue tracker: https://git.ligo.org/sean-leavey/zero/issues
.. _PEP 8: https://www.python.org/dev/peps/pep-0008/
.. _NumPy docstring format: https://numpydoc.readthedocs.io/en/latest/example.html
.. _Google style: https://developers.google.com/style/
.. include:: /defs.txt
###############
Data containers
###############
.. code-block:: python
>>> from zero.data import TransferFunction, NoiseSpectrum
>>> from zero.data import Response, NoiseDensity
|Zero| :ref:`analysis <analyses/index:Analyses>` results (responses and noise spectra) are
stored within `function` containers. These are relatively low level objects that hold each
function's data, its frequency axis, and any meta data produced by the analysis. These objects are
able to plot themselves when provided a figure to draw to. They also contain logic to compare
themselves to other functions, to check for equivalency.
In normal circumstances, you should not need to directly interact with these objects; rather, you
can plot and save their underlying data using a :ref:`Solution <solution/index:Solutions>`.
Responses
---------
:class:`Responses <.data.Response>` contain the response of a component or node to another component
or node. Each response contains references to the source and sink component or node, and its units.
Noise spectra
-------------
:class:`Noise spectra <.data.NoiseDensity>` contain the noise at a particular component or node
arising from noise produced by another component or node. They contain the :class:`noise source <.components.Noise>`
that produces the noise and a reference to the component or node that the noise is measured at, and
its units. :class:`Multi-noise spectra <.data.MultiNoiseDensity>` contain a list of multiple noise
sources; these are used to represent noise sums.
.. include:: /defs.txt
Information for developers
==========================
Submission of small bug fixes and features is encouraged. For larger features, please contact the
author to discuss feasibility and structure.
Code style
~~~~~~~~~~
Follow `PEP 8`_ where possible.
Documentation style
~~~~~~~~~~~~~~~~~~~
Use `NumPy docstring format`_. Language and grammar should follow `Google style`_.
Merge requests
~~~~~~~~~~~~~~
Please open a `merge request`_ on GitLab, targeting |Zero|'s `develop` branch. To keep the git
repository's merge graph clean, ideally you should make your changes on a branch with one of the
following conventions depending on what kind of change you make:
- ``feature/my-feature`` for new features