1+ """SAR ADC models"""
2+
3+ import numpy as np
4+ from adc_eval .adcs .basic import ADC
5+
6+
7+ class SAR (ADC ):
8+ """
9+ SAR ADC Class.
10+
11+ Parameters
12+ ----------
13+ nbits : int, optional
14+ Number of bits for the ADC. The default is 8.
15+ fs : float, optional
16+ Sample rate for the ADC in Hz. The default is 1Hz.
17+ vref : float, optional
18+ Reference level of the ADC in Volts ([0, +vref] conversion range). The default is 1.
19+ seed : int, optional
20+ Seed for random variable generation. The default is 1.
21+ **kwargs
22+ Extra arguments.
23+ weights : list, optional
24+ List of weights for SAR capacitors. Must be >= nbits. Defaults to binary weights.
25+ MSB weight should be in index 0.
26+
27+ Attributes
28+ -------
29+ vin : float
30+ Sets or returns the current input voltage level. Assumed +/-vref/2 input
31+ vlsb : float
32+ LSB voltage of the converter. vref/2^nbits
33+ noise : float, default=0
34+ Sets or returns the stdev of the noise generated by the converter.
35+ weights : list
36+ Sets or returns the capacitor weighting of the array. Default is binary weighting.
37+ mismatch : float
38+ Sets or returns the stdev of the mismatch of the converter. Default is no mismatch.
39+ offset : tuple of float
40+ Sets the (mean, stdev) of the offset of the converter. Default is no offset.
41+ gain_error : tuple of float
42+ Sets the (mean, stdev) of the gain error of the converter. Default is no gain error.
43+ distortion : list of float
44+ Sets the harmonic distortion values with index=0 corresponding to HD1.
45+ Example: For unity gain and only -30dB of HD3, input is [1, 0, 0.032]
46+ dout : int
47+ Digital output code for current vin value.
48+
49+ Methods
50+ -------
51+ run_step
52+
53+ """
54+
55+ def __init__ (self , nbits = 8 , fs = 1 , vref = 1 , seed = 1 , ** kwargs ):
56+ """Initialization function for Generic ADC."""
57+ super ().__init__ (nbits , fs , vref , seed )
58+
59+ self ._mismatch = None
60+
61+ # Get keyword arguments
62+ self ._weights = kwargs .get ("weights" , None )
63+
64+ @property
65+ def weights (self ):
66+ """Returns capacitor unit weights."""
67+ if self ._weights is None :
68+ self ._weights = np .flip (2 ** np .linspace (0 , self .nbits - 1 , self .nbits ))
69+ return np .array (self ._weights )
70+
71+ @weights .setter
72+ def weights (self , values ):
73+ """Sets the capacitor unit weights."""
74+ self ._weights = np .array (values )
75+ if self ._weights .size < self .nbits :
76+ print (f"WARNING: Capacitor weight array size is { self ._weights .size } for { self .nbits } -bit ADC." )
77+ self .mismatch = self .err ["mismatch" ]
78+
79+ @property
80+ def mismatch (self ):
81+ """Return noise stdev."""
82+ if self ._mismatch is None :
83+ self ._mismatch = np .zeros (self .weights .size )
84+ return self ._mismatch
85+
86+ @mismatch .setter
87+ def mismatch (self , stdev ):
88+ """Sets mismatch stdev."""
89+ self .err ["mismatch" ] = stdev
90+ self ._mismatch = np .random .normal (0 , stdev , self .weights .size )
91+ self ._mismatch /= np .sqrt (self .weights )
92+
93+ def run_step (self ):
94+ """Run a single ADC step."""
95+ vinx = self .vin
96+
97+ cweights = self .weights * (1 + self .mismatch )
98+ cdenom = sum (cweights ) + 1
99+
100+ comp_noise = np .random .normal (0 , self .err ["noise" ], cweights .size )
101+
102+ # Bit cycling
103+ vdac = vinx
104+ for n in range (len (cweights )):
105+ vcomp = vdac - self .vref / 2
106+ compout = vcomp * 1e6
107+ compout = - 1 if compout <= 0 else 1
108+ self .dbits [n ] = max (0 , compout )
109+ vdac -= compout * self .vref / 2 * cweights [n ] / cdenom
110+
111+ # Re-scale the data
112+ scalar = 2 ** self .nbits / cdenom
113+ self .dval = min (2 ** self .nbits - 1 , scalar * sum (self .weights * self .dbits ))
0 commit comments