Source code for denspp.offline.analog.amplifier.cur_amp

from dataclasses import dataclass
import numpy as np
from denspp.offline.analog.common_func import CommonAnalogFunctions
from denspp.offline.analog.dev_noise import ProcessNoise, SettingsNoise, DefaultSettingsNoise


[docs] @dataclass class SettingsCUR: """Individual data class to configure the current amplifier Attributes: vdd: Positive supply voltage [V] vss: Negative supply voltage [V] fs_ana: Sampling frequency of input [Hz] transimpedance: Transimpedance value [V/A] offset_v: Offset voltage of current amplifier [V] offset_i: Offset current of current amplifier [A] noise_en: Enable noise on output [True / False] para_en: Enable parasitic [True / False] """ vdd: float vss: float fs_ana: float # Amplifier characteristics transimpedance: float offset_v: float offset_i: float # Settings for parasitic noise_en: bool para_en: bool @property def vcm(self) -> float: return (self.vdd + self.vss) / 2
DefaultSettingsCUR = SettingsCUR( vdd=0.9, vss=-0.9, fs_ana=50e3, transimpedance=1e3, offset_v=1e-6, offset_i=1e-12, noise_en=False, para_en=False )
[docs] class CurrentAmplifier(CommonAnalogFunctions): _handler_noise: ProcessNoise _settings: SettingsCUR def __init__(self, settings_dev: SettingsCUR, settings_noise: SettingsNoise=DefaultSettingsNoise) -> None: """Class for emulating an analogue current amplifier :param settings_dev: Dataclass for handling the current amplifier :param settings_noise: Dataclass for handling the noise and parasitic simulation """ super().__init__() self.define_voltage_range(volt_low=settings_dev.vss, volt_hgh=settings_dev.vdd) self._handler_noise = ProcessNoise(settings_noise, settings_dev.fs_ana) self._settings = settings_dev @property def vcm(self) -> float: return self._settings.vcm def _add_parasitic(self, size: int, resistance: float=1.0) -> np.ndarray: u_para = np.zeros((size, )) u_para += self._settings.transimpedance * self._settings.offset_i u_para += self._settings.offset_v u_para += self._settings.vcm if self._settings.noise_en: u_para += self._handler_noise.gen_noise_real_volt(size, resistance) return u_para def _build_ref_difference(self, u_ref: np.ndarray | float) -> np.ndarray | float: return u_ref - self._settings.vcm
[docs] def transimpedance_amplifier(self, i_in: np.ndarray, u_ref: np.ndarray | float) -> np.ndarray: """Performing the transimpedance amplifier (single, normal) with input signal Args: i_in: Input current [A] u_ref: Negative input voltage [V] Returns: Corresponding numpy array with output voltage """ u_out = self._settings.transimpedance * i_in u_out += self._build_ref_difference(u_ref) u_out += self._add_parasitic(u_out.size) return self.clamp_voltage(u_out)
[docs] def instrumentation_amplifier(self, i_in: np.ndarray, u_off: np.ndarray | float, v_gain: float=1.0) -> np.ndarray: """Using an instrumentation amplifier for current sensing Args: i_in: Input current [A] u_off: Offset output voltage [V] v_gain: Gain of Amplifier [V/V] Returns: Corresponding numpy array with output voltage """ r_sense = self._settings.transimpedance u_out = r_sense * i_in u_out += self._build_ref_difference(u_off) u_out += self._add_parasitic(u_out.size, r_sense) return self.clamp_voltage(v_gain * u_out)
[docs] def push_amplifier(self, i_in: np.ndarray, u_ref: float) -> np.ndarray: """Performing the CMOS push/source current amplifier Args: i_in: Input current [A] u_ref: Negative input voltage [V] Returns: Corresponding numpy array with output voltage """ u_out = np.zeros_like(i_in) x_neg = np.argwhere(i_in < u_ref) u_out[x_neg,] = i_in[x_neg,] * self._settings.transimpedance u_out += self._add_parasitic(u_out.size, self._settings.transimpedance) return self.clamp_voltage(u_out)
[docs] def pull_amplifier(self, i_in: np.ndarray, u_ref: float) -> np.ndarray: """Performing the CMOS pull/sink current amplifier Args: i_in: Input current [A] u_ref: Negative input voltage [V] Returns: Corresponding numpy array with output voltage """ u_out = np.zeros_like(i_in) x_pos = np.argwhere(i_in >= u_ref) u_out[x_pos, ] = i_in[x_pos,] * self._settings.transimpedance u_out += self._add_parasitic(u_out.size, self._settings.transimpedance) return self.clamp_voltage(u_out)
[docs] def push_pull_amplifier(self, i_in: np.ndarray, u_ref: float) -> tuple[np.ndarray, np.ndarray]: """Performing the CMOS push-pull current amplifier Args: i_in: Input current [A] Returns: Tuple with corresponding numpy array of output voltage (positive, negative) """ u_pos = self.pull_amplifier(i_in, u_ref) u_neg = self.push_amplifier(i_in, u_ref) return u_pos, u_neg
[docs] def push_pull_abs_amplifier(self, i_in: np.ndarray, u_ref: float) -> np.ndarray: """Performing the CMOS push-pull current absolute amplifier Args: i_in: Input current [A] u_ref: Negative input voltage [V] Returns: Corresponding numpy array with output voltage """ u_out = self.pull_amplifier(i_in, u_ref) u_out -= self.push_amplifier(i_in, u_ref) return u_out