Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
e2e4dc2
Bump ruff from 0.4.10 to 0.5.0
dependabot[bot] Jul 1, 2024
0dd1c70
Bump pylint from 3.2.3 to 3.2.5
dependabot[bot] Jul 1, 2024
dacd90d
Merge pull request #56 from fronzbot/dependabot/pip/pylint-3.2.5
fronzbot Jul 2, 2024
72f5f23
Merge pull request #55 from fronzbot/dependabot/pip/ruff-0.5.0
fronzbot Jul 2, 2024
a3506cd
Bump matplotlib from 3.9.0 to 3.9.1
dependabot[bot] Jul 8, 2024
9ded6a4
Bump ruff from 0.5.0 to 0.5.1
dependabot[bot] Jul 8, 2024
3543b1b
Merge pull request #59 from fronzbot/dependabot/pip/ruff-0.5.1
fronzbot Jul 11, 2024
7d6fb20
Merge pull request #57 from fronzbot/dependabot/pip/matplotlib-3.9.1
fronzbot Jul 11, 2024
f16a270
Bump tox from 4.15.1 to 4.16.0
dependabot[bot] Jul 11, 2024
7e9d58e
Merge pull request #58 from fronzbot/dependabot/pip/tox-4.16.0
fronzbot Jul 11, 2024
0f5de4b
Bump ruff from 0.5.1 to 0.5.2
dependabot[bot] Jul 15, 2024
1bd804a
Bump coverage from 7.5.4 to 7.6.0
dependabot[bot] Jul 15, 2024
cd2fa4b
Merge pull request #60 from fronzbot/dependabot/pip/ruff-0.5.2
fronzbot Jul 15, 2024
2048760
Merge pull request #61 from fronzbot/dependabot/pip/coverage-7.6.0
fronzbot Jul 15, 2024
d2cf9e9
Bump pytest from 8.2.2 to 8.3.2
dependabot[bot] Jul 29, 2024
0241305
Bump black from 24.4.2 to 24.8.0
dependabot[bot] Aug 5, 2024
7c5df6d
Bump matplotlib from 3.9.1 to 3.9.2
dependabot[bot] Aug 19, 2024
7fa9f71
Bump ruff from 0.5.2 to 0.6.3
dependabot[bot] Sep 2, 2024
cd89138
Fix some math to account for leaky bins
fronzbot Sep 3, 2024
ed2d0e0
Merge pull request #74 from fronzbot/dependabot/pip/ruff-0.6.3
fronzbot Sep 3, 2024
bbd553d
Merge pull request #69 from fronzbot/dependabot/pip/black-24.8.0
fronzbot Sep 3, 2024
635f689
Merge pull request #65 from fronzbot/dependabot/pip/pytest-8.3.2
fronzbot Sep 3, 2024
c783213
Merge pull request #70 from fronzbot/dependabot/pip/matplotlib-3.9.2
fronzbot Sep 3, 2024
94b9619
Bump pylint from 3.2.5 to 3.2.7
dependabot[bot] Sep 3, 2024
692c0d9
Merge pull request #76 from fronzbot/fix-leaky-signals
fronzbot Sep 3, 2024
9b2a760
Bump tox from 4.16.0 to 4.18.0
dependabot[bot] Sep 3, 2024
250dae2
Merge pull request #75 from fronzbot/dependabot/pip/pylint-3.2.7
fronzbot Sep 3, 2024
8ac0f04
Bump coverage from 7.6.0 to 7.6.1
dependabot[bot] Sep 3, 2024
e31dede
Merge pull request #67 from fronzbot/dependabot/pip/coverage-7.6.1
fronzbot Sep 3, 2024
9055b27
Merge pull request #72 from fronzbot/dependabot/pip/tox-4.18.0
fronzbot Sep 3, 2024
0451b20
Bump pytest from 8.3.2 to 8.3.3
dependabot[bot] Sep 16, 2024
a504bd5
Bump black from 24.8.0 to 24.10.0
dependabot[bot] Oct 14, 2024
6edc3dd
Bump tox from 4.18.0 to 4.23.2
dependabot[bot] Oct 28, 2024
12c8d07
Bump pytest-cov from 5.0.0 to 6.0.0
dependabot[bot] Nov 4, 2024
b50a8b7
Update wheel requirement from ~=0.40.0 to >=0.40,<0.46
dependabot[bot] Nov 11, 2024
84b2d3d
Update setuptools requirement from ~=68.0 to >=68,<76
dependabot[bot] Nov 11, 2024
f891225
Bump ruff from 0.6.3 to 0.8.0
dependabot[bot] Nov 25, 2024
bae73c0
Bump coverage from 7.6.1 to 7.6.8
dependabot[bot] Nov 25, 2024
64ef008
Refactoring to allow addition of ADC models and simulation
fronzbot Apr 15, 2025
2f069eb
Merge branch 'dev' into add-adcs
fronzbot Apr 15, 2025
092c614
Merge branch 'dev' of github.com:fronzbot/python-adc-eval into add-adcs
fronzbot Apr 15, 2025
6d2af35
Merge pull request #104 from fronzbot/add-adcs
fronzbot Apr 15, 2025
6ec039f
Merge pull request #102 from fronzbot/dependabot/pip/ruff-0.8.0
fronzbot Apr 15, 2025
12e8aff
Merge pull request #96 from fronzbot/dependabot/pip/pytest-cov-6.0.0
fronzbot Apr 15, 2025
c4e1279
Merge pull request #99 from fronzbot/dependabot/pip/setuptools-gte-68…
fronzbot Apr 15, 2025
ade79ed
Merge branch 'dev' into dependabot/pip/wheel-gte-0.40-and-lt-0.46
fronzbot Apr 15, 2025
31960ea
Merge pull request #88 from fronzbot/dependabot/pip/black-24.10.0
fronzbot Apr 15, 2025
8fb225b
Merge branch 'dev' into dependabot/pip/pytest-8.3.3
fronzbot Apr 15, 2025
53b9802
Merge pull request #98 from fronzbot/dependabot/pip/wheel-gte-0.40-an…
fronzbot Apr 15, 2025
c58a475
Bump pylint to 3.3.1
fronzbot Apr 15, 2025
fb70de5
Merge pull request #80 from fronzbot/dependabot/pip/pytest-8.3.3
fronzbot Apr 15, 2025
d5bb9d6
Merge branch 'dev' into dependabot/pip/tox-4.23.2
fronzbot Apr 15, 2025
ccf8cac
Merge branch 'dev' into bump-pylint-3.3.1
fronzbot Apr 15, 2025
fe9fa20
Merge branch 'dev' into dependabot/pip/coverage-7.6.8
fronzbot Apr 15, 2025
9c12181
Merge pull request #105 from fronzbot/bump-pylint-3.3.1
fronzbot Apr 15, 2025
ba9c39c
Merge pull request #94 from fronzbot/dependabot/pip/tox-4.23.2
fronzbot Apr 15, 2025
9520f63
Merge branch 'dev' into dependabot/pip/coverage-7.6.8
fronzbot Apr 15, 2025
b693827
Merge pull request #103 from fronzbot/dependabot/pip/coverage-7.6.8
fronzbot Apr 15, 2025
5509822
Refactored existing tests
fronzbot Apr 16, 2025
1a79a6c
Moved files and tests around for better org
fronzbot Apr 16, 2025
47fdca0
Moved windowing function outside of plot_spectrum
fronzbot Apr 16, 2025
28571b3
Core module tests completed
fronzbot Apr 17, 2025
5932478
Lint
fronzbot Apr 17, 2025
a418335
Added filter tests
fronzbot Apr 17, 2025
599f727
Merge pull request #106 from fronzbot/refactor-tests
fronzbot Apr 17, 2025
048899d
Updated docstrings
fronzbot Apr 17, 2025
7b189ad
Merge pull request #107 from fronzbot/update-docstrings
fronzbot Apr 17, 2025
935e86d
Add basic SAR ADC model
fronzbot Apr 18, 2025
ef5ec58
Fix linting and stuff
fronzbot Apr 18, 2025
6a0e4ff
Merge pull request #108 from fronzbot/add-sar-adc
fronzbot Apr 18, 2025
0095961
Fixed SAR weighting configuration
fronzbot Apr 18, 2025
b214965
Merge pull request #109 from fronzbot/fix-sar-weighting
fronzbot Apr 21, 2025
fcf6256
Update pyproject.toml
fronzbot Jun 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
matrix:
platform:
- ubuntu-latest
python-version: ['3.9', '3.10', '3.11', '3.12']
python-version: ['3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ python_adc_eval.egg-info
dist
.ruff_cache
.coverage
.secret
build
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ Given an array of values representing the output of an ADC, the spectrum can be
leak=<adjacent bins to filter>,
window=<window type (rectangular/hanning)>,
no_plot=<True/False>,
yaxis=<"power"/"fullscale">
yaxis=<"power"/"fullscale"/"magnitude">,
single_sided=<True/False>
)


