Skip to content

v0.2.1 #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 59 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
d7c823b
Update README.rst
fronzbot Apr 24, 2024
6bf8167
Delete adc_eval/analyser.png
fronzbot Apr 25, 2024
2a7ecdf
Bump pygments from 2.17.2 to 2.18.0
dependabot[bot] May 6, 2024
444613b
Bump pylint from 3.1.0 to 3.1.1
dependabot[bot] May 13, 2024
49fa31a
Merge pull request #23 from fronzbot/dependabot/pip/pylint-3.1.1
fronzbot May 13, 2024
0379779
Bump pylint from 3.1.1 to 3.2.2
dependabot[bot] May 20, 2024
dcab6e8
Bump matplotlib from 3.8.4 to 3.9.0
dependabot[bot] May 20, 2024
3cd4abb
Merge pull request #24 from fronzbot/dependabot/pip/pylint-3.2.2
fronzbot May 21, 2024
b80195c
Merge pull request #25 from fronzbot/dependabot/pip/matplotlib-3.9.0
fronzbot May 21, 2024
f9d7a7a
Merge pull request #19 from fronzbot/dependabot/pip/pygments-2.18.0
fronzbot May 21, 2024
6cf65af
Bump black from 24.4.1 to 24.4.2
dependabot[bot] May 21, 2024
02b12b6
Bump ruff from 0.4.1 to 0.4.4
dependabot[bot] May 21, 2024
c83ad7c
Merge pull request #22 from fronzbot/dependabot/pip/ruff-0.4.4
fronzbot May 21, 2024
54b12c6
Merge pull request #16 from fronzbot/dependabot/pip/black-24.4.2
fronzbot May 21, 2024
9dfe488
Bump coverage from 7.5.0 to 7.5.1
dependabot[bot] May 21, 2024
3f6071c
Bump tox from 4.14.2 to 4.15.0
dependabot[bot] May 21, 2024
5c0d01d
Merge pull request #18 from fronzbot/dependabot/pip/tox-4.15.0
fronzbot May 21, 2024
5078786
Merge pull request #21 from fronzbot/dependabot/pip/coverage-7.5.1
fronzbot May 21, 2024
95d9eb4
First cut.
fronzbot May 23, 2024
1f273cb
First wave of passing tests.
fronzbot May 23, 2024
df240e5
Create tests.yml
fronzbot May 23, 2024
ee9907d
Merge pull request #26 from fronzbot/add-tests
fronzbot May 24, 2024
e79576e
Create coverage.yml
fronzbot May 24, 2024
2b87921
Add coverage badge
fronzbot May 24, 2024
4fb4e43
Fix underline
fronzbot May 24, 2024
5be2571
Update lint.yml to py3.11
fronzbot May 24, 2024
83802d7
Missing coverage name added
fronzbot May 24, 2024
3e7caf1
Add coverage env
fronzbot May 24, 2024
2da8358
Merge pull request #27 from fronzbot/add-coverage-action
fronzbot May 24, 2024
29ee2fd
Split up psd tests, added more rigor
fronzbot May 24, 2024
36561cf
Add .coverage to gitignore
fronzbot May 24, 2024
02b8094
Merge pull request #28 from fronzbot/more-tests
fronzbot May 24, 2024
1cfe95a
Bump ruff from 0.4.4 to 0.4.5
dependabot[bot] May 27, 2024
e65f1d0
Update coverage.yml
fronzbot May 28, 2024
f970aa4
Merge pull request #30 from fronzbot/dependabot/pip/ruff-0.4.5
fronzbot May 28, 2024
3537c6c
Bump coverage from 7.5.1 to 7.5.2
dependabot[bot] May 28, 2024
775f536
Merge pull request #29 from fronzbot/dependabot/pip/coverage-7.5.2
fronzbot May 29, 2024
e565ede
Pin codecov version because it constantly breaks
fronzbot May 29, 2024
038d545
Merge pull request #31 from fronzbot/pin-codecov
fronzbot May 29, 2024
6c061e2
Rollback codecov action to v3
fronzbot May 29, 2024
c2f8ea7
Merge pull request #32 from fronzbot/roll-back-codecov
fronzbot May 29, 2024
cb15853
Added some more tests for the spectrum module
fronzbot May 29, 2024
a6e50f8
Merge pull request #33 from fronzbot/add-more-tests
fronzbot May 29, 2024
f40e46c
Bump ruff from 0.4.5 to 0.4.8
dependabot[bot] Jun 10, 2024
ab7c8c9
Bump pytest from 8.2.1 to 8.2.2
dependabot[bot] Jun 10, 2024
aaa6d19
Update coverage.yml
fronzbot Jun 11, 2024
ebcd4eb
Bump pylint from 3.2.2 to 3.2.3
dependabot[bot] Jun 11, 2024
c38a776
Merge pull request #39 from fronzbot/dependabot/pip/pylint-3.2.3
fronzbot Jun 11, 2024
1db9a3e
Merge branch 'dev' into dependabot/pip/pytest-8.2.2
fronzbot Jun 11, 2024
0c95b50
Merge pull request #36 from fronzbot/dependabot/pip/ruff-0.4.8
fronzbot Jun 11, 2024
5e5a1b9
Bump coverage from 7.5.2 to 7.5.3
dependabot[bot] Jun 11, 2024
524cbb4
Bump tox from 4.15.0 to 4.15.1
dependabot[bot] Jun 11, 2024
808fe8b
Merge pull request #38 from fronzbot/dependabot/pip/pytest-8.2.2
fronzbot Jun 11, 2024
ae71ffe
Merge pull request #37 from fronzbot/dependabot/pip/tox-4.15.1
fronzbot Jun 11, 2024
d637c9d
Merge pull request #34 from fronzbot/dependabot/pip/coverage-7.5.3
fronzbot Jun 11, 2024
190ceea
Fixed issue with leaky indices
fronzbot Jun 11, 2024
98269f7
Lint fixes
fronzbot Jun 11, 2024
878a7d7
Fix lint
fronzbot Jun 11, 2024
e7d90fd
Merge pull request #40 from fronzbot/fix-leak-index
fronzbot Jun 11, 2024
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 added .DS_Store
Binary file not shown.
58 changes: 58 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: coverage

