Source code for cbadc.circuit.opamp

from typing import Tuple
from . import Terminal, SubCircuitElement, Ground
from ..analog_frontend import AnalogFrontend
from ..analog_system import AnalogSystem
from ..digital_control import DigitalControl as NominalDigitalControl
from ..digital_control.dither_control import DitherControl as NominalDitherControl
from .components.passives import Resistor, Capacitor
import numpy as np
from .components.opamp import OpAmp
from .digital_control import DigitalControl, DitherControl
from .analog_frontend import CircuitAnalogFrontend


[docs]class OpAmpFrontend(CircuitAnalogFrontend): """An opamp-based analog frontend. Parameters ---------- analog_frontend : AnalogFrontend The analog frontend to which this opamp-based analog frontend belongs. GBWP : float The GBWP of the opamp. DC_gain : float The DC gain of the opamp. vdd_voltage : float, optional The supply voltage of the opamp, by default 1.2. in_high : float, optional The high input voltage of the opamp, by default 0.0. in_low : float, optional The low input voltage of the opamp, by default 0.0. C_int : float, optional The integration capacitance, by default 100e-15. C_amp : float, optional The capacitance of the internal opamp pole, by default 10e-15. """ C: float def __init__( self, analog_frontend: AnalogFrontend, GBWP: float, DC_gain: float, vdd_voltage: float = 1.2, in_high=0.0, in_low=0.0, C_int: float = 100e-15, C_amp: float = 10e-15, ): self.analog_frontend = analog_frontend self.vgndp = [ Terminal(f"VGND_{i}_P") for i in range(analog_frontend.analog_system.N) ] self.vgndn = [ Terminal(f"VGND_{i}_N") for i in range(analog_frontend.analog_system.N) ] super().__init__( analog_frontend, vdd_voltage, in_high, in_low, subckt_name="opamp_analog_frontend", instance_name="Xaf", ) self._generate_state_resistor_network(analog_frontend, C_int) # self._generate_observation_network(analog_frontend.analog_system) self._generate_integrators( analog_frontend.analog_system, GBWP, DC_gain, C_amp, C_int ) def _generate_integrators( self, analog_system: AnalogSystem, GBWP: float, DC_gain: float, C_amp: float, C_int: float, ): opamps = [ OpAmp( f"Xop_{n}", "opamp", GBWP=GBWP, DC_gain=DC_gain, C=C_amp, ) for n in range(analog_system.N) ] self.add(*opamps) for n in range(analog_system.N): self.connects( (self.xp[n], opamps[n]["OUT_P"]), (self.xn[n], opamps[n]["OUT_N"]), (self.vgndp[n], opamps[n]["IN_P"]), (self.vgndn[n], opamps[n]["IN_N"]), (self["VSS"], opamps[n]["VSS"]), (self["VDD"], opamps[n]["VDD"]), (self["VCM"], opamps[n]["VCM"]), ) _caps_p = [ Capacitor( f"CP_{index}", C_int, ) for index in range(analog_system.N) ] _caps_n = [ Capacitor( f"CN_{index}", C_int, ) for index in range(analog_system.N) ] self.add(*_caps_p, *_caps_n) for n in range(analog_system.N): self.connects( (self.xp[n], _caps_p[n][1]), (self.vgndp[n], _caps_p[n][0]), (self.xn[n], _caps_n[n][1]), (self.vgndn[n], _caps_n[n][0]), ) def _generate_resistor_pair( self, nominal_value: float, instance_name: str, t1: Tuple[Terminal, Terminal], t2: Tuple[Terminal, Terminal], C_int: float, ): _RP = Resistor(f"RP_{instance_name}", 1.0 / (1 * C_int * np.abs(nominal_value))) _RN = Resistor(f"RN_{instance_name}", 1.0 / (1 * C_int * np.abs(nominal_value))) self.add(_RP, _RN) if nominal_value < 0: # inverting connection self.connect(t1[0], _RP[0]) self.connect(t1[1], _RN[0]) self.connect(t2[0], _RP[1]) self.connect(t2[1], _RN[1]) else: # non-inverting connection self.connect(t1[0], _RP[0]) self.connect(t1[1], _RN[0]) self.connect(t2[0], _RN[1]) self.connect(t2[1], _RP[1]) def _generate_state_resistor_network( self, analog_frontend: AnalogFrontend, C_int: float ): if analog_frontend.analog_system.Gamma is None: raise BaseException("Gamma must not be Nonw") # B Matrix for n in range(analog_frontend.analog_system.N): for l in range(analog_frontend.analog_system.L): if analog_frontend.analog_system.B[n, l] != 0.0: self._generate_resistor_pair( analog_frontend.analog_system.B[n, l], f"b_{n}_{l}", ( self[f"IN{l}_P"], self[f"IN{l}_N"], ), (self.vgndp[n], self.vgndn[n]), C_int, ) # A Matrix for n in range(analog_frontend.analog_system.N): for nn in range(analog_frontend.analog_system.N): if analog_frontend.analog_system.A[n, nn] != 0.0: self._generate_resistor_pair( analog_frontend.analog_system.A[n, nn], f"a_{n}_{nn}", (self.xp[nn], self.xn[nn]), (self.vgndp[n], self.vgndn[n]), C_int, ) # Gamma Matrix for n in range(analog_frontend.analog_system.N): for m in range(analog_frontend.analog_system.M): if analog_frontend.analog_system.Gamma[n, m] != 0.0: self._generate_resistor_pair( analog_frontend.analog_system.Gamma[n, m], f"gamma_{n}_{m}", ( self[f"OUT{m}_P"], self[f"OUT{m}_N"], ), (self.vgndp[n], self.vgndn[n]), C_int, )