Commit e936f3ee authored by Sean Leavey's avatar Sean Leavey
Browse files

Merge branch 'develop' into feature/multiple-cli-inputs

parents 0be63a1a d2f079d8
......@@ -140,30 +140,28 @@ Parentheses may be used to delimit groups:
Display
~~~~~~~
The results are displayed in a table. By default, only the op-amp model names
matching a given query are displayed in the table. To add extra columns,
specify the corresponding flag as part of the call:
``--a0``
Show open loop gain.
``--gbw``
Show gain-bandwidth product.
``--delay``
Show delay.
``--vnoise``
Show flat voltage noise.
``--vcorner``
Show voltage noise corner frequency.
``--inoise``
Show flat current noise.
``--icorner``
Show current noise corner frequency.
``--vmax``
Show maximum output voltage.
``--imax``
Show maximum output current.
``--sr``
Show slew rate.
The results are displayed in a table. The rows are sorted based on the order in which the parameters
are defined in the search query, from left to right, with the leftmost parameter being sorted last.
The default sort direction is defined based on the parameter. The sort direction can be specified
explicitly as ``ASC`` (ascending) or ``DESC`` (descending) with the corresponding ``--sort``
parameter:
================== =========== =================
Flag Parameter Default direction
================== =========== =================
``--sort-a0`` ``a0`` descending
``--sort-gbw`` ``gbw`` descending
``--sort-delay`` ``delay`` ascending
``--sort-vnoise`` ``vnoise`` ascending
``--sort-vcorner`` ``vcorner`` ascending
``--sort-inoise`` ``inoise`` ascending
``--sort-icorner`` ``icorner`` ascending
``--sort-vmax`` ``vmax`` descending
``--sort-imax`` ``imax`` descending
``--sort-sr`` ``sr`` ascending
================== =========== =================
Parameters that are not explicitly searched are not ordered.
Command reference
-----------------
......
......@@ -13,6 +13,7 @@ REQUIREMENTS = [
"setuptools_scm >= 3.1.0",
"ply >= 3.11",
"Click == 7.0",
"quantiphy >= 2.5.0",
"PyYAML >= 3.13",
"graphviz >= 0.9",
]
......
"""Configuration component parser tests"""
from unittest import TestCase
from zero.config import LibraryOpAmp
class LibraryOpAmpTestCase(TestCase):
"""Library op-amp parser tests"""
def test_a0_db_scaling(self):
"""Test a0 specified in dB is correctly scaled to absolute magnitude."""
a0_abs = 1e6
opamp_a = LibraryOpAmp(a0=a0_abs)
for a0_db in ["120 dB", "120dB", "120 db", "120db", "120 DB", "120DB", "120.0 dB"]:
with self.subTest(a0_db):
opamp_b = LibraryOpAmp(a0=a0_db)
self.assertEqual(opamp_a.a0, opamp_b.a0)
......@@ -2,9 +2,9 @@
import numpy as np
from zero.data import Series, MultiNoiseDensity
from zero.misc import mag_to_db
from ..data import ZeroDataTestCase
class SeriesTestCase(ZeroDataTestCase):
"""Data series tests"""
def setUp(self):
......@@ -19,7 +19,7 @@ class SeriesTestCase(ZeroDataTestCase):
self.data_im = test_data[:, 1]
# Magnitude and phase equivalent.
self.data_mag_abs = np.abs(self.data_cplx)
self.data_mag_db = 20 * np.log10(self.data_mag_abs)
self.data_mag_db = mag_to_db(self.data_mag_abs)
self.data_phase_rad = np.angle(self.data_cplx)
self.data_phase_deg = np.degrees(self.data_phase_rad)
......
......@@ -7,16 +7,6 @@ from zero.format import Quantity
class QuantityParserTestCase(TestCase):
"""Quantity parsing tests"""
def test_invalid(self):
# invalid characters
for test_value in r" !\"€£$%^&\*\(\)\{\}\[\];:'@#~/\?><\\\|¬`":
with self.subTest(msg="Test invalid quantity", quantity=test_value):
self.assertRaisesRegex(ValueError, r"unrecognised quantity", Quantity, test_value)
# invalid strings
self.assertRaisesRegex(ValueError, r"unrecognised quantity", Quantity, "")
self.assertRaisesRegex(ValueError, r"unrecognised quantity", Quantity, "invalid")
def test_float_values(self):
"""Test parsing of float quantities"""
self.assertAlmostEqual(Quantity(1.23), 1.23)
......@@ -27,7 +17,6 @@ class QuantityParserTestCase(TestCase):
"""Test parsing of string quantities"""
self.assertAlmostEqual(Quantity("1.23"), 1.23)
self.assertAlmostEqual(Quantity("-765e3"), -765e3)
self.assertAlmostEqual(Quantity("6.3e-2.3"), 6.3 * 10 ** -2.3)
def test_string_values_with_si_scales(self):
"""Test parsing of string quantities with SI scales"""
......@@ -53,19 +42,19 @@ class QuantityParserTestCase(TestCase):
"""Test parsing of string quantities with units and SI scales"""
q = Quantity("1.23")
self.assertAlmostEqual(q, 1.23)
self.assertEqual(q.unit, None)
self.assertEqual(q.units, "")
q = Quantity("1.23 Hz")
self.assertAlmostEqual(q, 1.23)
self.assertEqual(q.unit, "Hz")
self.assertEqual(q.units, "Hz")
q = Quantity("1.69pF")
self.assertAlmostEqual(q, 1.69e-12)
self.assertEqual(q.unit, "F")
self.assertEqual(q.units, "F")
q = Quantity("3.21uH")
self.assertAlmostEqual(q, 3.21e-6)
self.assertEqual(q.unit, "H")
self.assertEqual(q.units, "H")
q = Quantity("4.88MΩ")
self.assertAlmostEqual(q, 4.88e6)
self.assertEqual(q.unit, "Ω")
self.assertEqual(q.units, "Ω")
def test_copy(self):
"""Test quantity copy constructor"""
......@@ -76,95 +65,3 @@ class QuantityParserTestCase(TestCase):
self.assertEqual(float(q), float(Quantity(q)))
# strings equal
self.assertEqual(str(q), str(Quantity(q)))
class QuantityFormatterTestCase(TestCase):
"""Quantity formatting tests"""
def test_default_format(self):
"""Test default quantities format"""
# default precision is 4
self.assertEqual(Quantity(1.23).format(), "1.2300")
self.assertEqual(Quantity("4.56k").format(), "4.5600k")
self.assertEqual(Quantity("7.89 M").format(), "7.8900M")
self.assertEqual(Quantity("1.01 GHz").format(), "1.0100 GHz")
def test_unit_format(self):
"""Test quantities with units format"""
# SI scale and unit, default precision
self.assertEqual(Quantity("1.01 GHz").format(show_unit=True, show_si=True), "1.0100 GHz")
self.assertEqual(Quantity("1.01 nHz").format(show_unit=True, show_si=True), "1.0100 nHz")
# SI scale, but no unit, default precision
self.assertEqual(Quantity("1.01 MHz").format(show_unit=False, show_si=True), "1.0100M")
self.assertEqual(Quantity("1.01 uHz").format(show_unit=False, show_si=True), "1.0100µ")
# unit, but no SI scale, default precision
self.assertEqual(Quantity("1.01 kHz").format(show_unit=True, show_si=False), "1.0100e3 Hz")
self.assertEqual(Quantity("1.01 mHz").format(show_unit=True, show_si=False), "1.0100e-3 Hz")
# no unit nor SI scale, default precision
self.assertEqual(Quantity("1.01 THz").format(show_unit=False, show_si=False), "1.0100e12")
self.assertEqual(Quantity("1.01 pHz").format(show_unit=False, show_si=False), "1.0100e-12")
# SI scale and unit, 0 decimal places
self.assertEqual(Quantity("1.01 GHz").format(show_unit=True, show_si=True, precision=0), "1 GHz")
self.assertEqual(Quantity("1.01 nHz").format(show_unit=True, show_si=True, precision=0), "1 nHz")
# SI scale, but no unit, 1 decimal place
self.assertEqual(Quantity("1.01 GHz").format(show_unit=False, show_si=True, precision=1), "1.0G")
self.assertEqual(Quantity("1.01 nHz").format(show_unit=False, show_si=True, precision=1), "1.0n")
# unit, but no SI scale, 2 decimal places
self.assertEqual(Quantity("1.01 GHz").format(show_unit=True, show_si=False, precision=2), "1.01e9 Hz")
self.assertEqual(Quantity("1.01 nHz").format(show_unit=True, show_si=False, precision=2), "1.01e-9 Hz")
# no unit nor SI scale, 3 decimal places
self.assertEqual(Quantity("1.01 GHz").format(show_unit=False, show_si=False, precision=3), "1.010e9")
self.assertEqual(Quantity("1.01 nHz").format(show_unit=False, show_si=False, precision=3), "1.010e-9")
# with decimal place move
self.assertEqual(Quantity("12345.01 GHz").format(show_unit=False, show_si=False, precision=3), "12.35e12")
self.assertEqual(Quantity("12345.01 nHz").format(show_unit=False, show_si=False, precision=3), "12.35e-6")
self.assertEqual(Quantity("0.0012345 nHz").format(show_unit=False, show_si=False, precision=3), "1.235e-12")
# SI scale and unit, full precision
self.assertEqual(Quantity("1.01 GHz").format(show_unit=True, show_si=True, precision="full"), "1.01 GHz")
self.assertEqual(Quantity("1.01 nHz").format(show_unit=True, show_si=True, precision="full"), "1.01 nHz")
# with decimal place move
self.assertEqual(Quantity("12345.01 GHz").format(show_unit=True, show_si=True, precision="full"), "12.34501 THz")
self.assertEqual(Quantity("12345.01 nHz").format(show_unit=True, show_si=True, precision="full"), "12.34501 µHz")
# SI scale, but no unit, full precision
self.assertEqual(Quantity("12.3456 GHz").format(show_unit=False, show_si=True, precision="full"), "12.3456G")
self.assertEqual(Quantity("12.3456 nHz").format(show_unit=False, show_si=True, precision="full"), "12.3456n")
# unit, but no SI scale, full precision
self.assertEqual(Quantity("123.456789 GHz").format(show_unit=True, show_si=False, precision="full"), "123.456789e9 Hz")
self.assertEqual(Quantity("123.456789 nHz").format(show_unit=True, show_si=False, precision="full"), "123.456789e-9 Hz")
# with decimal place move
self.assertEqual(Quantity("123456.789 GHz").format(show_unit=True, show_si=False, precision="full"), "123.456789e12 Hz")
self.assertEqual(Quantity("123456.789 nHz").format(show_unit=True, show_si=False, precision="full"), "123.456789e-6 Hz")
self.assertEqual(Quantity("0.00123456789 nHz").format(show_unit=True, show_si=False, precision="full"), "1.23456789e-12 Hz")
# no unit nor SI scale, full precision
self.assertEqual(Quantity("123.4567890123 GHz").format(show_unit=False, show_si=False, precision="full"), "123.4567890123e9")
self.assertEqual(Quantity("123.4567890123 nHz").format(show_unit=False, show_si=False, precision="full"), "123.4567890123e-9")
# with decimal place move
self.assertEqual(Quantity("12345.67890123 GHz").format(show_unit=False, show_si=False, precision="full"), "12.34567890123e12")
self.assertEqual(Quantity("12345.67890123 nHz").format(show_unit=False, show_si=False, precision="full"), "12.34567890123e-6")
self.assertEqual(Quantity("0.001234567890123 nHz").format(show_unit=False, show_si=False, precision="full"), "1.234567890123e-12")
# scales below f should default to exponential notation
self.assertEqual(Quantity("0.001234567890123 fHz").format(show_unit=False, show_si=False, precision="full"), "1.234567890123e-18")
self.assertEqual(Quantity("0.001234567890123 aHz").format(show_unit=False, show_si=False, precision="full"), "1.234567890123e-21")
self.assertEqual(Quantity("0.001234567890123 zHz").format(show_unit=False, show_si=False, precision="full"), "1.234567890123e-24")
self.assertEqual(Quantity("0.001234567890123 yHz").format(show_unit=False, show_si=False, precision="full"), "1.234567890123e-27")
# scales above T should default to exponential notation
self.assertEqual(Quantity("12345.67890123 THz").format(show_unit=False, show_si=False, precision="full"), "12.34567890123e15")
self.assertEqual(Quantity("12345.67890123 PHz").format(show_unit=False, show_si=False, precision="full"), "12.34567890123e18")
self.assertEqual(Quantity("12345.67890123 EHz").format(show_unit=False, show_si=False, precision="full"), "12.34567890123e21")
self.assertEqual(Quantity("12345.67890123 ZHz").format(show_unit=False, show_si=False, precision="full"), "12.34567890123e24")
self.assertEqual(Quantity("12345.67890123 YHz").format(show_unit=False, show_si=False, precision="full"), "12.34567890123e27")
......@@ -17,6 +17,9 @@ LOGGER = logging.getLogger(__name__)
CONF = ZeroConfig()
LIBRARY = OpAmpLibrary()
# Library search filter order.
LIBRARY_FILTER_CHOICE = click.Choice(("ASC", "DESC"), case_sensitive=False)
# Shared arguments:
# https://github.com/pallets/click/issues/108
......@@ -263,17 +266,19 @@ def library_show(paged):
@library.command("search")
@click.argument("query")
@click.option("--a0", is_flag=True, default=False, help="Show open loop gain.")
@click.option("--gbw", is_flag=True, default=False, help="Show gain-bandwidth product.")
@click.option("--vnoise", is_flag=True, default=False, help="Show flat voltage noise.")
@click.option("--vcorner", is_flag=True, default=False, help="Show voltage noise corner frequency.")
@click.option("--inoise", is_flag=True, default=False, help="Show flat current noise.")
@click.option("--icorner", is_flag=True, default=False, help="Show current noise corner frequency.")
@click.option("--vmax", is_flag=True, default=False, help="Show maximum output voltage.")
@click.option("--imax", is_flag=True, default=False, help="Show maximum output current.")
@click.option("--sr", is_flag=True, default=False, help="Show slew rate.")
@click.option("--sort-a0", type=LIBRARY_FILTER_CHOICE, default="DESC", show_default=True)
@click.option("--sort-gbw", type=LIBRARY_FILTER_CHOICE, default="DESC", show_default=True)
@click.option("--sort-delay", type=LIBRARY_FILTER_CHOICE, default="ASC", show_default=True)
@click.option("--sort-vnoise", type=LIBRARY_FILTER_CHOICE, default="ASC", show_default=True)
@click.option("--sort-vcorner", type=LIBRARY_FILTER_CHOICE, default="ASC", show_default=True)
@click.option("--sort-inoise", type=LIBRARY_FILTER_CHOICE, default="ASC", show_default=True)
@click.option("--sort-icorner", type=LIBRARY_FILTER_CHOICE, default="ASC", show_default=True)
@click.option("--sort-vmax", type=LIBRARY_FILTER_CHOICE, default="DESC", show_default=True)
@click.option("--sort-imax", type=LIBRARY_FILTER_CHOICE, default="DESC", show_default=True)
@click.option("--sort-sr", type=LIBRARY_FILTER_CHOICE, default="ASC", show_default=True)
@click.option("--paged", is_flag=True, default=False, help="Print results with paging.")
def library_search(query, a0, gbw, vnoise, vcorner, inoise, icorner, vmax, imax, sr, paged):
def library_search(query, sort_a0, sort_gbw, sort_delay, sort_vnoise, sort_vcorner, sort_inoise,
sort_icorner, sort_vmax, sort_imax, sort_sr, paged):
"""Search Zero op-amp library.
Op-amp parameters listed in the library can be searched:
......@@ -294,60 +299,38 @@ def library_search(query, a0, gbw, vnoise, vcorner, inoise, icorner, vmax, imax,
The query engine supports arbitrary expressions.
Example: all op-amps with noise less than 10 nV/sqrt(Hz) and corner frequency
below 10 Hz:
The 'a0' parameter can be specified in magnitude or decibels. For decibels, append 'dB' (case
insensitive) to the value.
vnoise < 10n & vcorner < 10
The results are sorted sequentially in the order that each parameter appears in the
search query (left to right). The sort direction (descending or ascending) depends on the type
of parameter. The sort direction for parameter 'X' can be overridden using the corresponding
'--sort-X' flag. Specify 'ASC' for ascending and 'DESC' for descending order.
"""
echo = click.echo_via_pager if paged else click.echo
engine = LibraryQueryEngine()
# build parameter list
params = []
if a0:
params.append("a0")
if gbw:
params.append("gbw")
if vnoise:
params.append("vnoise")
if vcorner:
params.append("vcorner")
if inoise:
params.append("inoise")
if icorner:
params.append("icorner")
if vmax:
params.append("vmax")
if imax:
params.append("imax")
if sr:
params.append("sr")
# get results
devices = engine.query(query)
sort_order = {"a0": sort_a0 == "DESC", "gbw": sort_gbw == "DESC", "delay": sort_delay == "DESC",
"vnoise": sort_vnoise == "DESC", "vcorner": sort_vcorner == "DESC",
"inoise": sort_inoise == "DESC", "icorner": sort_icorner == "DESC",
"vmax": sort_vmax == "DESC", "imax": sort_imax == "DESC", "sr": sort_sr == "DESC"}
# Get results.
devices = engine.query(query, sort_order=sort_order)
if not devices:
click.echo("No op-amps found", err=True)
sys.exit()
sys.exit(1)
nmodel = len(devices)
if nmodel == 1:
opstr = "op-amp"
else:
opstr = "op-amps"
click.echo(f"{nmodel} {opstr} found:")
header = ["Model"] + params
rows = []
for device in devices:
row = [device.model]
row.extend([str(getattr(device, param)) for param in params])
rows.append(row)
echo(tabulate(rows, header, tablefmt=CONF["format"]["table"]))
rows.append([str(getattr(device, param)) for param in engine.parameters])
table = tabulate(rows, engine.parameters, tablefmt=CONF["format"]["table"])
if paged:
click.echo_via_pager(table)
else:
click.echo(table)
@cli.group()
def config():
......
......@@ -490,7 +490,7 @@ class Inductor(PassiveComponent):
coupling_factor = self.coupling_factors[other]
mutual_inductance = coupling_factor * np.sqrt(self.inductance * other.inductance)
return Quantity(mutual_inductance, unit=self.DISPLAY_UNIT)
return Quantity(mutual_inductance, units=self.DISPLAY_UNIT)
def impedance_from(self, other, frequency):
"""Calculate the impedance this inductor has due to the specified coupled inductor
......
......@@ -5,6 +5,7 @@ import numpy as np
from .base import BaseConfig
from ..format import Quantity
from ..misc import db_to_mag
LOGGER = logging.getLogger(__name__)
......@@ -121,40 +122,21 @@ class OpAmpLibrary(BaseConfig):
if "zeros" in data and data["zeros"] is not None:
for freq in data["zeros"]:
zeros.extend(self._parse_freq_str(freq))
poles = np.array(poles)
zeros = np.array(zeros)
# Build op-amp data dict with poles and zeros as entries.
class_data = {"zeros": zeros, "poles": poles}
# Add other op-amp data.
if "a0" in data:
class_data["a0"] = Quantity(data["a0"])
if "gbw" in data:
class_data["gbw"] = Quantity(data["gbw"], "Hz")
if "delay" in data:
class_data["delay"] = Quantity(data["delay"], "s")
if "vnoise" in data:
class_data["vnoise"] = Quantity(data["vnoise"], "V/sqrt(Hz)")
if "vcorner" in data:
class_data["vcorner"] = Quantity(data["vcorner"], "Hz")
if "inoise" in data:
class_data["inoise"] = Quantity(data["inoise"], "A/sqrt(Hz)")
if "icorner" in data:
class_data["icorner"] = Quantity(data["icorner"], "Hz")
if "vmax" in data:
class_data["vmax"] = Quantity(data["vmax"], "V")
if "imax" in data:
class_data["imax"] = Quantity(data["imax"], "A")
if "sr" in data:
class_data["sr"] = Quantity(data["sr"], "V/s")
# Add data to library.
self.add_data(name, class_data)
data["poles"] = np.array(poles)
data["zeros"] = np.array(zeros)
# Check if there are aliases.
aliases = []
if "aliases" in data:
aliases = [alias.strip() for alias
in data["aliases"].split(",")]
# Create new op-amps for each alias using identical data.
for alias in aliases:
self.add_data(alias, class_data)
aliases.extend([alias.strip() for alias in data["aliases"].split(",")])
# Remove unused op-amp fields.
for field in ["aliases", "comment", "description"]:
if field in data:
del data[field]
# Add data to library.
self.add_data(name, data)
# Create new op-amps for each alias using identical data.
for alias in aliases:
self.add_data(alias, data)
def add_data(self, name, data):
"""Add op-amp data to library.
......@@ -272,12 +254,11 @@ class LibraryOpAmp:
poles=np.array([]), vnoise=3.2e-9, vcorner=2.7, inoise=0.4e-12, icorner=140,
vmax=12, imax=0.06, sr=1e6, **kwargs):
super().__init__(**kwargs)
# default properties
# Default properties.
self._model = "None"
self.params = {}
# set parameters
# Op-amp parameters.
self.model = model
self.a0 = a0
self.gbw = gbw
......@@ -307,7 +288,14 @@ class LibraryOpAmp:
@a0.setter
def a0(self, a0):
self.params["a0"] = Quantity(a0)
try:
a0 = a0.strip()
if a0[-2:].lower() == "db":
# Convert decibels to absolute magnitude.
a0 = db_to_mag(float(a0[:-2].strip()))
except AttributeError:
pass
self.params["a0"] = Quantity(a0, "V/V")
@property
def gbw(self):
......@@ -431,7 +419,6 @@ class LibraryOpAmp:
:class:`float`
Op-amp gain at specified frequency.
"""
return (self.a0
/ (1 + self.a0 * 1j * frequency / self.gbw)
* np.exp(-2j * np.pi * self.delay * frequency)
......@@ -449,19 +436,14 @@ class LibraryOpAmp:
def _mag_q_pairs(self, complex_freqs):
complex_freqs = list(complex_freqs)
pairs = []
for freq in complex_freqs:
fabs = np.absolute(freq)
freq_conj = np.conj(freq)
# find conjugate
# Find conjugate.
if freq_conj in complex_freqs:
complex_freqs.remove(freq_conj)
qfactor = fabs / (2 * np.real(freq)) # = 0.5 if real pole
pairs.append((fabs, qfactor))
return pairs
def __str__(self):
......
# Zero component library. Op-amps are based on the library from LISO, reproduced with permission
# from Gerhard Heinzel. All credit goes to him for the data and measurements.
#
# Please note: this library is experimental, incomplete and may be wrong.
# Whenever the individual op-amp properties become important, you must
# check yourself that the correct values are entered below.
# Please note: this library is experimental, incomplete and may be wrong. Whenever the individual
# op-amp properties become important, you must check yourself that the correct values are entered
# below.
#
# Strings starting with '#' are comments.
#
......@@ -11,7 +11,8 @@
# -------
#
# Everything is in SI units:
# - 'a0': DC open loop gain
# - 'a0': DC open loop gain (V / V)
# - This can be specified in decibels or absolute magnitude. For decibels, append "dB".
# - 'gbw': gain-bandwidth product for typical operating frequencies
# - 'vnoise': voltage noise spectral density (V / sqrt(Hz))
# - 'vcorner' voltage noise 1/f corner frequency
......@@ -20,13 +21,12 @@
# - 'poles': pole frequencies in the op-amp's open-loop response
# - 'zeros': zero frequencies in the op-amp's open-loop response
#
# Options that are not specified for a particular op-amp default to standard
# values. Depending on the parameter, the default can be drastically different
# from that of a particular op-amp, so be careful.
# Options that are not specified for a particular op-amp default to standard values. Depending on
# the parameter, the default can be drastically different # from that of a particular op-amp, so be
# careful.
#
# Note that multiple pole/zero frequencies can be defined for each op-amp,
# and complex values can be specified by providing the q-factor after the
# frequency, e.g.
# Note that multiple pole/zero frequencies can be defined for each op-amp, and complex values can be
# specified by providing the q-factor after the frequency, e.g.
#
# poles:
# - 100k
......@@ -35,25 +35,23 @@
#
# These values are converted into single complex values internally.
#
# Unless mentioned explicitly, values are "typical" for the cheapest grade
# at 25 degrees. a0 should usually be uncritical; these are entered for
# large loads. The 1/f corner frequencies 'vcorner' and 'icorner' (in Hz) are
# often not well defined. Poles and zeroes of the open-loop transfer function
# are interpreted as additional features to the 1/f frequency response
# Unless mentioned explicitly, values are "typical" for the cheapest grade at 25 degrees. The a0
# parameter should usually be uncritical; these are entered for large loads. The 1/f corner
# frequencies 'vcorner' and 'icorner' (in Hz) are often not well defined. Poles and zeroes of the
# open-loop transfer function are interpreted as additional features to the 1/f frequency response
# given by a0 and gbw.
#
# 'vmax' (in volts), 'imax' (in amperes) and 'sr' (in V/s) describe the
# output capabilities (used by the 'maxinput' command).
# 'vmax' (in volts), 'imax' (in amperes) and 'sr' (in V/s) describe the output capabilities (used by
# the 'maxinput' command).
#
# Identical components with different names can be specified for the root
# component by specifying their names in a list using the "aliases" entry,
# e.g.
# Identical components with different names can be specified for the root component by specifying
# their names in a list using the "aliases" entry, e.g.
#
# aliases:
# - op27
# - op47
#
# This will create identical, but distinct op-amp classes.
# This will create distinct op-amp models with identical parameters.
schema: 1
......@@ -61,7 +59,7 @@ op-amps:
op00:
description: (almost) ideal op-amp
a0: 1e12
a0: 240 dB
gbw: 1e15
vnoise: 0
vcorner: 1
......@@ -223,7 +221,7 @@ op-amps:
opa671:
description: fast FET, for photodiode transimpedance
a0: 1e4
a0: 80 dB
gbw: 35e6
vnoise: 10e-9
vcorner: 1e3
......@@ -270,7 +268,7 @@ op-amps:
ad829: &ad829
description: fast low noise voltage-feedback
comment: no ext. comp., measured at gain 1
a0: 1e5 # 100V/mV
a0: 100 dB
gbw: 85M
vnoise: 1.7e-9
vcorner: 30
......@@ -374,7 +372,7 @@ op-amps:
opa2604:
aliases: opa604
a0: 1e5
a0: 120 dB