Expand Down
1 change: 1 addition & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Init file for tests."""
4 changes: 0 additions & 4 deletions adc_eval/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
"""Initialization file for module."""

from . import spectrum
from . import converters
from . import signals
1 change: 1 addition & 0 deletions adc_eval/adcs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Initialization file for module."""
152 changes: 152 additions & 0 deletions adc_eval/adcs/basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
"""Basic ADC models."""

import numpy as np


def dac(samples, nbits=8, vref=1):
"""Digital to analog converter."""
quants = 2**nbits
dv = vref / quants
return samples * dv


class ADC:
"""
Generic ADC Class.

Parameters
----------
nbits : int, default=8
Number of bits for the ADC.
fs : int or float, default=1
Sample rate for the ADC in Hz.
vref : int or float, default=1
Reference level of the ADC in Volts ([0, +vref] conversion range).
seed : int, default=1
Seed for random variable generation.
**kwargs
Extra arguments.

Attributes
-------
vin : float
Sets or returns the current input voltage level. Assumed +/-vref/2 input
vlsb : float
LSB voltage of the converter. vref/2^nbits
noise : float, default=0
Sets or returns the stdev of the noise generated by the converter.
mismatch : float, default=0
Sets or returns the stdev of the mismatch of the converter.
offset : tuple of float, default=(0, 0)
Sets the (mean, stdev) of the offset of the converter.
gain_error : tuple of float, default=(0, 0)
Sets the (mean, stdev) of the gain error of the converter.
distortion : list of float, default=[1]
Sets the harmonic distortion values with index=0 corresponding to HD1.
Example: For unity gain and only -30dB of HD3, input is [1, 0, 0.032]
dout : int
Digital output code for current vin value.

Methods
-------
run_step

"""

