Zero issueshttps://git.ligo.org/sean-leavey/zero/-/issues2022-08-30T08:50:46Zhttps://git.ligo.org/sean-leavey/zero/-/issues/54Subtracting OpAmp - Unclear Documentation/Examples.2022-08-30T08:50:46ZNathan HollandSubtracting OpAmp - Unclear Documentation/Examples.Follows from [this mattermost thread](https://chat.ligo.org/ligo/pl/rwfcox68ytb5ifwju5h8uby9ro).
The documentation/examples for OpAmps are unclear about how to use both ports, for example [this subtracting arrangement](/uploads/3ce315b2...Follows from [this mattermost thread](https://chat.ligo.org/ligo/pl/rwfcox68ytb5ifwju5h8uby9ro).
The documentation/examples for OpAmps are unclear about how to use both ports, for example [this subtracting arrangement](/uploads/3ce315b25ae215abd797d6ba6a0e43e5/non_inverting_test-Schematic_v1p00.pdf). Below is a minimum working example, with some inspiration from the CIT 40m fork of Zero.
```python
import numpy as np
from zero import Circuit
from zero.components import OpAmp
from zero.analysis import AcSignalAnalysis
opa188 = {# Part name.
'model' : 'OPA188',
# Open-loop gain: USE HIGH VOLTAGE - Supply.
'a0' : 10**(136/20),
# Gain bandwidth product.
'gbw' : 2e6,
# Flat voltage noise level - spectral density.
'vnoise' : 8.8e-9,
# Corner for voltage noise, in Hz - extrapolation.
'vcorner' : 65e-3,
# Flat current noise level.
'inoise' : 7e-15,
# Corner for current noise, in Hz - guess.
'icorner' : 65e-3,
# Maximum voltage output.
'vmax' : 15,
# Maximum current output.
'imax' : 16e-3,
# Slew rate
'sr' : 0.8e6}
# Non-inverting amplifier.
non_invert_amp = Circuit()
# Around non-inverting input.
# Input to non-inverting port.
non_invert_amp.add_resistor(name = 'R2', value = 1e3, node1 = 'Vin',
node2 = 'Vp')
# Non-inverting port to ground.
non_invert_amp.add_resistor(name = 'R4', value = 6e3, node1 = 'Vp',
node2 = 'gnd')
non_invert_amp.add_capacitor(name = 'C2', value = 1.5e-6, node1 = 'Vp',
node2 = 'gnd')
# Around inverting input.
# Inverting input to ground.
non_invert_amp.add_resistor(name = 'R1', value = 1e3, node1 = 'gnd',
node2 = 'Vn')
# Inverting input to output.
non_invert_amp.add_resistor(name = 'R3', value = 6e3, node1 = 'Vn',
node2 = 'Vo')
non_invert_amp.add_capacitor(name = 'C1', value = 1.5e-6, node1 = 'Vn',
node2 = 'Vo')
# OpAmp.
non_invert_amp.add_component(OpAmp(name = 'U1', node1 = 'Vp', node2 = 'Vn',
node3 = 'Vo', **opa188))
# Output LPF.
non_invert_amp.add_resistor(name = 'R5', value = 5e3, node1 = 'Vo',
node2 = 'Vout')
non_invert_amp.add_capacitor(name = 'C3', value = 2e-6, node1 = 'Vout',
node2 = 'gnd')
# Analysis.
# Frequency vector.
f = np.geomspace(30e-3, 3e2, num = 401)
# Setup analysis?
analyse_NonInvert = AcSignalAnalysis(circuit = non_invert_amp)
# Do analysis.
tf_NonInvert = analyse_NonInvert.calculate(frequencies = f,
node = 'Vin', input_type = 'voltage')
# Subtracting amplifier.
subtract_amp = Circuit()
# Around non-inverting input.
# Input to non-inverting port.
subtract_amp.add_resistor(name = 'R2', value = 1e3, node1 = 'VinP',
node2 = 'Vp')
# Non-inverting port to ground.
subtract_amp.add_resistor(name = 'R4', value = 6e3, node1 = 'Vp',
node2 = 'gnd')
subtract_amp.add_capacitor(name = 'C2', value = 1.5e-6, node1 = 'Vp',
node2 = 'gnd')
# Around inverting input.
# Inverting input to ground.
subtract_amp.add_resistor(name = 'R1', value = 1e3, node1 = 'VinN',
node2 = 'Vn')
# Inverting input to output.
subtract_amp.add_resistor(name = 'R3', value = 6e3, node1 = 'Vn',
node2 = 'Vo')
subtract_amp.add_capacitor(name = 'C1', value = 1.5e-6, node1 = 'Vn',
node2 = 'Vo')
# OpAmp.
subtract_amp.add_component(OpAmp(name = 'U1', node1 = 'Vp', node2 = 'Vn',
node3 = 'Vo', **opa188))
# Output LPF.
subtract_amp.add_resistor(name = 'R5', value = 5e3, node1 = 'Vo',
node2 = 'Vout')
subtract_amp.add_capacitor(name = 'C3', value = 2e-6, node1 = 'Vout',
node2 = 'gnd')
# Analysis.
# Setup
analyse_Subtractor = AcSignalAnalysis(circuit = subtract_amp)
# Analyse.
tf_Subtractor = analyse_Subtractor.calculate(frequencies = f,
node = 'VinP', input_type = 'voltage')
```
The non-inverting OpAmp `tf_NonInvert.plot_response(sink='Vout').show()`, and subtracting OpAmp `tf_Subtractor.plot_response(sink='Vout').show()` transfer functions should be identical but aren't: `15.5 dB` vs `-1 dB` respectively.https://git.ligo.org/sean-leavey/zero/-/issues/53Can we use a different color map that the matplotlib default in the plot_nois...2021-10-05T08:00:07ZJeffrey KisselCan we use a different color map that the matplotlib default in the plot_noise() and plot_responses() methods of the solution class?Apologies for the green-ness of everything I'm about to say.
When @christopher.wipf uses LISO (and thus zero) to model the LIGO suspension coil drivers in [suspensions/ligo/electronics/models/coildriver](https://git.ligo.org/suspensions...Apologies for the green-ness of everything I'm about to say.
When @christopher.wipf uses LISO (and thus zero) to model the LIGO suspension coil drivers in [suspensions/ligo/electronics/models/coildriver](https://git.ligo.org/suspensions/ligo/electronics/-/tree/master/models/coildriver), some of the noise budget plots, where I assume he's using the plot_noise() method of the Solutions class (using words that I hope are correct from zero's help [plotting documentation](https://docs.ligo.org/sean-leavey/zero/plotting/index.html),
> Plotting in analysis scripts
In scripts, plots are generated by the call to the solution’s plot_responses() or plot_noise() methods. These support many display options, as listed below. The return value from these methods is the Figure, which can be further modified.
> After calling either plot_responses() or plot_noise(), you can show the generated plots with show(). This method is called separately to allow you to show a number of plots simultaneously.
create plots like this:
https://git.ligo.org/christopher.wipf/electronics/-/jobs/1598746/artifacts/file/models/coildriver/omcs_top/D1003116-v2_LISO_SWLP-0_NoiseIcoil.png
The problem is that even *if* one ignores all the sub-dominant noise components, one can't identify what the dominant noise component is because the colormap loops over after ~10 curves or so, the components in orange could be the dominant or the subdominant.
A different colormap might solve this.
- maybe user defined, or you, zero, don't want to be so insistent as to chose one for everyone to solve all problems, or
- maybe, if we want to be smart about it, the plot_noise() methods could only plot the top 10 most dominant terms, and add all of the subdominant terms in quadrature, lumping them in to one subdominant curve, so they don't consume so many legend colors.
- maybe, once the feature request [Issue 49](https://git.ligo.org/sean-leavey/zero/-/issues/49) / Node Graphs milestone gets implemented / hit, then this point will be come moot.
Thanks! And sorry again if I've used all the wrong language to describe my problem and ideas for a solution!https://git.ligo.org/sean-leavey/zero/-/issues/52get_window_title deprecated2021-09-29T01:27:16ZChristopher Wipfget_window_title deprecatedWhen plotting from zero a deprecation warning is emitted:
```
/Users/ccw/Library/Python/3.9/lib/python/site-packages/zero/display.py:651: MatplotlibDeprecationWarning:
The get_window_title function was deprecated in Matplotlib 3.4 and w...When plotting from zero a deprecation warning is emitted:
```
/Users/ccw/Library/Python/3.9/lib/python/site-packages/zero/display.py:651: MatplotlibDeprecationWarning:
The get_window_title function was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use manager.get_window_title or GUI-specific methods instead.
LOGGER.info("figure created on %s", figure.canvas.get_window_title())
```
Version info:
```
>>> sys.version
'3.9.7 (default, Sep 1 2021, 12:35:15) \n[Clang 12.0.5 (clang-1205.0.22.9)]'
>>> matplotlib.__version__
'3.4.3'
>>> zero.__version__
'0.9.1'
```https://git.ligo.org/sean-leavey/zero/-/issues/51Give warning when using wrong node name in AcSignalAnalysis.calculate()2020-01-29T22:36:19ZAnchal GuptaGive warning when using wrong node name in AcSignalAnalysis.calculate()I discovered that AcSignalAnalysis.calculate() does not give any warning or error if the wrong node name is given as an argument to it. AcNoiseAnalysis, on the other hand, gives an error for the same mistake by the user. We should correc...I discovered that AcSignalAnalysis.calculate() does not give any warning or error if the wrong node name is given as an argument to it. AcNoiseAnalysis, on the other hand, gives an error for the same mistake by the user. We should correct this. Attaching a simple code that tests this case.[zeroNodeWrongNameTest.py](/uploads/71dd61dd38cce35b1fd3e1a22ed4ff38/zeroNodeWrongNameTest.py)Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/50Consider changing nodes to be circuit-specific2020-01-29T22:36:20ZSean LeaveyConsider changing nodes to be circuit-specific`Node`s are currently singletons. This was originally to avoid having to require the user having to call `circuit.get_node()` all the time to reference nodes in order to perform analyses, but in reality it is also possible to specify nod...`Node`s are currently singletons. This was originally to avoid having to require the user having to call `circuit.get_node()` all the time to reference nodes in order to perform analyses, but in reality it is also possible to specify nodes by their string names only in most (all?) parts of the public API, making this singleton property a bit pointless. Furthermore, the singleton property of nodes makes deep copying problematic (see `circuit.__deepcopy__()` added in 65bbad6).
Since this property seems not necessary, it might be worth removing it. Then nodes would be stored in a circuit and not the global state.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/49Allow connecting sub-circuits together to form a larger circuits2021-10-02T01:00:13ZAnchal GuptaAllow connecting sub-circuits together to form a larger circuitsWe should take advantage of the circuit being a class fully by allowing connecting different circuit objects together to form bigger circuits. This will make zero scalable and will make debugging easier.
I think we can define a function ...We should take advantage of the circuit being a class fully by allowing connecting different circuit objects together to form bigger circuits. This will make zero scalable and will make debugging easier.
I think we can define a function like:
```
def combineCircuits(Cir1,Cir2,['cir1n1->cir2n2','cir1n2->cir2n5',.....]):
.
.
.
return combinedCircuit
```
Here, Cir1 and Cir2 are two different circuit objects and the third argument is the mapping of node connections to be made. The combined circuit will have all nodes of Cir1 and all nodes of Cir2 except for those which have been merged with nodes of Cir1.Node graphshttps://git.ligo.org/sean-leavey/zero/-/issues/48Node regeneration required when circuit nodes are manipulated2020-01-28T15:06:09ZAnchal GuptaNode regeneration required when circuit nodes are manipulatedI have attached a notebook example which illustrates this issue.[NodeRegenerationOnCircuitChanges.ipynb](/uploads/e7c5a5fa96d331884c3bfddd0098bc9a/NodeRegenerationOnCircuitChanges.ipynb). Right after someone changes any node of a circuit...I have attached a notebook example which illustrates this issue.[NodeRegenerationOnCircuitChanges.ipynb](/uploads/e7c5a5fa96d331884c3bfddd0098bc9a/NodeRegenerationOnCircuitChanges.ipynb). Right after someone changes any node of a circuit, there are no calls made to _regenerate_node_set() function. I see this is because nodes are set through property setter function and in that scope, it doesn't have knowledge of the circuit object it is part of.
Due to this, right after a node is manipulated, the number of nodes circuit.n_nodes and the list of nodes circuit.nodes is outdated and may have errors in them unless _regenerate_node_set() is called. There are two solutions that I can think of:
1) Ban changing the nodes of the circuit object directly and define the set_node function to ensure _regenerate_node_set is called inside it.
2) Some clever __setitem__ function for the circuit object which works with dictionary-like functionality of circuit as well. I'm not really sure if this is possible, but this will be way more intuitive and will make using circuit['r1'].node2='n3' legal.Node graphshttps://git.ligo.org/sean-leavey/zero/-/issues/43Allow individual noise or response functions to be plotted on their own2019-06-13T20:27:53ZSean LeaveyAllow individual noise or response functions to be plotted on their ownCurrently `NoiseDensity` and `Response` functions can `draw` their data to an existing `axis` provided by a `Solution`, but they can't just plot themselves on their own. Furthermore, if you provide the `axis` of a figure you made yoursel...Currently `NoiseDensity` and `Response` functions can `draw` their data to an existing `axis` provided by a `Solution`, but they can't just plot themselves on their own. Furthermore, if you provide the `axis` of a figure you made yourself (e.g. with `Solution.noise_figure()`), the function doesn't add axis labels or grids etc.
The functions should be able to access the same plotting tools that `Solution` uses. Maybe split the plotting stuff out of `Solution` and into somewhere else where it can be used by the functions separately.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/39Support vinput/voutput in addition to uinput/uoutput?2019-02-04T19:23:27ZSebastian SteinlechnerSupport vinput/voutput in addition to uinput/uoutput?Just a quick thought, maybe it would be helpful for the international audience if the parser would understand `vinput`/`voutput` as an alias of `uinput`/`uoutput`?Just a quick thought, maybe it would be helpful for the international audience if the parser would understand `vinput`/`voutput` as an alias of `uinput`/`uoutput`?Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/35Add solution data dump functions2019-01-28T20:11:30ZSean LeaveyAdd solution data dump functionsSave to CSV, tab separated value, etc...
Eventually it'd be nice to have a standard data container to hold results alongside their plotting logic, and allow further manipulations (e.g. +, -, /, *, etc.) with data provenance stored in th...Save to CSV, tab separated value, etc...
Eventually it'd be nice to have a standard data container to hold results alongside their plotting logic, and allow further manipulations (e.g. +, -, /, *, etc.) with data provenance stored in the object.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/32Respect LISO's plot ordering when plotting a LISO input or output file.2019-05-07T15:03:13ZSean LeaveyRespect LISO's plot ordering when plotting a LISO input or output file.Since solution merging was introduced in 623a9034, colour wheels on plots are no longer reset when plotting LISO equivalents, so colours for equivalent functions are different. Since now the plotting tool doesn't know the difference betw...Since solution merging was introduced in 623a9034, colour wheels on plots are no longer reset when plotting LISO equivalents, so colours for equivalent functions are different. Since now the plotting tool doesn't know the difference between functions merged from different solutions, add a new plot spec to functions store a "colour wheel group".
UPDATE 2019/05/07: colours now match when comparing LISO to Zero, but absolute order when running a Zero on its own with a LISO input file still differs from what LISO produces.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/29Handle mutual inductances where one component has been deleted2019-08-08T06:14:46ZSean LeaveyHandle mutual inductances where one component has been deletedMutual inductances are stored in `Inductor` objects, but they have no way of knowing if the other inductor has since been deleted from the circuit. Perhaps use `weakref` to check, or have the `Circuit` object deal with cleaning up induc...Mutual inductances are stored in `Inductor` objects, but they have no way of knowing if the other inductor has since been deleted from the circuit. Perhaps use `weakref` to check, or have the `Circuit` object deal with cleaning up inductor references.Node graphsSean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/28Detect floating secondary circuits when mutual inductance is used2019-07-03T08:35:49ZSean LeaveyDetect floating secondary circuits when mutual inductance is usedSecondary circuits used in conjunction with `m` cannot be floating. Prior to simulating a circuit with mutual inductances, use a graph algorithm to detect if the secondary circuit is grounded at some point and warn the user if not.Secondary circuits used in conjunction with `m` cannot be floating. Prior to simulating a circuit with mutual inductances, use a graph algorithm to detect if the secondary circuit is grounded at some point and warn the user if not.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/26Show line with syntax error2018-09-16T14:47:51ZSean LeaveyShow line with syntax errorWhen a syntax error is encountered, show the affected line contents as well as its line number. For example, with the `m` command before it was supported (in e.g. fc5ddd90878987d1fb650340c04479f755b026c1):
```
r r1 1k n1 n2
l l1 10u n2 g...When a syntax error is encountered, show the affected line contents as well as its line number. For example, with the `m` command before it was supported (in e.g. fc5ddd90878987d1fb650340c04479f755b026c1):
```
r r1 1k n1 n2
l l1 10u n2 gnd
l l2 40u n3 gnd # winding ratio 1:2
m m1 .95 l1 l2
r r2 1k n3 gnd
freq log 1 1M 1000
uinput n1
uoutput n3
```
`circuit.liso.base.LisoParserError: LISO syntax error: unexpected parameter count (4) (line 1013)`
This should instead say something like
`circuit.liso.base.LisoParserError: LISO syntax error: unexpected parameter count (4) near "..." (line 1013)`
Not sure if this affects existing tests which look for specific patterns of error message - best check first before making this change.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/24Use an object to represent noise in op-amps and other components2019-07-12T07:36:23ZSean LeaveyUse an object to represent noise in op-amps and other componentsLISO uses a white noise and 1/f corner frequency to represent op-amp noise. Resistors have only flat Johnson noise. Instead of specifying noise with single numbers, allow components to accept a `NoiseModel` object that allows the user to...LISO uses a white noise and 1/f corner frequency to represent op-amp noise. Resistors have only flat Johnson noise. Instead of specifying noise with single numbers, allow components to accept a `NoiseModel` object that allows the user to specify more complex noise spectra. Such a model could provide a constructor for building a standard LISO-style noise spectrum, but also allow complex data either specified from a file (interpolated to new frequency vector) or using e.g. a `zpk` model.
Examples of noise that LISO can't represent:
- Resistor excess noise
- Noise in chopper-stabilised op-amps, like [LTC2057](http://www.analog.com/en/products/amplifiers/operational-amplifiers/high-voltage-op-amps-greaterthanequalto-12v/ltc2057.html), where there is a bump at the chopping frequencySean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/23Display matrix and table elements using `Quantity`2018-06-22T21:26:51ZSean LeaveyDisplay matrix and table elements using `Quantity``MatrixDisplay` and `TableDisplay` have a lot of complexity in order to display quantities properly. Change these to use the new `Quantities` class to handle display.`MatrixDisplay` and `TableDisplay` have a lot of complexity in order to display quantities properly. Change these to use the new `Quantities` class to handle display.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/22Set up integration testing on different platforms2018-06-22T07:17:51ZSean LeaveySet up integration testing on different platforms#21 highlights the need for testing on different versions of Python and different systems. Use Gitlab's CI feature to test on different platforms.#21 highlights the need for testing on different versions of Python and different systems. Use Gitlab's CI feature to test on different platforms.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/17Detect unconnected nodes in input file and warn user2019-07-03T08:32:34ZSean LeaveyDetect unconnected nodes in input file and warn userNodes that aren't connected to anything can result in outputs that may confuse the user. The simulation currently runs anyway but gets a singular matrix with no results. For example, this circuit without a grounded negative input:
```py...Nodes that aren't connected to anything can result in outputs that may confuse the user. The simulation currently runs anyway but gets a singular matrix with no results. For example, this circuit without a grounded negative input:
```python
from circuit.liso import LisoInputParser
p = LisoInputParser()
p.parse("r r1 1k n1 ninp")
p.parse("op op1 op27 ninp ninm nout")
p.parse("r r2 100k nout ninp")
p.parse("uinput n1")
p.parse("uoutput nout")
p.parse("freq log 1 100k 1000")
p.show()
```
This prints...
```
usr/local/lib/python3.5/dist-packages/scipy/sparse/linalg/dsolve/linsolve.py:192: MatrixRankWarning: Matrix is exactly singular
warn("Matrix is exactly singular", MatrixRankWarning)
```
...but still attempts to plot the (empty) results.
The solver should check that the nodes are all connected to something.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/15Allow all applicable op-amp parameters to be set as a function of frequency2018-06-04T10:30:22ZSean LeaveyAllow all applicable op-amp parameters to be set as a function of frequencyRelated to #14. Allow the specification of gain vs frequency instead of a0 and GBW, and any other applicable frequency-dependent behaviour.Related to #14. Allow the specification of gain vs frequency instead of a0 and GBW, and any other applicable frequency-dependent behaviour.Sean LeaveySean Leaveyhttps://git.ligo.org/sean-leavey/zero/-/issues/14Allow op-amp output impedance to be defined in parameter file2018-11-19T16:30:19ZSean LeaveyAllow op-amp output impedance to be defined in parameter fileThe LISO op-amp library doesn't let one define op-amp output impedance, but it does potentially matter to correctly simulate certain op-amp behaviours. Investigate how tricky it would be to add this.The LISO op-amp library doesn't let one define op-amp output impedance, but it does potentially matter to correctly simulate certain op-amp behaviours. Investigate how tricky it would be to add this.Sean LeaveySean Leavey