Source code for denspp.offline.analog.adc.adc_sar

import numpy as np
from .adc_basic import BasicADC
from .adc_settings import SettingsADC, SettingsNon, RecommendedSettingsNon
from denspp.offline.analog.dev_noise import ProcessNoise


[docs] class SuccessiveApproximation(BasicADC): _settings: SettingsADC _handler_noise: ProcessNoise def __init__(self, settings_dev: SettingsADC, settings_non: SettingsNon = RecommendedSettingsNon) -> None: """"Class for applying a Successive Approximation (SAR) Analogue-Digital-Converter (ADC) on the raw data :param settings_dev: Configuration class for defining properties of ADC :param settings_non: Configuration class for non-idealities / parasitics of ADC (next feature) """ super().__init__(settings_dev) self.__use_noise = settings_non.use_noise # --- Transfer function self.__partition_digital = 2 ** np.arange(0, self._settings.Nadc) self.__partition_voltage = (self.__partition_digital / 2 ** self._settings.Nadc) * self._settings.vref_range self.__type_offset = [2 ** (self._settings.Nadc - 1) if self._settings.is_signed else 0] # --- Internal signals for noise shaping self.alpha_int = [1.0, 0.5] self.__stage_one_dly = self._settings.vcm self.__stage_two_dly = self._settings.vcm def __adc_sar_sample(self, uin: np.ndarray) -> [np.ndarray, np.ndarray]: """Running the SAR on input data""" # --- Bitmask generation BitMask = np.zeros(shape=(self._settings.Nadc,), dtype=int) BitMask[-1] = 1 # --- Run SAR code for idx in range(0, self._settings.Nadc): uref = self._settings.vref[1] + np.sum(BitMask * self.__partition_voltage) BitMask[self._settings.Nadc - 1 - idx] = np.heaviside(uin - uref, 1) if not idx == self._settings.Nadc - 1: BitMask[self._settings.Nadc - 2 - idx] = 1 uout = self._settings.vref[1] + np.sum(BitMask * self.__partition_voltage) xout = (np.sum(BitMask * self.__partition_digital) - self.__type_offset).astype(int) return uout, xout
[docs] def adc_sar(self, uin: np.ndarray) -> [np.ndarray, np.ndarray, np.ndarray]: """Running the SAR Topology as an ADC Args: uin: Input voltage Returns: Tuple with three numpy arrays [x_out = Output digital value, u_out = Output digitized voltage, quant_er = Quantization error] """ # Resampling of input uin_adc = self.clamp_voltage(uin) uin0 = self._do_resample(uin_adc) unoise = self._gen_noise(uin0.size) if self.__use_noise else np.zeros(shape=uin0.shape) # Running SAR code xout, uout, uerr = self._generate_sar_empty_data(uin0.shape) for idx, umod in enumerate(uin0): calc_out = self.__adc_sar_sample(umod) uout[idx] = calc_out[0] + unoise[idx] xout[idx] = calc_out[1] + np.floor(unoise[idx] / self._settings.lsb) uerr[idx] = umod - uout[idx] return xout, uout, uerr
[docs] def adc_sar_ns_delay(self, uin: np.ndarray) -> [np.ndarray, np.ndarray, np.ndarray]: """Running the Noise Shaping SAR Topology (Delay of last sample) Args: uin: Input voltage Returns: Tuple with three numpy arrays [x_out = Output digital value, u_out = Output digitized voltage, quant_er = Quantization error] """ # Resampling of input uin_adc = self.clamp_voltage(uin) uin0 = self._do_resample(uin_adc) unoise = self._gen_noise(uin0.size) if self.__use_noise else np.zeros(shape=uin0.shape) # Running SAR code xout, uout, uerr = self._generate_sar_empty_data(uin0.shape) for idx, din in enumerate(uin0): umod = din + self.__stage_one_dly calc_out = self.__adc_sar_sample(umod) uout[idx] = calc_out[0] + unoise[idx] xout[idx] = calc_out[1] + np.floor(unoise[idx] / self._settings.lsb) uerr[idx] = din - uout[idx] # --- Noise shaping post-processing self.__stage_one_dly = uerr[idx] return xout, uout, uerr
[docs] def adc_sar_ns_order_one(self, uin: np.ndarray) -> [np.ndarray, np.ndarray, np.ndarray]: """Running the Noise Shaping SAR Topology (First order with integration) Args: uin: Input voltage Returns: Tuple with three numpy arrays [x_out = Output digital value, u_out = Output digitized voltage, quant_er = Quantization error] """ # Resampling of input uin_adc = self.clamp_voltage(uin) uin0 = self._do_resample(uin_adc) unoise = self._gen_noise(uin0.size) if self.__use_noise else np.zeros(shape=uin0.shape) # Running SAR code xout, uout, uerr = self._generate_sar_empty_data(uin0.shape) for idx, din in enumerate(uin0): # --- SAR processing umod = din + self.__stage_one_dly calc_out = self.__adc_sar_sample(umod) uout[idx] = calc_out[0] + unoise[idx] xout[idx] = calc_out[1] + np.floor(unoise[idx] / self._settings.lsb) uerr[idx] = din - uout[idx] # --- Post-processing: Noise shaping self.__stage_one_dly += self.alpha_int[0] * uerr[idx] return xout, uout, uerr
[docs] def adc_sar_ns_order_two(self, uin: np.ndarray) -> [np.ndarray, np.ndarray, np.ndarray]: """Running the Noise Shaping SAR Topology (Second order with integration) Args: uin: Input voltage Returns: Tuple with three numpy arrays [x_out = Output digital value, u_out = Output digitized voltage, quant_er = Quantization error] """ # Resampling of input uin_adc = self.clamp_voltage(uin) uin0 = self._do_resample(uin_adc) unoise = self._gen_noise(uin0.size) if self.__use_noise else np.zeros( shape=uin0.shape) # Running SAR code xout, uout, uerr = self._generate_sar_empty_data(uin0.shape) for idx, din in enumerate(uin0): umod = din + self.__stage_two_dly calc_out = self.__adc_sar_sample(umod) uout[idx] = calc_out[0] + unoise[idx] xout[idx] = calc_out[1] + np.floor(unoise[idx] / self._settings.lsb) uerr[idx] = din - uout[idx] # --- Noise shaping post-processing self.__stage_one_dly += self.alpha_int[0] * uerr[idx] self.__stage_two_dly += self.alpha_int[1] * self.__stage_one_dly return xout, uout, uerr