def __init__(self, nbits=8, fs=1, vref=1, seed=1, **kwargs):
"""Initialization function for Generic ADC."""
np.random.seed(seed)
self.nbits = nbits
self.fs = fs
self.vref = vref
self.seed = seed
self.err = {"noise": 0, "gain": 0, "dist": [1], "offset": 0, "mismatch": 0}
self.dbits = np.zeros(nbits)
self.dval = 0

@property
def vin(self):
"""Return input value."""
return self._vin

@vin.setter
def vin(self, x):
"""Set the input value."""
x += self.vref / 2
x = max(0, min(x, self.vref))
self._vin = x

@property
def vlsb(self):
"""Return the LSB voltage."""
return self.vref / 2**self.nbits

@property
def noise(self):
"""Return noise status."""
return self.err["noise"]

@noise.setter
def noise(self, stdev):
"""Set noise stdev in Vrms."""
self.err["noise"] = stdev

@property
def mismatch(self):
"""Return noise stdev."""
print("WARNING: 'mismatch' feature not implemented for this class.")
return False

@mismatch.setter
def mismatch(self, stdev):
"""Set mismatch stdev."""
print("WARNING: 'mismatch' feature not implemented for this class.")
pass

@property
def offset(self):
"""Return offset value."""
return self.err["offset"]

@offset.setter
def offset(self, values):
"""Set offset mean and stdev."""
self.err["offset"] = np.random.normal(values[0], values[1])

@property
def gain_error(self):
"""Return gain error status."""
return self.err["gain"]

@gain_error.setter
def gain_error(self, values):
"""Set gain error mean and stdev."""
self.err["gain"] = np.random.normal(values[0], values[1])

@property
def distortion(self):
"""Return distortion gains (1st-order indexed)."""
return self.err["dist"]

@distortion.setter
def distortion(self, gains):
"""Set distortion gains (1st-order indexed)."""
self.err["dist"] = gains

@property
def dout(self):
"""Return digital output code."""
return int(self.dval)

