diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..be7f37f --- /dev/null +++ b/.drone.yml @@ -0,0 +1,88 @@ +kind: pipeline +type: docker +name: archlinux + +clone: + depth: 50 + +steps: + - name: archlinux_build + image: archlinux_build + pull: if-not-exists + volumes: + - name: archlinux_ccache + path: /root/.ccache + commands: + # The following command is not required, we included this in the docker + # image of archlinux_build + # - pacman -S --noconfirm ccache openblas fftw pulseaudio pybind11 + - git submodule update --init --recursive + - cmake . + # More than two makes ascee2 irresponsive for now + - make -j2 + + - name: archlinux_test + image: archlinux_build + pull: if-not-exists + commands: + # The following command is not required, we included this in the docker + # image of archlinux_build + # - pacman -S --noconfirm openblas python-pytest fftw pulseaudio python-pip python-scipy python-h5py + - pip install -r requirements.txt + - pip install . + - pytest + + # - name: release-arch + # commands: + # - + +volumes: + - name: archlinux_ccache + host: + path: /tmp/archlinux_ccache + +--- +kind: pipeline +type: docker +name: ubuntu + +clone: + depth: 3 + +volumes: +- name: archlinux_ccache + path: /root/.ccache + +steps: + - name: ubuntu_build + image: ubuntu + pull: if-not-exists + volumes: + - name: ubuntu_ccache + path: /root/.ccache + commands: + # The following commands are not required, we included this in the docker + # image of ubuntu_build + #- apt update + #- apt install -y git cmake python3-pybind11 libopenblas-dev python3-pip python3-scipy libusb-1.0-0-dev libpulse-dev python3-h5py fftw-dev + - git submodule update --init --recursive + - cmake . + # More than two makes ascee2 irresponsive for now + - make -j2 + + - name: ubuntu_test + image: ubuntu + pull: if-not-exists + commands: + # The following commands are not required, we included this in the docker + # image of ubuntu_build + #- apt update + #- apt install -y python3-pytest fftw pulseaudio python3-pip python3-scipy python3-h5py + - pip install -r requirements.txt + - pip install . + - pytest-3 + +volumes: + - name: ubuntu_ccache + host: + path: /tmp/ubuntu_ccache diff --git a/README.md b/README.md index bf111a3..949a10a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Library for Acoustic Signal Processing +[![Build Status](https://drone.ascee.nl/api/badges/ASCEE/lasp/status.svg)](https://drone.ascee.nl/ASCEE/lasp) + Welcome to LASP: Library for Acoustic Signal Processing. LASP is a C++ library with a Python interface which is supposed to acquire and process (multi) sensor data in real time on a PC and output results. @@ -32,7 +34,7 @@ If you have any question(s), please feel free to contact us: info@ascee.nl. ## Dependencies -- `$ sudo apt install libopenblas-dev python3-pip python3-scipy libusb-dev libpulse-dev cmake-curses-gui python3-h5py` +- `$ sudo apt install python3-pybind11 libopenblas-dev python3-pip python3-scipy libusb-1.0-0-dev libpulse-dev cmake-curses-gui python3-h5py` - `$ pip3 install --user -r requirements.txt` diff --git a/test/test_biquadbank.py b/examples/example_biquadbank.py similarity index 88% rename from test/test_biquadbank.py rename to examples/example_biquadbank.py index be0a1da..1f5315a 100644 --- a/test/test_biquadbank.py +++ b/examples/example_biquadbank.py @@ -2,15 +2,10 @@ import numpy as np from lasp import SeriesBiquad, AvPowerSpectra from lasp.filter import SPLFilterDesigner - import matplotlib.pyplot as plt from scipy.signal import sosfreqz -# plt.close('all') +plt.close('all') -# def test_cppslm2(): -# """ -# Generate a sine wave, now A-weighted -# """ fs = 48000 omg = 2*np.pi*1000 diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 6ac7893..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,17 +0,0 @@ -[project] # Project metadata -name = "lasp" -readme = "README.md" -requires-python = ">=3.8" -license = { "file" = "LICENSE" } -authors = [{ "name" = "J.A. de Jong et al.", "email" = "info@ascee.nl" }] - -classifiers = [ - "Topic :: Scientific/Engineering", - "Programming Language :: Python :: 3.8", - "Operating System :: POSIX :: Linux", - "Operating System :: Microsoft :: Windows", -] - -# urls = { "Documentation" = "https://" } -dynamic = ["version", "description"] - diff --git a/requirements.txt b/requirements.txt index c46d0e7..c7a9274 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ appdirs dataclasses_json +matplotlib diff --git a/setup.py b/setup.py index b46819d..66ceecd 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,22 @@ -import glob +import glob, os import platform from setuptools import setup if 'Linux' in platform.platform(): - extension = list(glob.glob('src/lasp/lasp_cpp.cpython*')) - if len(extension) == 0: + ext_name_glob = 'lasp_cpp.cpython*' + extensions = list(glob.glob('src/lasp/' + ext_name_glob)) + + # Split of path from file. + ext_names = [os.path.split(a)[1] for a in extensions] + + print(extensions) + if len(extensions) == 0: raise RuntimeError('Please first run CMake to build extension') - elif len(extension) > 1: + elif len(extensions) > 1: raise RuntimeError('Too many extension files found') - pkgdata = extension + pkgdata = ext_names else: raise RuntimeError('Not yet Windows-proof') @@ -24,9 +30,6 @@ classifiers = [ keywords = ["DSP", "DAQ", "Signal processing"] -with open('README.md', 'r') as f: - readme = f.read() - setup( name="lasp", @@ -40,12 +43,11 @@ setup( classifiers=classifiers, keywords=keywords, license="MIT", - readme=readme, dependencies=["numpy", "scipy", "appdirs", "h5py", "appdirs", - "dataclasses_json"], + "dataclasses_json"], + package_dir={"": "src"}, packages=['lasp', 'lasp.filter', 'lasp.tools'], - data_files = pkgdata, include_package_data=True, - package_dir={'': 'src'}, + package_data={'lasp': pkgdata}, python_requires='>=3.8', ) diff --git a/test/test_aps.py b/test/test_aps.py index 4ec248f..1e78498 100644 --- a/test/test_aps.py +++ b/test/test_aps.py @@ -8,8 +8,6 @@ Created on Mon Jan 15 19:45:33 2018 import numpy as np from lasp import AvPowerSpectra, Window -import matplotlib.pyplot as plt -# plt.close('all') def test_aps1(): nfft = 16384 diff --git a/test/test_cppslm.py b/test/test_cppslm.py index 5890b8d..ab3dbb8 100644 --- a/test/test_cppslm.py +++ b/test/test_cppslm.py @@ -2,34 +2,35 @@ import numpy as np from lasp import cppSLM from lasp.filter import SPLFilterDesigner -import matplotlib.pyplot as plt + def test_cppslm1(): """ Generate a sine wave """ fs = 48000 - omg = 2*np.pi*1000 - - slm = cppSLM.fromBiquads(fs, 2e-5, 1, 0.125, [1.,0,0,1,0,0]) - - t = np.linspace(0, 10, 10*fs, endpoint=False) + omg = 2 * np.pi * 1000 + + slm = cppSLM.fromBiquads(fs, 2e-5, 1, 0.125, + np.array([[1., 0, 0, 1, 0, 0]]).T) + + t = np.linspace(0, 10, 10 * fs, endpoint=False) + + # Input signal with an rms of 1 Pa + in_ = np.sin(omg * t) * np.sqrt(2) - # Input signal with an rms of 1 Pa - in_ = np.sin(omg*t)*np.sqrt(2) - # Compute overall RMS - rms = np.sqrt(np.sum(in_**2)/in_.size) + rms = np.sqrt(np.sum(in_**2) / in_.size) # Compute overall level - level = 20*np.log10(rms/2e-5) - + level = 20 * np.log10(rms / 2e-5) + # Output of SLM out = slm.run(in_) - + # Output of SLM should be close to theoretical # level, at least for reasonable time constants # (Fast, Slow etc) - assert(np.isclose(out[-1,0], level)) + assert (np.isclose(out[-1, 0], level)) def test_cppslm2(): @@ -37,53 +38,57 @@ def test_cppslm2(): Generate a sine wave, now A-weighted """ fs = 48000 - omg = 2*np.pi*1000 - + omg = 2 * np.pi * 1000 + filt = SPLFilterDesigner(fs).A_Sos_design() - slm = cppSLM.fromBiquads(fs, 2e-5, 0, 0.125, filt.flatten(), [1.,0,0,1,0,0]) - - t = np.linspace(0, 10, 10*fs, endpoint=False) - - # Input signal with an rms of 1 Pa - in_ = np.sin(omg*t) *np.sqrt(2) - + slm = cppSLM.fromBiquads(fs, 2e-5, 0, 0.125, + filt.flatten(), # Pre-filter coefs + np.array([[1., 0, 0, 1, 0, 0]]).T # Bandpass coefs + ) + + t = np.linspace(0, 10, 10 * fs, endpoint=False) + + # Input signal with an rms of 1 Pa + in_ = np.sin(omg * t) * np.sqrt(2) + # Compute overall RMS - rms = np.sqrt(np.sum(in_**2)/in_.size) + rms = np.sqrt(np.sum(in_**2) / in_.size) # Compute overall level - level = 20*np.log10(rms/2e-5) - + level = 20 * np.log10(rms / 2e-5) + # Output of SLM out = slm.run(in_) # Output of SLM should be close to theoretical # level, at least for reasonable time constants # (Fast, Slow etc) - assert np.isclose(out[-1,0], level, atol=1e-2) + assert np.isclose(out[-1, 0], level, atol=1e-2) + def test_cppslm3(): fs = 48000 - omg = 2*np.pi*1000 - + omg = 2 * np.pi * 1000 + filt = SPLFilterDesigner(fs).A_Sos_design() - slm = cppSLM.fromBiquads(fs, 2e-5, 0, 0.125, filt.flatten(), [1.,0,0,1,0,0]) - t = np.linspace(0, 10, 10*fs, endpoint=False) - - in_ = 10*np.sin(omg*t) * np.sqrt(2)+np.random.randn() + slm = cppSLM.fromBiquads(fs, 2e-5, 0, 0.125, + filt.flatten(), + np.array([[1., 0, 0, 1, 0, 0]]).T) + t = np.linspace(0, 10, 10 * fs, endpoint=False) + + in_ = 10 * np.sin(omg * t) * np.sqrt(2) + np.random.randn() # Compute overall RMS - rms = np.sqrt(np.sum(in_**2)/in_.size) + rms = np.sqrt(np.sum(in_**2) / in_.size) # Compute overall level - level = 20*np.log10(rms/2e-5) - - + level = 20 * np.log10(rms / 2e-5) + # Output of SLM out = slm.run(in_) - - Lpeak = 20*np.log10(np.max(np.abs(in_)/2e-5)) + + Lpeak = 20 * np.log10(np.max(np.abs(in_) / 2e-5)) Lpeak slm.Lpeak() - assert np.isclose(out[-1,0], slm.Leq()[0][0], atol=1e-2) - assert np.isclose(Lpeak, slm.Lpeak()[0][0], atol=2e0) - + assert np.isclose(out[-1, 0], slm.Leq()[0], atol=1e-2) + assert np.isclose(Lpeak, slm.Lpeak()[0], atol=2e0) if __name__ == '__main__': diff --git a/test/test_ps.py b/test/test_ps.py index b320da9..cb238a5 100644 --- a/test/test_ps.py +++ b/test/test_ps.py @@ -5,8 +5,6 @@ Testing code for power spectra """ import numpy as np from lasp import PowerSpectra, Window -# import matplotlib.pyplot as plt -# plt.close('all') def test_ps(): """ diff --git a/test/test_slm.py b/test/test_slm.py deleted file mode 100644 index 1596262..0000000 --- a/test/test_slm.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/python3 -import numpy as np -from lasp import SLM - - - -nframes = 0 -samplerate = 48000 -omg = 2*np.pi*1000 - - - -# def mycallback(input_, nframes, streamtime): -# t = np.linspace(streamtime, streamtime + nframes/samplerate, -# nframes)[np.newaxis,:] -# outp = 0.1*np.sin(omg*t) -# return outp, 0 - -# if __name__ == '__main__': -# pa = RtAudio() -# count = pa.getDeviceCount() -# # dev = pa.getDeviceInfo(0) -# for i in range(count): -# dev = pa.getDeviceInfo(i) -# print(dev) - -# outputparams = {'deviceid': 0, 'nchannels': 1, 'firstchannel': 0} -# pa.openStream(outputparams, None , Format_FLOAT64,samplerate, 512, mycallback) -# pa.startStream() - -# input() - -# pa.stopStream() -# pa.closeStream() - - -