on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, dev ]

jobs:
coverage:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11']
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_test.txt
pip install tox
- name: Run Coverage
run: |
tox -r -e cov
- name: Upload coverage
uses: actions/upload-artifact@v4.3.3
with:
name: coverage-${{ matrix.python-version }}
path: coverage.xml
overwrite: true
upload-coverage:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11']
needs:
- coverage
timeout-minutes: 10
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.6
- name: Download all coverage artifacts
uses: actions/download-artifact@v4.1.7
with:
name: coverage-${{ matrix.python-version }}
path: coverage.xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4.4.1
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
name: python-adc-eval
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9]
python-version: [3.11]

steps:
- uses: actions/checkout@v2
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: tests

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]

jobs:
build:
runs-on: ${{ matrix.platform }}
strategy:
max-parallel: 4
matrix:
platform:
- ubuntu-latest
python-version: ['3.9', '3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements_test.txt
pip install tox
- name: Test
run: |
tox -r
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ __pycache__
python_adc_eval.egg-info
dist
.ruff_cache
.coverage
8 changes: 5 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
python-adc-eval |Lint| |PyPi Version| |Codestyle|
===================================================
python-adc-eval |Lint| |PyPi Version| |Codecov| |Codestyle|
=============================================================

A python-based ADC evaluation tool, suitable for standalone or library-based usage

Expand Down Expand Up @@ -48,7 +48,9 @@ Given an array of values representing the output of an ADC, the spectrum can be

.. |Lint| image:: https://github.com/fronzbot/python-adc-eval/workflows/Lint/badge.svg
:target: https://github.com/fronzbot/python-adc-eval/actions?query=workflow%3ALint
.. |PyPi Version| image:: https://img.shields.io/pypi/v/spithon.svg
.. |PyPi Version| image:: https://img.shields.io/pypi/v/python-adc-eval.svg
:target: https://pypi.org/project/python-adc-eval
.. |Codestyle| image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
.. |Codecov| image:: https://codecov.io/gh/fronzbot/python-adc-eval/graph/badge.svg?token=156GMQ4NNV
:target: https://codecov.io/gh/fronzbot/python-adc-eval
Binary file removed adc_eval/analyser.png
Binary file not shown.
27 changes: 18 additions & 9 deletions adc_eval/spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
def db_to_pow(value, places=3):
"""Convert dBW to W."""
if isinstance(value, np.ndarray):
return 10 * np.log10(value)
return 10 ** (0.1 * value)
return round(10 ** (0.1 * value), places)


Expand Down Expand Up @@ -90,18 +90,25 @@ def find_harmonics(spectrum, freq, nfft, bin_sig, psig, harms=5, leak=20):
bin_harm = int(harm - (zone - 1) * nfft / 2)

# Make sure we pick the max bin where power is maximized; due to spectral leakage
bin_harm_max = bin_harm
# if bin_harm == nfft/2, set to bin of 0
if bin_harm == nfft / 2:
bin_harm = 0
pwr_max = spectrum[bin_harm]
for i in range(bin_harm - leak, bin_harm + leak + 1):
if spectrum[i] > spectrum[bin_harm_max]:
bin_harm_max = i

bin_harm = bin_harm_max
try:
pwr = spectrum[i]
if pwr > pwr_max:
bin_harm = i
pwr_max = pwr
except IndexError:
# bin + leakage out of bounds, so stop looking
break

harm_stats["harm"][harm_index]["bin"] = bin_harm
harm_stats["harm"][harm_index]["power"] = spectrum[bin_harm]
harm_stats["harm"][harm_index]["power"] = pwr
harm_stats["harm"][harm_index]["freq"] = round(freq[bin_harm] / 1e6, 1)
harm_stats["harm"][harm_index]["dBc"] = dBW(spectrum[bin_harm] / psig)
harm_stats["harm"][harm_index]["dB"] = dBW(spectrum[bin_harm])
harm_stats["harm"][harm_index]["dBc"] = dBW(pwr / psig)
harm_stats["harm"][harm_index]["dB"] = dBW(pwr)

harm_index = harm_index + 1

Expand All @@ -118,7 +125,9 @@ def calc_psd(data, fs, nfft=2**12, single_sided=False):
psd = np.mean(XF, axis=1) / (fs / nfft) # average the ffts and divide by bin width
freq = fs * np.linspace(0, 1, nfft)
if single_sided:
# First we double all the bins, then we halve the DC bin
psd = 2 * psd[0 : int(nfft / 2)]
psd[0] /= 2
freq = freq[0 : int(nfft / 2)]
return (freq, psd)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ classifiers = [
]
requires-python = ">=3.8.0"
dependencies = [
"matplotlib==3.8.4",
"matplotlib==3.9.0",
]

[project.urls]
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
matplotlib==3.8.4
matplotlib==3.9.0
16 changes: 10 additions & 6 deletions requirements_test.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
black==24.4.1
coverage==7.5.0
pylint==3.1.0
ruff==0.4.1
tox==4.14.2
black==24.4.2
coverage==7.5.3
pylint==3.2.3
pytest==8.2.2
pytest-cov==5.0.0
pytest-sugar==1.0.0
pytest-timeout==2.3.1
ruff==0.4.8
tox==4.15.1
restructuredtext-lint==1.4.0
pygments==2.17.2
pygments==2.18.0
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Init file for tests directory."""
139 changes: 139 additions & 0 deletions tests/test_calc_psd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
"""Test the calc_psd method."""

import unittest
import numpy as np
from unittest import mock
from adc_eval import spectrum


class TestCalcPSD(unittest.TestCase):
"""Test the calc_psd method."""

def setUp(self):
"""Initialize tests."""
self.nfft = 2**8
self.nlen = 2**18
accuracy = 0.01
self.bounds = [1 - accuracy, 1 + accuracy]
np.random.seed(1)

def test_calc_psd_randomized_dual(self):
"""Test calc_psd with random data."""
for i in range(0, 10):
data = np.random.randn(self.nlen)
(freq, psd) = spectrum.calc_psd(data, 1, nfft=self.nfft, single_sided=False)
mean_val = np.mean(psd)
self.assertTrue(self.bounds[0] <= mean_val <= self.bounds[1], msg=mean_val)

def test_calc_psd_randomized_single(self):
"""Test calc_psd with random data and single-sided."""
for i in range(0, 10):
data = np.random.randn(self.nlen)
(freq, psd) = spectrum.calc_psd(data, 1, nfft=self.nfft, single_sided=True)
mean_val = np.mean(psd)
self.assertTrue(
2 * self.bounds[0] <= mean_val <= 2 * self.bounds[1], msg=mean_val
)

def test_calc_psd_zeros_dual(self):
"""Test calc_psd with zeros."""
data = np.zeros(self.nlen)
(freq, psd) = spectrum.calc_psd(data, 1, nfft=self.nfft, single_sided=False)
mean_val = np.mean(psd)
self.assertTrue(
self.bounds[0] - 1 <= mean_val <= self.bounds[1] - 1, msg=mean_val
)

def test_calc_psd_zeros_single(self):
"""Test calc_psd with zeros and single-sided.."""
data = np.zeros(self.nlen)
(freq, psd) = spectrum.calc_psd(data, 1, nfft=self.nfft, single_sided=True)
mean_val = np.mean(psd)
self.assertTrue(
self.bounds[0] - 1 <= mean_val <= self.bounds[1] - 1, msg=mean_val
)

def test_calc_psd_ones_dual(self):
"""Test calc_psd with ones."""
data = np.ones(self.nlen)
(freq, psd) = spectrum.calc_psd(data, 1, nfft=self.nfft, single_sided=False)
mean_val = np.mean(psd)
self.assertTrue(self.bounds[0] <= mean_val <= self.bounds[1], msg=mean_val)

def test_calc_psd_ones_single(self):
"""Test calc_psd with ones and single-sided."""
data = np.ones(self.nlen)
(freq, psd) = spectrum.calc_psd(data, 1, nfft=self.nfft, single_sided=True)
mean_val = np.mean(psd)
self.assertTrue(
2 * self.bounds[0] <= mean_val <= 2 * self.bounds[1], msg=mean_val
)

def test_calc_psd_two_sine_dual(self):
"""Test calc_psd with two sine waves."""
fs = 1
fbin = fs / self.nfft
f1 = 29 * fbin
f2 = 97 * fbin
a1 = 0.37
a2 = 0.11
t = 1 / fs * np.linspace(0, self.nlen - 1, self.nlen)
data = a1 * np.sin(2 * np.pi * f1 * t) + a2 * np.sin(2 * np.pi * f2 * t)
(freq, psd) = spectrum.calc_psd(data, fs, nfft=self.nfft, single_sided=False)
exp_peaks = [
round(a1**2 / 4 * self.nfft, 3),
round(a2**2 / 4 * self.nfft, 3),
]
exp_f1 = [round(f1, 2), round(fs - f1, 2)]
exp_f2 = [round(f2, 2), round(fs - f2, 2)]

peak1 = max(psd)
ipeaks = np.where(psd >= peak1 * self.bounds[0])[0]
fpeaks = [round(freq[ipeaks[0]], 2), round(freq[ipeaks[1]], 2)]

self.assertEqual(round(peak1, 3), exp_peaks[0])
self.assertListEqual(fpeaks, exp_f1)

psd[ipeaks[0]] = 0
psd[ipeaks[1]] = 0

peak2 = max(psd)
ipeaks = np.where(psd >= peak2 * self.bounds[0])[0]
fpeaks = [round(freq[ipeaks[0]], 2), round(freq[ipeaks[1]], 2)]

self.assertEqual(round(peak2, 3), exp_peaks[1])
self.assertListEqual(fpeaks, exp_f2)

def test_calc_psd_two_sine_single(self):
"""Test calc_psd with two sine waves, single-eided."""
fs = 1
fbin = fs / self.nfft
f1 = 29 * fbin
f2 = 97 * fbin
a1 = 0.37
a2 = 0.11
t = 1 / fs * np.linspace(0, self.nlen - 1, self.nlen)
data = a1 * np.sin(2 * np.pi * f1 * t) + a2 * np.sin(2 * np.pi * f2 * t)
(freq, psd) = spectrum.calc_psd(data, fs, nfft=self.nfft, single_sided=True)
exp_peaks = [
round(a1**2 / 2 * self.nfft, 3),
round(a2**2 / 2 * self.nfft, 3),
]
exp_f1 = round(f1, 2)
exp_f2 = round(f2, 2)

peak1 = max(psd)
ipeak = np.where(psd == peak1)[0][0]
fpeak = round(freq[ipeak], 2)

self.assertEqual(round(peak1, 3), exp_peaks[0])
self.assertEqual(fpeak, exp_f1)

psd[ipeak] = 0

peak2 = max(psd)
ipeak = np.where(psd == peak2)[0][0]
fpeak = round(freq[ipeak], 2)

self.assertEqual(round(peak2, 3), exp_peaks[1])
self.assertEqual(fpeak, exp_f2)
Loading
Loading