def run_step(self):
"""Run a single ADC step."""
vinx = self.vin
dval = int(
min(max(int((2**self.nbits) * vinx / self.vref), 0), 2**self.nbits - 1)
)
bits = [int(x) for x in bin(dval)[2:]]

while len(bits) < self.nbits:
bits.insert(0, 0)
self.dbits = bits
self.dval = dval
130 changes: 130 additions & 0 deletions adc_eval/adcs/sar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""SAR ADC models"""

import numpy as np
from adc_eval.adcs.basic import ADC


class SAR(ADC):
"""
SAR ADC Class.

Parameters
----------
nbits : int, optional
Number of bits for the ADC. The default is 8.
fs : float, optional
Sample rate for the ADC in Hz. The default is 1Hz.
vref : float, optional
Reference level of the ADC in Volts ([0, +vref] conversion range). The default is 1.
seed : int, optional
Seed for random variable generation. The default is 1.
**kwargs
Extra arguments.
weights : list, optional
List of weights for SAR capacitors. Must be >= nbits. Defaults to binary weights.
MSB weight should be in index 0.

Attributes
-------
vin : float
Sets or returns the current input voltage level. Assumed +/-vref/2 input
vlsb : float
LSB voltage of the converter. vref/2^nbits
noise : float, default=0
Sets or returns the stdev of the noise generated by the converter.
weights : list
Sets or returns the capacitor weighting of the array. Default is binary weighting.
mismatch : float
Sets or returns the stdev of the mismatch of the converter. Default is no mismatch.
comp_noise : float
Sets or returns the stdev of the comparator noise. Default is no noise.
offset : tuple of float
Sets the (mean, stdev) of the offset of the converter. Default is no offset.
gain_error : tuple of float
Sets the (mean, stdev) of the gain error of the converter. Default is no gain error.
distortion : list of float
Sets the harmonic distortion values with index=0 corresponding to HD1.
Example: For unity gain and only -30dB of HD3, input is [1, 0, 0.032]
dout : int
Digital output code for current vin value.

Methods
-------
run_step

"""

def __init__(self, nbits=8, fs=1, vref=1, seed=1, **kwargs):
"""Initialization function for Generic ADC."""
super().__init__(nbits, fs, vref, seed)

self._mismatch = None
self._comp_noise = 0

# Get keyword arguments
self._weights = None
self.weights = kwargs.get("weights", self.weights)

@property
def weights(self):
"""Returns capacitor unit weights."""
if self._weights is None:
self._weights = np.flip(2 ** np.linspace(0, self.nbits - 1, self.nbits))
return np.array(self._weights)

@weights.setter
def weights(self, values):
"""Sets the capacitor unit weights."""
self._weights = np.array(values)
self.dbits = np.zeros(len(values))
if self._weights.size < self.nbits:
print(
f"WARNING: Capacitor weight array size is {self._weights.size} for {self.nbits}-bit ADC."
)
self.mismatch = self.err["mismatch"]

@property
def mismatch(self):
"""Return noise stdev."""
if self._mismatch is None:
self._mismatch = np.zeros(self.weights.size)
return self._mismatch

@mismatch.setter
def mismatch(self, stdev):
"""Sets mismatch stdev."""
self.err["mismatch"] = stdev
self._mismatch = np.random.normal(0, stdev, self.weights.size)
self._mismatch /= np.sqrt(self.weights)

@property
def comp_noise(self):
"""Returns the noise of the comparator."""
return self._comp_noise

@comp_noise.setter
def comp_noise(self, value):
"""Sets the noise of the comparator."""
self._comp_noise = value

def run_step(self):
"""Run a single ADC step."""
vinx = self.vin

cweights = self.weights * (1 + self.mismatch)
cdenom = sum(cweights) + 1

comp_noise = np.random.normal(0, self.comp_noise, cweights.size)

# Bit cycling
vdac = vinx
for n, _ in enumerate(cweights):
vcomp = vdac - self.vref / 2 + comp_noise[n]
compout = vcomp * 1e6
compout = -1 if compout <= 0 else 1
self.dbits[n] = max(0, compout)
vdac -= compout * self.vref / 2 * cweights[n] / cdenom

# Re-scale the data
scalar = 2**self.nbits / cdenom
self.dval = min(2**self.nbits - 1, scalar * sum(self.weights * self.dbits))
29 changes: 0 additions & 29 deletions adc_eval/converters.py

This file was deleted.

Loading