Source code for cbadc.digital_control.switch_capacitor_control

"""Switched capacitor digital control"""
import numpy as np
from .digital_control import DigitalControl


[docs]class SwitchedCapacitorControl(DigitalControl): """Represents a digital control system that uses switched capacitor control Parameters ---------- T : `float total clock period T1 : `float`, `array_like`, shape=(M,) time at which the digital control empties the capacitor into the system. Can be either float or array of float. T2 : `float`, `array_like`, shape=(M,) time at which the switched capacitor is re-charged and disconnected from the analog system. M : `int` number of controls. A: array_like, shape(M,M), optional dynamical system model. t0 : `float`, optional determines initial time, defaults to 0. VCap: `float`, optional the voltage stored on each capacitor before discharge, defaults to 1. Attributes ---------- T : `float` total clock period :math:`T` of digital control system. T1 : `array_like`, shape=(M,) discharge phase time T2 : `float` charge phase time M : `int` number of controls :math:`M`. M_tilde : `int` number of control observations :math:`\\tilde{M}`. Note ---- For this digital control system :math:`M=\\tilde{M}`. """ def __init__(self, T, T1, T2, M, A, t0=0, VCap=1.0): raise DeprecationWarning("SwitchedCapacitorControl is deprecated.") if isinstance(T1, (list, tuple, np.ndarray)): self.T1 = np.array(T1, dtype=np.double) else: self.T1 = T1 * np.ones(M, dtype=np.double) self._T1_next = t0 + self.T1 if isinstance(T2, (list, tuple, np.ndarray)): self.T2 = np.array(T2, dtype=np.double) else: self.T2 = T2 * np.ones(T2, dtype=np.double) self._T2_next = t0 + self.T2 self.M = M # Check for invalid period times. for m in range(self.M): if self.T2[m] <= self.T1[m] or (self.T2[m] + T == self.T1[m]): raise Exception( f"Invalid T1={self.T1[m]} and T2={self.T2[m]} for m={m}" ) self.T = T if (self.T < self.T1).any() or (2 * self.T < self.T2).any(): raise Exception("T1 cannot exceed T and T2 cannot exceed 2T.") self.phase = np.zeros(M, dtype=int) if not isinstance(self.M, int): raise Exception("M must be an integer.") self._s = np.zeros(self.M, dtype=int) self.A = np.array(A, dtype=np.double) self.VCap = VCap def next_update(self): t_next = np.inf for m in range(self.M): if self._T1_next[m] < t_next: t_next = self._T1_next[m] if self._T2_next[m] < t_next: t_next = self._T2_next[m] return t_next
[docs] def control_update(self, t, s_tilde: np.ndarray): # Check if time t has passed the next control update\ reset = np.zeros(self.M, dtype=bool) for m in range(self.M): if not t < self._T2_next[m]: self.phase[m] = 1 reset[m] = True self._T2_next[m] += self.T elif not t < self._T1_next[m]: self._s[m] = s_tilde[m] > 0 self.phase[m] = 0 reset[m] = True self._T1_next[m] += self.T return self.phase, reset, self._s
[docs] def control_signal(self) -> np.ndarray: """Returns the current control state, i.e, :math:`\mathbf{s}[k]`. Returns ------- `array_like`, shape=(M,), dtype=numpy.int8 current control state. """ return self._s