Source code for cbadc.analog_system.leap_frog

"""The leap-frog analog system"""
import numpy as np
from .analog_system import AnalogSystem, InvalidAnalogSystemError


[docs]class LeapFrog(AnalogSystem): """Represents an leap-frog analog system. This class inherits from :py:class:`cbadc.analog_system.AnalogSystem` and creates a convenient way of creating leap-frog A/D analog systems. For more information about leap-frog ADCs see `Leap Frog ADC <https://www.research-collection.ethz.ch/bitstream/handle/20.500.11850/469192/control-bounded_converters_a_dissertation_by_hampus_malmberg.pdf?sequence=1&isAllowed=y&page=126/>`_. A leap-frog analog system is goverened by the differential equations, :math:`\dot{\mathbf{x}}(t) = \mathbf{A} \mathbf{x}(t) + \mathbf{B} \mathbf{u}(t) + \mathbf{\Gamma} \mathbf{s}(t)` :math:`\mathbf{y}(t) = \mathbf{C}^\mathsf{T} \mathbf{x}(t)` :math:`\\tilde{\mathbf{s}}(t) = \\tilde{\mathbf{\Gamma}}^\mathsf{T} \mathbf{x}(t)` where :math:`\mathbf{A} = \\begin{pmatrix} \\rho_1 & \\rho_2 \\\ \\beta_2 & 0 & \\rho_3 \\\ & \ddots & \ddots & \ddots \\\ & & \\beta_N & 0 & \\rho_{N+1} \\end{pmatrix}` :math:`\mathbf{B} = \\begin{pmatrix} \\beta_1 & 0 & \cdots & 0 \\end{pmatrix}^\mathsf{T}` :math:`\mathbf{C}^\mathsf{T} = \mathbf{I}_N` :math:`\mathbf{\Gamma} = \\begin{pmatrix} \\kappa_1 \\\ & \ddots \\\ & & \\kappa_N \\end{pmatrix}` :math:`\\tilde{\mathbf{\Gamma}}^\mathsf{T} = \mathbf{I}_N` Parameters ---------- beta : `array_like`, shape=(N,) vector with per integrator signal amplification :math:`\\begin{pmatrix}\\beta_1 & \cdots & \\beta_N \\end{pmatrix}`. alpha : `array_like`, shape=(N-1,) feedback factor vector :math:`\\begin{pmatrix}\\alpha_1 & \cdots & \\alpha_{N-1} \\end{pmatrix}`. rho : `array_like`, shape=(N,) local feedback factor vector :math:`\\begin{pmatrix}\\rho_1 & \cdots & \\rho_N \\end{pmatrix}`. kappa : `array_like`, shape=(N,) control gain vector :math:`\\begin{pmatrix}\\kappa_1 & \cdots & \\kappa_N \\end{pmatrix}`. Attributes ---------- N : `int` state space order :math:`N`. N_tilde : `int` number of signal observations :math:`\\tilde{N}`. M : `int` number of digital control signals :math:`M`. M_tilde : `int` number of control signal observations :math:`\\tilde{M}`. L : `int` number of input signals :math:`L`. A : `array_like`, shape=(N, N) system matrix :math:`\mathbf{A}`. B : `array_like`, shape=(N, L) input matrix :math:`\mathbf{B}`. CT : `array_like`, shape=(N_tilde, N) signal observation matrix :math:`\mathbf{C}^\mathsf{T}`. Gamma : `array_like`, shape=(N, M) control input matrix :math:`\mathbf{\Gamma}`. Gamma_tildeT : `array_like`, shape=(M_tilde, N) control observation matrix :math:`\\tilde{\mathbf{\Gamma}}^\mathsf{T}`. See also -------- :py:class:`cbadc.analog_system.ChainOfIntegrators` Example ------- >>> import numpy as np >>> from cbadc.analog_system import LeapFrog >>> beta = np.array([101, 102, 103]) >>> alpha = np.array([-1, -2]) >>> rho = np.array([0, 0, 0]) >>> kappa = np.arange(100,109).reshape((3, 3)) >>> system = LeapFrog(beta, alpha, rho, kappa) Raises ------ :py:class:`InvalidAnalogSystemError` For faulty analog system parametrization. """ def __init__( self, beta: np.ndarray, alpha: np.ndarray, rho: np.ndarray, kappa: np.ndarray ): """Create an leap-frog analog system.""" if beta.shape[0] != beta.size: InvalidAnalogSystemError(self, "beta must be a one dimensional vector") if alpha.shape[0] != alpha.size: InvalidAnalogSystemError(self, "alpha must be a one dimensional vector") if rho.shape[0] != rho.size: InvalidAnalogSystemError(self, "rho must be a one dimensional vector") if kappa.shape[0] != kappa.size: InvalidAnalogSystemError(self, "kappa must be a one dimensional vector") if beta.size != rho.size and rho.size != kappa.size: InvalidAnalogSystemError( self, "beta, rho, kappa vector must be of same size" ) # State space order N = beta.size # Analog system parameters A = np.diag(alpha, k=1) + np.diag(beta[1:], k=-1) + np.diag(rho) B = np.zeros((N, 1)) B[0] = beta[0] CT = np.eye(N) # CT = np.zeros((1, N)) # CT[-1] = 1 # Check if Kappa is specified as a vector if kappa.shape[1] == 1: Gamma = np.diag(kappa.flatten()) else: Gamma = np.array(kappa, dtype=np.double) Gamma_tildeT = -Gamma.transpose() for row_index in range(Gamma_tildeT.shape[0]): Gamma_tildeT[row_index, :] = Gamma_tildeT[row_index, :] / np.linalg.norm( Gamma_tildeT[row_index, :] ) # initialize parent class AnalogSystem.__init__(self, A, B, CT, Gamma, Gamma_tildeT)