Source code for denspp.offline.analog.adc.adc_deltasigma
import numpy as np
from .adc_basic import BasicADC
from .adc_settings import SettingsADC, RecommendedSettingsADC, SettingsNon, RecommendedSettingsNon
from denspp.offline.analog.dev_noise import ProcessNoise
[docs]
class DeltaSigmaADC(BasicADC):
_settings: SettingsADC
_handler_noise: ProcessNoise
def __init__(self, settings_dev: SettingsADC, settings_non=RecommendedSettingsNon, dac_order: int=2) -> None:
"""Class for using Continuous Time Delta Sigma ADC
:param settings_dev: Configuration class for defining properties of ADC
:param settings_non: Configuration class for non-idealities / parasitics of ADC (next feature)
:param dac_order: Number of bits of used DAC in feedback
"""
super().__init__(settings_dev)
# --- Internal variables
self.use_noise = False
self.__dac_order = dac_order
self.__partition_digital = np.arange(0, 2 ** self.__dac_order, 1) / 2 ** self.__dac_order
self.__partition_voltage = self._settings.vref[1] + self.__partition_digital * self._settings.vref_range + self._settings.lsb / 2
# --- Variables for post-processing (noise-shaping)
self.__stage_one_dly = self._settings.vcm
self.__stage_two_dly = self._settings.vcm
def __ds_modulator(self, uin: np.ndarray, ufb: np.ndarray) -> np.ndarray:
"""Performing first order delta sigma modulator
inputs:
uin - input voltage
ufb - feedback voltage
output:
du - difference voltage
"""
du = uin - ufb
# Voltage clipping
du = du if not du > self._settings.vdd else self._settings.vdd
du = du if not du < self._settings.vss else self._settings.vss
# Output
return du
@staticmethod
def __stream_converter(xin: int) -> np.ndarray:
"""Performing the stream conversion"""
xout = (1 + np.sum((-1) ** (1 - xin))) / 2
return xout
def __comp_1bit(self, uin: float) -> [np.ndarray, np.ndarray]:
"""1-bit DAC for DS modulation"""
xout = np.heaviside(uin - self._settings.vcm, 1)
ufb = self._settings.vref[0] if xout == 1 else self._settings.vref[1]
return xout, ufb
def __comp_Nbit(self, uin: float) -> [np.ndarray, np.ndarray]:
"""N-bit DAC for DS modulation"""
input = uin * np.ones(shape=self.__partition_voltage.shape)
result = np.heaviside(input - self.__partition_voltage, 1)
xout = np.sum(result)
ufb = self._settings.vref[1] + xout * self._settings.lsb
return xout, ufb
[docs]
def adc_deltasigma_order_one(self, uin: np.ndarray) -> np.ndarray:
""""Using the Delta Sigma Topology as an ADC (1-bit, first order)
Args:
uin: Input voltage [V]
Returns:
Corresponding digitized data value from Delta-Sigma ADC
"""
# Resampling the input to sampling frequency of ADC with oversampling
uin_adc = self.clamp_voltage(uin)
uin0 = self._do_resample(uin_adc)
uin0 += self._gen_noise(uin0.size) if self.use_noise == True else np.zeros(shape=uin0.shape)
# Running the delta sigma modulator
xout_hs, xbit = self._generate_dsigma_empty_data(uin0.shape)
umod_one = self._settings.vcm
ufb0 = self._settings.vref[1]
# --- DS Modulator (at high frequency)
for idx, umod in enumerate(uin0):
umod_one += self.__ds_modulator(umod, ufb0)
xbit[idx], ufb0 = self.__comp_1bit(umod_one)
xout_hs[idx] = self.__stream_converter(xbit[idx])
# --- Downsampling
xout0 = self.do_decimation_polyphase_order_two(xout_hs)
xout1 = self.do_decimation_polyphase_order_two(xout0)
xout2 = self.do_decimation_polyphase_order_two(xout1)
xout3 = self.do_decimation_polyphase_order_two(xout2)
xout4 = self.do_decimation_polyphase_order_two(xout3)
# --- Correction and output
xout = xout4
xout -= 2 ** (self._settings.Nadc - 1) if self._settings.type_out == "signed" else 0
xout = self.clamp_digital(xout)
return xout
[docs]
def adc_deltasigma_order_two(self, uin: np.ndarray) -> np.ndarray:
""""Using the Delta Sigma Topology as an ADC (1-bit, second order)
Args:
uin: Input voltage [V]
Returns:
Corresponding digitized data value from Delta-Sigma ADC
"""
# Resampling the input to sampling frequency of ADC with oversampling
uin_adc = self.clamp_voltage(uin)
uin0 = self._do_resample(uin_adc)
uin0 += self._gen_noise(uin0.size) if self.use_noise else np.zeros(shape=uin0.shape)
# Running the delta sigma modulator
xout_hs, xbit = self._generate_dsigma_empty_data(uin0.shape)
umod_one = self._settings.vcm
umod_two = self._settings.vcm
ufb0 = self._settings.vref[1]
# --- DS Modulator (at high frequency)
for idx, umod in enumerate(uin0):
umod_one += self.__ds_modulator(umod, ufb0)
umod_two += self.__ds_modulator(umod_one, self._settings.vcm)
xbit[idx], ufb0 = self.__comp_1bit(umod_two)
xout_hs[idx] = self.__stream_converter(xbit[idx])
# --- Downsampling
xout0 = self.do_decimation_polyphase_order_two(xout_hs)
xout1 = self.do_decimation_polyphase_order_two(xout0)
xout2 = self.do_decimation_polyphase_order_two(xout1)
xout3 = self.do_decimation_polyphase_order_two(xout2)
xout4 = self.do_decimation_polyphase_order_two(xout3)
# --- Correction and output
xout = xout4
xout -= 2 ** (self._settings.Nadc - 1) if self._settings.type_out == "signed" else 0
xout = self.clamp_digital(xout)
return xout