From 92fb5c1d7609d9443c5f252e344927de7fc8907f Mon Sep 17 00:00:00 2001 From: "J.A. de Jong" Date: Mon, 3 Jun 2024 16:57:12 +0200 Subject: [PATCH 01/16] Updated CMakeLists to compile with correct flags and settings --- CMakeLists.txt | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ab7b7b4..cd3fab4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,27 @@ -cmake_minimum_required (VERSION 3.16) +cmake_minimum_required(VERSION 3.16) project(LASP LANGUAGES C CXX VERSION 1.1) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED) -option(LASP_DOUBLE_PRECISION "Compile as double precision floating point" ON) +if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") + set(RPI TRUE) +else() + set(RPI FALSE) +endif() # Setting defaults for PortAudio and RtAudio backend, depending on Linux / # Windows. +set(DEFAULT_DOUBLE_PRECISION ON) if(WIN32) set(DEFAULT_RTAUDIO OFF) set(DEFAULT_PORTAUDIO ON) set(DEFAULT_ULDAQ OFF) +elseif(${RPI}) + set(DEFAULT_RTAUDIO OFF) + set(DEFAULT_PORTAUDIO ON) + set(DEFAULT_ULDAQ OFF) + else() set(DEFAULT_RTAUDIO OFF) set(DEFAULT_PORTAUDIO ON) @@ -19,6 +29,7 @@ else() endif() +option(LASP_DOUBLE_PRECISION "Compile as double precision floating point" ${DEFAULT_DOUBLE_PRECISION}) option(LASP_HAS_RTAUDIO "Compile with RtAudio Daq backend" ${DEFAULT_RTAUDIO}) option(LASP_HAS_PORTAUDIO "Compile with PortAudio Daq backend" ${DEFAULT_PORTAUDIO}) if(LASP_HAS_PORTAUDIO AND LASP_HAS_RTAUDIO) @@ -34,7 +45,7 @@ option(LASP_BUILD_CPP_TESTS "Build CPP test code" OFF) find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") - set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}") + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}") endif() # To allow linking to static libs from other directories @@ -80,7 +91,7 @@ endif() # Tune for current machine if(LASP_BUILD_TUNED) if(CMAKE_BUILD_TYPE STREQUAL "Debug") - message(FATAL_ERROR + message(FATAL_ERROR "Cannot build optimized and tuned code when debug is switched on") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -mtune=native") @@ -105,13 +116,17 @@ else() endif() # ###################################### Compilation flags -set(CMAKE_C_FLAGS_RELEASE "-O3 -flto -mfpmath=sse -march=x86-64 -mtune=native \ +set(CMAKE_C_FLAGS_RELEASE "-O3 -flto -mtune=native \ -fdata-sections -ffunction-sections -fomit-frame-pointer -finline-functions") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-type-limits -Werror=return-type") -set(CMAKE_CXX_FLAGS_RELEASE "-O3 -flto -mfpmath=sse -march=x86-64 -mtune=native \ +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -flto -mtune=native \ -fdata-sections -ffunction-sections -fomit-frame-pointer -finline-functions") +if(NOT ${RPI}) + set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -mfpmath=sse -march=x86-64) + set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -mfpmath=sse -march=x86-64) +endif() set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -Wall ") # ############################# End compilation flags From 41e748c2f5dddaf0963320b213887d780c604df0 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong" Date: Mon, 3 Jun 2024 17:28:51 +0200 Subject: [PATCH 02/16] Made code to compile and probably work with 32-bits floating point. This requires quite some testing to be done --- CMakeLists.txt | 2 +- cpp_src/dsp/lasp_window.cpp | 6 +++--- cpp_src/lasp_cpp.cpp | 9 +++++++-- python_src/lasp/filter/fir_design.py | 5 +++-- python_src/lasp/lasp_config.py | 8 +++++++- python_src/lasp/lasp_measurement.py | 11 ++++++----- python_src/lasp/lasp_octavefilter.py | 3 ++- python_src/lasp/lasp_reverb.py | 3 ++- python_src/lasp/lasp_slm.py | 3 ++- python_src/lasp/lasp_weighcal.py | 2 +- python_src/lasp/tools/tools.py | 1 + test/test_fft.py | 2 +- 12 files changed, 36 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd3fab4..932b14b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ elseif(${RPI}) set(DEFAULT_RTAUDIO OFF) set(DEFAULT_PORTAUDIO ON) set(DEFAULT_ULDAQ OFF) - + set(DEFAULT_DOUBLE_PRECISION OFF) else() set(DEFAULT_RTAUDIO OFF) set(DEFAULT_PORTAUDIO ON) diff --git a/cpp_src/dsp/lasp_window.cpp b/cpp_src/dsp/lasp_window.cpp index 9dedb95..fb5d7e4 100644 --- a/cpp_src/dsp/lasp_window.cpp +++ b/cpp_src/dsp/lasp_window.cpp @@ -11,7 +11,7 @@ using std::cerr; using std::endl; // Safe some typing. Linspace form 0 up to (and NOT including N). -#define lin0N arma::linspace(0, N - 1, N) +#define lin0N arma::linspace(0, N - 1, N) vd Window::hann(const us N) { return arma::pow(arma::sin((arma::datum::pi/N) * lin0N), 2); @@ -24,8 +24,8 @@ vd Window::blackman(const us N) { d a0 = 7938. / 18608.; d a1 = 9240. / 18608.; d a2 = 1430. / 18608.; - return a0 - a1 * d_cos((2 * number_pi/N) * lin0N) + - a2 * d_cos((4 * number_pi / N)* lin0N ); + return a0 - a1 * arma::cos((2 * number_pi/N) * lin0N) + + a2 * arma::cos((4 * number_pi / N)* lin0N ); } vd Window::rectangular(const us N) { return arma::ones(N); } diff --git a/cpp_src/lasp_cpp.cpp b/cpp_src/lasp_cpp.cpp index d5c7f76..481d690 100644 --- a/cpp_src/lasp_cpp.cpp +++ b/cpp_src/lasp_cpp.cpp @@ -44,6 +44,12 @@ void init_siggen(py::module &m); PYBIND11_MODULE(lasp_cpp, m) { +#if LASP_DOUBLE_PRECISION == 1 + m.attr("LASP_DOUBLE_PRECISION") = true; +#else + m.attr("LASP_DOUBLE_PRECISION") = false; +#endif + init_dsp(m); init_deviceinfo(m); init_daqconfiguration(m); @@ -51,6 +57,5 @@ PYBIND11_MODULE(lasp_cpp, m) { init_streammgr(m); init_datahandler(m); init_siggen(m); - } -/** @} */ +/** @} */ \ No newline at end of file diff --git a/python_src/lasp/filter/fir_design.py b/python_src/lasp/filter/fir_design.py index 5dd26bc..ad742fb 100644 --- a/python_src/lasp/filter/fir_design.py +++ b/python_src/lasp/filter/fir_design.py @@ -12,6 +12,7 @@ __all__ = ['freqResponse', 'bandpass_fir_design', 'lowpass_fir_design', import numpy as np from scipy.signal import freqz, hann, firwin2 +from ..lasp_config import empty def freqResponse(fs, freq, coefs_b, coefs_a=1.): @@ -44,7 +45,7 @@ def bandpass_fir_design(L, fs, fl, fu, window=hann): Omg2 = 2*np.pi*fu/fs Omg1 = 2*np.pi*fl/fs - fir = np.empty(L, dtype=float) + fir = empty(L, dtype=float) # First Create ideal band-pass filter fir[L//2] = (Omg2-Omg1)/np.pi @@ -64,7 +65,7 @@ def lowpass_fir_design(L, fs, fc, window=hann): " than upper cut-off" Omgc = 2*np.pi*fc/fs - fir = np.empty(L, dtype=float) + fir = empty(L, dtype=float) # First Create ideal band-pass filter fir[L//2] = Omgc/np.pi diff --git a/python_src/lasp/lasp_config.py b/python_src/lasp/lasp_config.py index 46e7af8..24074e4 100644 --- a/python_src/lasp/lasp_config.py +++ b/python_src/lasp/lasp_config.py @@ -6,8 +6,14 @@ Author: J.A. de Jong - ASCEE Description: LASP configuration """ import numpy as np +from .lasp_cpp import LASP_DOUBLE_PRECISION -LASP_NUMPY_FLOAT_TYPE = np.float64 +if LASP_DOUBLE_PRECISION: + LASP_NUMPY_FLOAT_TYPE = np.float64 + LASP_NUMPY_COMPLEX_TYPE = np.float128 +else: + LASP_NUMPY_FLOAT_TYPE = np.float32 + LASP_NUMPY_COMPLEX_TYPE = np.float64 def zeros(shape): diff --git a/python_src/lasp/lasp_measurement.py b/python_src/lasp/lasp_measurement.py index 9fb3614..5259575 100644 --- a/python_src/lasp/lasp_measurement.py +++ b/python_src/lasp/lasp_measurement.py @@ -64,6 +64,7 @@ from .lasp_version import LASP_VERSION_MAJOR, LASP_VERSION_MINOR from .lasp_cpp import Window, DaqChannel, AvPowerSpectra from typing import List from functools import lru_cache +from .lasp_config import ones # Measurement file extension MEXT = 'h5' @@ -223,7 +224,7 @@ class IterData(IterRawData): def __init__(self, fa, channels, sensitivity, **kwargs): super().__init__(fa, channels, **kwargs) - self.sens = np.asarray(sensitivity)[self.channels] + self.sens = np.asarray(sensitivity, dtype=LASP_NUMPY_FLOAT_TYPE)[self.channels] assert self.sens.ndim == 1 def __next__(self): @@ -329,10 +330,10 @@ class Measurement: try: sens = f.attrs["sensitivity"] self._sens = ( - sens * np.ones(self.nchannels) if isinstance(sens, float) else sens + sens * ones(self.nchannels) if isinstance(sens, float) else sens ) except KeyError: - self._sens = np.ones(self.nchannels) + self._sens = ones(self.nchannels) # The time is cached AND ALWAYS ASSUMED TO BE AN IMMUTABLE OBJECT. # It is also cached. Changing the measurement timestamp should not @@ -885,7 +886,7 @@ class Measurement: """ if isinstance(sens, float): # Put all sensitivities equal - sens = sens * np.ones(self.nchannels) + sens = sens * ones(self.nchannels) elif isinstance(sens, list): sens = np.asarray(sens) @@ -1199,7 +1200,7 @@ class Measurement: nchannels = 1 nframes = len(data) data = data[:, np.newaxis] - sensitivity = np.ones(nchannels) + sensitivity = ones(nchannels) with h5.File(newfn, "w") as hf: hf.attrs["samplerate"] = samplerate diff --git a/python_src/lasp/lasp_octavefilter.py b/python_src/lasp/lasp_octavefilter.py index 2a183ac..f8aeb43 100644 --- a/python_src/lasp/lasp_octavefilter.py +++ b/python_src/lasp/lasp_octavefilter.py @@ -77,6 +77,7 @@ class FirFilterBank: self.fs = fs self.xs = list(range(xmin, xmax + 1)) + raise RuntimeError('Not working code anymore') maxdecimation = self.designer.firDecimation(self.xs[0]) self.decimators = [] @@ -245,7 +246,7 @@ class SosFilterBank: for i, x in enumerate(self.xs): channel = self.designer.createSOSFilter(x) if sos is None: - sos = np.empty((channel.size, len(self.xs))) + sos = empty((channel.size, len(self.xs))) sos[:, i] = channel.flatten() self._fb = BiquadBank(sos) diff --git a/python_src/lasp/lasp_reverb.py b/python_src/lasp/lasp_reverb.py index 9ac5831..88ed057 100644 --- a/python_src/lasp/lasp_reverb.py +++ b/python_src/lasp/lasp_reverb.py @@ -6,6 +6,7 @@ Description: Reverberation time estimation tool using least squares """ from .lasp_common import getTime +from .lasp_config import ones import numpy as np @@ -56,7 +57,7 @@ class ReverbTime: x = self._t[istart:istop][:, np.newaxis] # Solve the least-squares problem, by creating a matrix of - A = np.hstack([x, np.ones(x.shape)]) + A = np.hstack([x, ones(x.shape)]) # print(A.shape) # print(points.shape) diff --git a/python_src/lasp/lasp_slm.py b/python_src/lasp/lasp_slm.py index 63f974b..052ea07 100644 --- a/python_src/lasp/lasp_slm.py +++ b/python_src/lasp/lasp_slm.py @@ -5,6 +5,7 @@ Sound level meter implementation @author: J.A. de Jong - ASCEE """ from .lasp_cpp import cppSLM +from .lasp_config import empty import numpy as np from .lasp_common import (TimeWeighting, FreqWeighting, P_REF) from .filter import SPLFilterDesigner @@ -101,7 +102,7 @@ class SLM: assert fbdesigner.fs == fs sos_firstx = fbdesigner.createSOSFilter(self.xs[0]).flatten() self.nom_txt.append(fbdesigner.nominal_txt(self.xs[0])) - sos = np.empty((sos_firstx.size, nfilters), dtype=float, order='C') + sos = empty((sos_firstx.size, nfilters), dtype=float, order='C') sos[:, 0] = sos_firstx for i, x in enumerate(self.xs[1:]): diff --git a/python_src/lasp/lasp_weighcal.py b/python_src/lasp/lasp_weighcal.py index dcff2bc..38e7246 100644 --- a/python_src/lasp/lasp_weighcal.py +++ b/python_src/lasp/lasp_weighcal.py @@ -47,7 +47,7 @@ class WeighCal: P = 2048 # Filter length (number of taps) - self._firs = np.empty((P, self.nchannels)) + self._firs = empty((P, self.nchannels)) self._fbs = [] for chan in range(self.nchannels): fir = arbitrary_fir_design(fs, P, freq_design, diff --git a/python_src/lasp/tools/tools.py b/python_src/lasp/tools/tools.py index 8caee6b..64e4cd9 100644 --- a/python_src/lasp/tools/tools.py +++ b/python_src/lasp/tools/tools.py @@ -21,6 +21,7 @@ import copy import numpy as np from numpy import log2, pi, sin from ..lasp_cpp import freqSmooth +from ..lasp_config import zeros @unique diff --git a/test/test_fft.py b/test/test_fft.py index 09e0b4e..f4f4176 100644 --- a/test/test_fft.py +++ b/test/test_fft.py @@ -31,7 +31,7 @@ def test_backward_fft(): nfft = 2048 freq = getFreq(nfft, nfft) - # Sig = np.zeros(nfft//2+1, dtype=complex) + # Sig = zeros(nfft//2+1, dtype=complex) Sigr = np.random.randn(nfft//2+1) Sigi = np.random.randn(nfft//2+1) From e3bcfa30cec1e973f896938b19d26b34263e94c0 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Mon, 17 Jun 2024 12:10:31 +0200 Subject: [PATCH 03/16] Updated portaudio --- CMakeLists.txt | 4 ++-- third_party/portaudio | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 932b14b..e2d39ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,8 +124,8 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3 -flto -mtune=native \ -fdata-sections -ffunction-sections -fomit-frame-pointer -finline-functions") if(NOT ${RPI}) - set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -mfpmath=sse -march=x86-64) - set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} -mfpmath=sse -march=x86-64) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfpmath=sse -march=x86-64") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpmath=sse -march=x86-64") endif() set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -Wall ") diff --git a/third_party/portaudio b/third_party/portaudio index daaf637..88ab584 160000 --- a/third_party/portaudio +++ b/third_party/portaudio @@ -1 +1 @@ -Subproject commit daaf637f6f9fce670031221abfd7dfde92e5cce3 +Subproject commit 88ab584e7bf4358599744cd662cfbc978f41efbf From 74bfdef921590873233b8f3c92dc94e40dd3d867 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Mon, 17 Jun 2024 15:50:33 +0200 Subject: [PATCH 04/16] Updated portaudio --- third_party/portaudio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/portaudio b/third_party/portaudio index daaf637..18a606e 160000 --- a/third_party/portaudio +++ b/third_party/portaudio @@ -1 +1 @@ -Subproject commit daaf637f6f9fce670031221abfd7dfde92e5cce3 +Subproject commit 18a606e1f928852bfc29639d9539ae74d37b5dee From a1802686d1f9df443b08c7254016175240e6c1bc Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Tue, 18 Jun 2024 09:01:44 +0200 Subject: [PATCH 05/16] Removed lasp_imptube. Old code not of use anymore --- python_src/lasp/lasp_imptube.py | 173 -------------------------------- 1 file changed, 173 deletions(-) delete mode 100644 python_src/lasp/lasp_imptube.py diff --git a/python_src/lasp/lasp_imptube.py b/python_src/lasp/lasp_imptube.py deleted file mode 100644 index 8a00a89..0000000 --- a/python_src/lasp/lasp_imptube.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -"""! -Author: J.A. de Jong - ASCEE - -Description: Two-microphone impedance tube methods -""" -__all__ = ['TwoMicImpedanceTube'] -# from lrftubes import Air -from .lasp_measurement import Measurement -from numpy import pi, sqrt, exp -import numpy as np -from scipy.interpolate import UnivariateSpline -# from lrftubes import PrsDuct -from functools import lru_cache - -class TwoMicImpedanceTube: - def __init__(self, mnormal: Measurement, - mswitched: Measurement, - s: float, - d1: float, - d2: float, - fl: float = None, - fu: float = None, - periodic_method=False, - # mat= Air(), - D_imptube = 50e-3, - thermoviscous = True, - **kwargs): - - """ - Initialize two-microphone impedance tube methods - - Args: - mnormal: Measurement in normal configuration - mswitched: Measurement in normal configuration - s: Microphone distance - fl: Lower evaluation frequency - fu: Lower evaluation frequency - - kwargs: tuple with extra arguments, of which: - N: Period length of periodic excitation *obligatory* - chan0: Measurement channel index of mic 0 - chan1: Measurement channel index of mic 1 - - """ - self.mnormal = mnormal - self.mswitched = mswitched - - self.mat = mat - self.s = s - self.d1 = d1 - self.d2 = d2 - - self.fl = fl - if fl is None: - ksmin = 0.1*pi - kmin = ksmin/s - self.fl = kmin*mat.c0/2/pi - - self.fu = fu - if fu is None: - ksmax = 0.8*pi - kmax = ksmax/s - self.fu = kmax*mat.c0/2/pi - - self.thermoviscous = thermoviscous - self.D_imptube = D_imptube - - self.periodic_method = periodic_method - self.channels = [kwargs.pop('chan0', 0), kwargs.pop('chan1', 1)] - # Compute calibration correction - if periodic_method: - self.N = kwargs.pop('N') - freq, C1 = mnormal.periodicCPS(self.N, channels=self.channels) - freq, C2 = mswitched.periodicCPS(self.N, channels=self.channels) - else: - self.nfft = kwargs.pop('nfft', 16000) - freq, C1 = mnormal.CPS(nfft=self.nfft, channels=self.channels) - freq, C2 = mswitched.CPS(nfft=self.nfft, channels=self.channels) - - # Store this, as it is often used for just a single sample. - self.C1 = C1 - self.freq = freq - - self.il = np.where(self.freq<= self.fl)[0][-1] - self.ul = np.where(self.freq > self.fu)[0][0] - - # Calibration correction factor - # self.K = 0*self.freq + 1.0 - K = sqrt(C2[:,0,1]*C1[:,0,0]/(C2[:,1,1]*C1[:,1,0])) - # self.K = UnivariateSpline(self.freq, K.real)(self.freq) +\ - # 1j*UnivariateSpline(self.freq, K.imag)(self.freq) - self.K = K - - def cut_to_limits(self, ar): - return ar[self.il:self.ul] - - def getFreq(self): - """ - Array of frequencies, cut to limits of validity - """ - return self.cut_to_limits(self.freq) - - @lru_cache - def G_AB(self, meas): - if meas is self.mnormal: - C = self.C1 - freq = self.freq - else: - if self.periodic_method: - freq, C = meas.periodicCPS(self.N, self.channels) - else: - freq, C = meas.CPS(nfft=self.nfft, channels=self.channels) - - # Microphone transfer function - G_AB = self.K*C[:,1,0]/C[:,0,0] - return self.getFreq(), self.cut_to_limits(G_AB) - - def k(self, freq): - """ - Wave number, or thermoviscous wave number - """ - if self.thermoviscous: - D = self.D_imptube - S = pi/4*D**2 - d = PrsDuct(0, S=S, rh=D/4, cs='circ') - d.mat = self.mat - omg = 2*pi*freq - G, Z = d.GammaZc(omg) - return G - else: - return 2*pi*freq/self.mat.c0 - - - def R(self, meas): - freq, G_AB = self.G_AB(meas) - s = self.s - k = self.k(freq) - d1 = self.d1 - RpA = (G_AB - exp(-1j*k*s))/(exp(1j*k*s)-G_AB) - - R = RpA*exp(2*1j*k*(s+d1)) - - return freq, R - - def alpha(self, meas): - """ - Acoustic absorption coefficient - """ - freq, R = self.R(meas) - return freq, 1 - np.abs(R)**2 - - def z(self, meas): - """ - Acoustic impedance at the position of the sample, in front of the sample - """ - freq, R = self.R(meas) - return freq, self.mat.z0*(1+R)/(1-R) - - def zs(self, meas): - """ - Sample impedance jump, assuming a cavity behind the sample with - thickness d2 - """ - freq, R = self.R(meas) - z0 = self.mat.z0 - k = 2*pi*freq/self.mat.c0 - d2 = self.d2 - - zs = 2*z0*(1-R*exp(2*1j*k*d2))/((R-1)*(exp(2*d2*k*1j)-1)) - return freq, zs - From afffa0b2ca5ec999b6b46ae4aafda1faf05c443f Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Tue, 18 Jun 2024 09:11:46 +0200 Subject: [PATCH 06/16] Bugfix to accomodate scipy versions >=1.13. Fixed the version of scipy to be at least this one. Updated readme regarding version bumping --- CMakeLists.txt | 2 +- README.md | 13 +++++++++++++ pyproject.toml | 4 ++-- python_src/lasp/filter/fir_design.py | 3 ++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2d39ec..d70d62b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(LASP LANGUAGES C CXX VERSION 1.1) +project(LASP LANGUAGES C CXX VERSION 1.6.2) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED) diff --git a/README.md b/README.md index 6f92c5c..d07e20c 100644 --- a/README.md +++ b/README.md @@ -144,3 +144,16 @@ This will build the documentation. It can be read by: - See examples directories for IPython notebooks. - Please refer to the [documentation](https://lasp.ascee.nl/) for features. + + +# Development docs + +## Bumping version number + +When bumping the version number, please update the number in + +- `pyproject.toml` +- `CMakeLists.txt` + +Then, create a commit with tag `vX.X.X`, and push it. + diff --git a/pyproject.toml b/pyproject.toml index 42291aa..b040966 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires-python = ">=3.10" description = "Library for Acoustic Signal Processing" license = { "file" = "LICENSE" } authors = [{ "name" = "J.A. de Jong", "email" = "j.a.dejong@ascee.nl" }] -version = "1.6.1" +version = "1.6.2" keywords = ["DSP", "DAQ", "Signal processing"] @@ -23,7 +23,7 @@ classifiers = [ urls = { "Documentation" = "https://lasp.ascee.nl" } dependencies = [ - "scipy==1.12", + "scipy>=1.13.1", "matplotlib>=3.7.2", "appdirs", "dataclasses_json", diff --git a/python_src/lasp/filter/fir_design.py b/python_src/lasp/filter/fir_design.py index ad742fb..5b43dfa 100644 --- a/python_src/lasp/filter/fir_design.py +++ b/python_src/lasp/filter/fir_design.py @@ -11,7 +11,8 @@ __all__ = ['freqResponse', 'bandpass_fir_design', 'lowpass_fir_design', 'arbitrary_fir_design'] import numpy as np -from scipy.signal import freqz, hann, firwin2 +from scipy.signal import freqz, firwin2 +from scipy.signal.windows import hann from ..lasp_config import empty From c7f8ac7122ba92499b2b53ef50b41fa5c4984238 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Tue, 18 Jun 2024 09:14:58 +0200 Subject: [PATCH 07/16] Added extra readme --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d07e20c..7b9ea00 100644 --- a/README.md +++ b/README.md @@ -157,3 +157,12 @@ When bumping the version number, please update the number in Then, create a commit with tag `vX.X.X`, and push it. +## Updating to latest version (editable mode) + +When updating to the latest version of LASP in editable mode: + +```bash +- $ git pull +- $ git submodule update +- $ pip install -e . -v +``` \ No newline at end of file From c8a4ded7501f1108219546aefd025fb6aac9e12b Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Wed, 19 Jun 2024 10:15:28 +0200 Subject: [PATCH 08/16] Checkout v3. v4 seems to be buggy. --- .gitea/workflows/workflow.yml | 2 +- CMakeLists.txt | 4 ++-- pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index bc3feab..9c9c9e9 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -12,7 +12,7 @@ jobs: - lasp_dist:/dist steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: submodules: true diff --git a/CMakeLists.txt b/CMakeLists.txt index d70d62b..ef57dcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(LASP LANGUAGES C CXX VERSION 1.6.2) +project(LASP LANGUAGES C CXX VERSION 1.6.3) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED) @@ -136,7 +136,7 @@ include(OSSpecific) include(rtaudio) include(portaudio) include(uldaq) -# +# add_definitions(-Dgsl_CONFIG_DEFAULTS_VERSION=1) add_subdirectory(cpp_src) if(LASP_BUILD_CPP_TESTS) diff --git a/pyproject.toml b/pyproject.toml index b040966..ae2dc03 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires-python = ">=3.10" description = "Library for Acoustic Signal Processing" license = { "file" = "LICENSE" } authors = [{ "name" = "J.A. de Jong", "email" = "j.a.dejong@ascee.nl" }] -version = "1.6.2" +version = "1.6.3" keywords = ["DSP", "DAQ", "Signal processing"] From 9bcc2e417337a93829b6731bb3aa69c04b7d4001 Mon Sep 17 00:00:00 2001 From: Casper Date: Fri, 21 Jun 2024 14:05:53 +0200 Subject: [PATCH 09/16] Update comments + minor change --- python_src/lasp/lasp_measurementset.py | 72 ++++++++++++++++++-------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/python_src/lasp/lasp_measurementset.py b/python_src/lasp/lasp_measurementset.py index 6973868..98904c2 100644 --- a/python_src/lasp/lasp_measurementset.py +++ b/python_src/lasp/lasp_measurementset.py @@ -14,17 +14,16 @@ class MeasurementSet(list): """ Group of measurements that have some correspondence to one another. Class is used to operate on multiple measurements at once. - """ def __init__(self, mlist: List[Measurement] = []): """ Initialize a measurement set - Args: + Arg: mlist: Measurement list - """ + if any([not isinstance(i, Measurement) for i in mlist]): raise TypeError("Object in list should be of Measurement type") @@ -33,11 +32,17 @@ class MeasurementSet(list): super().__init__(mlist) def getNewestReferenceMeasurement(self, mtype: MeasurementType): - """Return the newest (in time) measurement in the current list of a certain type. Returns None in case no measurement could be found. - - Args: - mtype (MeasurementType): The type required. """ + Get the NEWEST ref. measurement of a current type, in the current set. + + Arg: + mtype (MeasurementType): The type required. + + Return: + - The newest (in time) measurement in the current list of a certain type. + - None, in case no measurement could be found. + """ + mnewest = None for m in self: if m.measurementType() == mtype: @@ -49,19 +54,26 @@ class MeasurementSet(list): return mnewest def getReferenceMeasurements(self, mtype: MeasurementType): - """Get all available reference measurements of a certain type in the - current set. + """Get ALL ref. measurements of a certain type, in the current set. - Args: + Arg: mtype (MeasurementType): The type of which to list - Returns: - a new measurement set including all measurements of a certain type + Return: + A new measurement set, including all measurements of a certain type """ + return [m for m in self if m.measurementType() == mtype] def getNewestReferenceMeasurements(self): - """Returns a dictionary with newest measurement of each type that is not specific returns None in case no measurement is found.""" + """ + Get the NEWEST ref. measurement of all types, in the current set. + + Return: + - A dictionary with the newest measurement of each type that is not specific + - None, in case no measurement is found. + """ + newest = {} for m in self: mtype = m.measurementType() @@ -75,8 +87,17 @@ class MeasurementSet(list): return newest def newestReferenceOlderThan(self, secs): - """Returns a dictionary of references with the newest reference, that is still - older than `secs` seconds.""" + """ + Get a dictionary of reference measurements which are older than a + specified threshold. Only one of each type is returned. + + Args: + - secs: time threshold, in seconds + + Return: + - a dictionary of references with the newest reference, that is still + older than `secs` seconds + """ curtime = time.time() newest = self.getNewestReferenceMeasurements() newest_older_than = {} @@ -87,25 +108,29 @@ class MeasurementSet(list): def measTimeSame(self): """ - Returns True if all measurements have the same measurement - time (recorded time) - + Returns True if all measurements have the same measurement length and + sample rate """ + if len(self) > 0: - first = self[0].N - return all([first == meas.N for meas in self]) + firstN = self[0].N # samples + firstFS = self[0].samplerate # sample rate + sameN = all([firstN == meas.N for meas in self]) + sameFS = all([firstFS == meas.samplerate for meas in self]) + return sameN and sameFS else: return False def measSimilar(self): """ Similar means: channel metadata is the same, and the measurement time - is the same. It means that the recorded data is, of course, different. + is the same. Returns: - True if measChannelsSame() and measTimeSame() else False - + - True if measChannelsSame() and measTimeSame() + - False otherwise """ + return self.measTimeSame() and self.measChannelsSame() def measChannelsSame(self): @@ -115,6 +140,7 @@ class MeasurementSet(list): a set of measurements, simultaneously. If the channel data is the same (name, sensitivity, ...) it returns True. """ + if len(self) > 0: first = self[0].channelConfig return all([first == meas.channelConfig for meas in self]) From 1cc6b9106dad9ff32e9749dfc69745e05b4066e2 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Mon, 24 Jun 2024 09:44:19 +0200 Subject: [PATCH 10/16] Bugfix: float129 -> complex128 --- python_src/lasp/lasp_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_src/lasp/lasp_config.py b/python_src/lasp/lasp_config.py index 24074e4..de94229 100644 --- a/python_src/lasp/lasp_config.py +++ b/python_src/lasp/lasp_config.py @@ -10,7 +10,7 @@ from .lasp_cpp import LASP_DOUBLE_PRECISION if LASP_DOUBLE_PRECISION: LASP_NUMPY_FLOAT_TYPE = np.float64 - LASP_NUMPY_COMPLEX_TYPE = np.float128 + LASP_NUMPY_COMPLEX_TYPE = np.complex128 else: LASP_NUMPY_FLOAT_TYPE = np.float32 LASP_NUMPY_COMPLEX_TYPE = np.float64 From a1781fa66c5ea2506f9b2083735ea021a09b0e03 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Mon, 24 Jun 2024 09:45:10 +0200 Subject: [PATCH 11/16] Bump version due to bugfix --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ae2dc03..eef1351 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires-python = ">=3.10" description = "Library for Acoustic Signal Processing" license = { "file" = "LICENSE" } authors = [{ "name" = "J.A. de Jong", "email" = "j.a.dejong@ascee.nl" }] -version = "1.6.3" +version = "1.6.4" keywords = ["DSP", "DAQ", "Signal processing"] From 832302bba2a0c82d351bdbd4ba62dd3bb93296c3 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Mon, 24 Jun 2024 09:56:35 +0200 Subject: [PATCH 12/16] Some warnings fixed. The rest is markup suggestions from black, of which part is committed --- python_src/lasp/lasp_measurement.py | 156 ++++++++++++++----------- python_src/lasp/lasp_measurementset.py | 2 +- 2 files changed, 90 insertions(+), 68 deletions(-) diff --git a/python_src/lasp/lasp_measurement.py b/python_src/lasp/lasp_measurement.py index 5259575..d9acee8 100644 --- a/python_src/lasp/lasp_measurement.py +++ b/python_src/lasp/lasp_measurement.py @@ -1,6 +1,24 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import annotations +from contextlib import contextmanager +from weakref import WeakValueDictionary +import h5py as h5 +import uuid +import pathlib +import glob +import itertools +import numpy as np +from enum import Enum, unique +from .lasp_config import LASP_NUMPY_FLOAT_TYPE +from scipy.io import wavfile +import os, time, wave, logging +from .lasp_common import SIQtys, Qty, getFreq +from .lasp_version import LASP_VERSION_MAJOR, LASP_VERSION_MINOR +from .lasp_cpp import Window, DaqChannel, AvPowerSpectra +from typing import List +from functools import lru_cache +from .lasp_config import ones """! Author: J.A. de Jong - ASCEE @@ -46,29 +64,11 @@ The video dataset can possibly be not present in the data. """ -__all__ = ["Measurement", "scaleBlockSens", "MeasurementType"] -from contextlib import contextmanager -from weakref import WeakValueDictionary -import h5py as h5 -import uuid -import pathlib -import glob -import itertools -import numpy as np -from enum import Enum, unique -from .lasp_config import LASP_NUMPY_FLOAT_TYPE -from scipy.io import wavfile -import os, time, wave, logging -from .lasp_common import SIQtys, Qty, getFreq -from .lasp_version import LASP_VERSION_MAJOR, LASP_VERSION_MINOR -from .lasp_cpp import Window, DaqChannel, AvPowerSpectra -from typing import List -from functools import lru_cache -from .lasp_config import ones +__all__ = ["Measurement", "scaleBlockSens", "MeasurementType"] # Measurement file extension -MEXT = 'h5' -DOTMEXT = f'.{MEXT}' +MEXT = "h5" +DOTMEXT = f".{MEXT}" @unique @@ -272,36 +272,36 @@ class Measurement: self.version_major = f.attrs["LASP_VERSION_MAJOR"] self.version_minor = f.attrs["LASP_VERSION_MINOR"] except KeyError: - # No version information stored + # No version information stored self.version_major = 0 self.version_minor = 1 try: # Try to catch UUID (Universally Unique IDentifier) - self._UUID = f.attrs['UUID'] + self._UUID = f.attrs["UUID"] # Flag indicating we have to add a new UUID create_new_uuid = False except KeyError: create_new_uuid = True try: - # UUID of the reference measurement. Should be stored as + # UUID of the reference measurement. Should be stored as # a lists of tuples, where each tuple is a combination of (, , ). # The last filename is a filename that *probably* is the reference measurement with # given UUID. If it is not, we will search for it in the same directory as `this` measurement. # If we cannot find it there, we will give up, and remove the field corresponding to this reference measurement type. - refMeas_list = f.attrs['refMeas'] + refMeas_list = f.attrs["refMeas"] # Build a tuple string from it self._refMeas = {} - for (key, val, name) in refMeas_list: + for key, val, name in refMeas_list: self._refMeas[MeasurementType(int(key))] = (val, name) except KeyError: self._refMeas = {} try: - self._type_int = f.attrs['type_int'] + self._type_int = f.attrs["type_int"] except KeyError: self._type_int = 0 @@ -368,7 +368,9 @@ class Measurement: self.genNewUUID() else: if self.UUID in Measurement.uuid_s.keys(): - raise RuntimeError(f"Measurement '{self.name}' is already opened. Cannot open measurement twice. Note: this error can happen when measurements are manually copied.") + raise RuntimeError( + f"Measurement '{self.name}' is already opened. Cannot open measurement twice. Note: this error can happen when measurements are manually copied." + ) # Store weak reference to 'self' in list of UUID's. They are removed when no file is open anymore Measurement.uuid_s[self._UUID] = self @@ -380,11 +382,11 @@ class Measurement: Args: newname: New name, with or without extension """ - _ , ext = os.path.splitext(newname) + _, ext = os.path.splitext(newname) # Add proper extension if new name is given without extension. if ext != DOTMEXT: newname = newname + DOTMEXT - + # Folder, Base filename + extension folder, _ = os.path.split(self.fn) @@ -397,7 +399,7 @@ class Measurement: """ Create new UUID for measurement and store in file. """ - self.setAttribute('UUID', str(uuid.uuid1())) + self.setAttribute("UUID", str(uuid.uuid1())) @property def UUID(self): @@ -405,59 +407,73 @@ class Measurement: Universally unique identifier """ return self._UUID - + def getRefMeas(self, mtype: MeasurementType): """ - Return corresponding reference measurement, if configured and can be found. If the reference + Return corresponding reference measurement, if configured and can be found. If the reference measurement is currently not open, it tries to open it by traversing other measurement files in the current directory. Throws a runtime error in case the reference measurement cannot be found. Throws a ValueError when the reference measurement is not configured. """ - + # See if we can find the UUID for the required measurement type try: required_uuid, possible_name = self._refMeas[mtype] except KeyError: raise ValueError(f"No reference measurement configured for '{self.name}'") - + m = None # Try to find it in the dictionary of of open measurements if required_uuid in Measurement.uuid_s.keys(): m = Measurement.uuid_s[required_uuid] - logging.debug(f'Returned reference measurement {m.name} from list of open measurements') - + logging.debug( + f"Returned reference measurement {m.name} from list of open measurements" + ) + # Not found in list of openend measurements. See if we can open it using its last stored file name we know of if m is None: try: m = Measurement(possible_name) if m.UUID == required_uuid: - logging.info(f'Opened reference measurement {m.name} by name') + logging.info(f"Opened reference measurement {m.name} by name") except Exception as e: - logging.error(f'Could not find reference measurement using file name: {possible_name}') + logging.error( + f"Could not find reference measurement using file name: {possible_name}" + ) # Last resort, see if we can find the right measurement in the same folder if m is None: try: folder, _ = os.path.split(self.fn) - m = Measurement.fromFolderWithUUID(required_uuid, folder, skip=[self.name]) - logging.info('Found reference measurement in folder with correct UUID. Updating name of reference measurement') + m = Measurement.fromFolderWithUUID( + required_uuid, folder, skip=[self.name] + ) + logging.info( + "Found reference measurement in folder with correct UUID. Updating name of reference measurement" + ) # Update the measurement file name in the list, such that next time it # can be opened just by its name. self.setRefMeas(m) except: - logging.error("Could not find the reference measurement. Is it deleted?") + logging.error( + "Could not find the reference measurement. Is it deleted?" + ) # Well, we found it. Now make sure the reference measurement actually has the right type (User could have marked it as a NotSpecific for example in the mean time). if m is not None: if m.measurementType() != mtype: m.removeRefMeas(mtype) - raise RuntimeError(f"Reference measurement for {self.name} is not a proper reference (anymore).") - + raise RuntimeError( + f"Reference measurement for {self.name} is not a proper reference (anymore)." + ) + # Whow, we passed all security checks, here we go! return m else: # Nope, not there. - raise RuntimeError(f"Could not find the reference measurement for '{self.name}'. Is it deleted?") + raise RuntimeError( + f"Could not find the reference measurement for '{self.name}'. Is it deleted?" + ) def removeRefMeas(self, mtype: MeasurementType): """ @@ -478,9 +494,12 @@ class Measurement: with self.file("r+") as f: # Update attribute in file. Stored as a flat list of string tuples: # [(ref_value1, uuid_1, name_1), (ref_value2, uuid_2, name_2), ...] - reflist = list((str(key.value), val1, val2) for key, (val1, val2) in self._refMeas.items()) + reflist = list( + (str(key.value), val1, val2) + for key, (val1, val2) in self._refMeas.items() + ) # print(reflist) - f.attrs['refMeas'] = reflist + f.attrs["refMeas"] = reflist def setRefMeas(self, m: Measurement): """ @@ -490,32 +509,36 @@ class Measurement: """ mtype = m.measurementType() if mtype == MeasurementType.NotSpecific: - raise ValueError('Measurement to be set as reference is not a reference measurement') - + raise ValueError( + "Measurement to be set as reference is not a reference measurement" + ) + self._refMeas[mtype] = (m.UUID, m.name) self.__storeReafMeas() @staticmethod - def fromFolderWithUUID(uuid_str: str, folder: str='', skip=[]): + def fromFolderWithUUID(uuid_str: str, folder: str = "", skip=[]): """ Returns Measurement object from a given UUID string. It first tries to find whether there - is an uuid in the static list of weak references. If not, it will try to open files in + is an uuid in the static list of weak references. If not, it will try to open files in the current file path. """ - for fn in glob.glob(str(pathlib.Path(folder)) + f'/*{DOTMEXT}'): + for fn in glob.glob(str(pathlib.Path(folder)) + f"/*{DOTMEXT}"): # Do not try to open this file in case it is in the 'skip' list. if len(list(filter(lambda a: a in fn, skip))) > 0: continue - + try: m = Measurement(fn) - if m.UUID == uuid_str: + if m.UUID == uuid_str: # Update 'last_fn' attribute in dict of stored reference measurements return m except Exception as e: - logging.error(f'Possible measurement file {fn} returned error {e} when opening.') + logging.error( + f"Possible measurement file {fn} returned error {e} when opening." + ) - raise RuntimeError(f'Measurement with UUID {uuid_str} could not be found.') + raise RuntimeError(f"Measurement with UUID {uuid_str} could not be found.") def setAttribute(self, attrname: str, value): """ @@ -535,17 +558,17 @@ class Measurement: """ Returns True when a measurement is flagged as being of a certaint "MeasurementType" """ - if (type_.value & self._type_int): + if type_.value & self._type_int: return True elif type_.value == self._type_int == 0: return True return False - + def setType(self, type_: MeasurementType): """ Set the measurement type to given type """ - self.setAttribute('type_int', type_.value) + self.setAttribute("type_int", type_.value) def measurementType(self): """ @@ -590,7 +613,7 @@ class Measurement: @channelConfig.setter def channelConfig(self, chcfg: List[DaqChannel]): """ - Set new channel configuration from list of DaqChannel objects. + Set new channel configuration from list of DaqChannel objects. Use cases: - Update channel types, sensitivities etc. @@ -999,9 +1022,9 @@ class Measurement: happen that a Measurement object is created twice for the same backing file, which we do not allow. """ # See if the base part of the filename is referring to a file that is already open - with h5.File(fn, 'r') as f: + with h5.File(fn, "r") as f: try: - theuuid = f.attrs['UUID'] + theuuid = f.attrs["UUID"] except KeyError: # No UUID stored in measurement. This is an old measurement that did not have UUID's # We create a new UUID here such that the file is opened from the filesystem @@ -1010,7 +1033,7 @@ class Measurement: if theuuid in Measurement.uuid_s.keys(): return Measurement.uuid_s[theuuid] - + return Measurement(fn) @staticmethod @@ -1091,8 +1114,8 @@ class Measurement: sensitivity, mfn, timestamp=None, - qtys: List[SIQtys]=None, - channelNames: List[str]=None, + qtys: List[SIQtys] = None, + channelNames: List[str] = None, force=False, ) -> Measurement: """ @@ -1162,7 +1185,7 @@ class Measurement: hf.attrs["nchannels"] = nchannels # Add physical quantity indices - hf.attrs['qtys_enum_idx'] = [qty.toInt() for qty in qtys] + hf.attrs["qtys_enum_idx"] = [qty.toInt() for qty in qtys] # Add channel names in case given if channelNames is not None: @@ -1218,4 +1241,3 @@ class Measurement: ad[0] = data return Measurement(newfn) - diff --git a/python_src/lasp/lasp_measurementset.py b/python_src/lasp/lasp_measurementset.py index 98904c2..08ace1b 100644 --- a/python_src/lasp/lasp_measurementset.py +++ b/python_src/lasp/lasp_measurementset.py @@ -79,7 +79,7 @@ class MeasurementSet(list): mtype = m.measurementType() if mtype == MeasurementType.NotSpecific: continue - if not mtype in newest: + if mtype not in newest: newest[mtype] = m else: if m.time > newest[mtype].time: From fa51d6e81cecff5ab610a69f6c98656e74ad200f Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Mon, 24 Jun 2024 10:00:56 +0200 Subject: [PATCH 13/16] Bump 1.6.5 --- pyproject.toml | 2 +- python_src/lasp/lasp_measurement.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eef1351..137e198 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires-python = ">=3.10" description = "Library for Acoustic Signal Processing" license = { "file" = "LICENSE" } authors = [{ "name" = "J.A. de Jong", "email" = "j.a.dejong@ascee.nl" }] -version = "1.6.4" +version = "1.6.5" keywords = ["DSP", "DAQ", "Signal processing"] diff --git a/python_src/lasp/lasp_measurement.py b/python_src/lasp/lasp_measurement.py index d9acee8..d35aee7 100644 --- a/python_src/lasp/lasp_measurement.py +++ b/python_src/lasp/lasp_measurement.py @@ -236,7 +236,8 @@ class Measurement: """Provides access to measurement data stored in the h5 measurement file format.""" - # Store a dict of open measurements, with uuid string as a key. We store them as a weak ref. + # Store a dict of open measurements, with uuid string as a key. We store + # them as a weak ref. uuid_s = WeakValueDictionary() def __init__(self, fn): From 27da426d66d6029814702ddff6ed87eebb630884 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - ASCEE" Date: Mon, 24 Jun 2024 02:11:56 -0700 Subject: [PATCH 14/16] Bump v1.6.6 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 137e198..6ff6eb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires-python = ">=3.10" description = "Library for Acoustic Signal Processing" license = { "file" = "LICENSE" } authors = [{ "name" = "J.A. de Jong", "email" = "j.a.dejong@ascee.nl" }] -version = "1.6.5" +version = "1.6.6" keywords = ["DSP", "DAQ", "Signal processing"] From a443be6e39bccdb58a44315c89d4c421701ebec7 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Mon, 24 Jun 2024 16:33:31 +0200 Subject: [PATCH 15/16] Updated readme for RPI install --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b9ea00..f00ce30 100644 --- a/README.md +++ b/README.md @@ -44,15 +44,17 @@ in a sister repository [lasp-doc](https://code.ascee.nl/ascee/lasp-doc). If you have any question(s), please feel free to contact us: [email](info@ascee.nl). + # Installation - Linux (Ubuntu-based) ## Prerequisites Run the following on the command line to install all prerequisites on -Debian-based Linux: +Debian-based Linux, x86-64: - `sudo apt install python3-pip libfftw3-3 libopenblas-base libusb-1.0-0 libpulse0` + ## Installation from wheel (recommended for non-developers) Go to: [LASP releases](https://code.ascee.nl/ASCEE/lasp/releases/latest/) and @@ -82,6 +84,28 @@ If building RtAudio with the Jack Audio Connection Kit (JACK) backend, you will - `$ cd lasp` - `pip install -e .` +# Building and installation for Raspberry Pi (Raspberry Pi OS) + +Run the following on the command line to install all prerequisites on +Raspberry Pi OS: + +- `sudo apt install libfftw3-dev libopenblas64-dev libhdf5-dev libclalsadrv-dev` + +In a virtualenv: install `build` + +- `$ pip install build` + +Then run: + +- `$ git clone --recursive https://code.ascee.nl/ASCEE/lasp.git` +- `$ cd lasp` +- `$ pyproject-build` + +Which will generate a `whl` in the `dist` folder, that is redistributable for Raspberry Pis that run Raspberry Pi OS. + +When installing the `whl`, it appears that H5PY takes quite some time to install. To follow this process, run it it verbose mode. + + # Installation - (x86_64) Windows (with WinPython), build with MSYS2 ## Prerequisites From 838a0f7cc13961775897bd05db44868c0702ab47 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Wed, 26 Jun 2024 12:17:43 +0200 Subject: [PATCH 16/16] Silence portaudio alsa errors when querying device info AND when starting stream. Do not know whether this solves the problem of its verbosity, but at least the code is where it belongs --- cpp_src/device/lasp_streammgr.cpp | 25 ---------------- .../device/portaudio/lasp_portaudiodaq.cpp | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/cpp_src/device/lasp_streammgr.cpp b/cpp_src/device/lasp_streammgr.cpp index 526e0c8..3b328c7 100644 --- a/cpp_src/device/lasp_streammgr.cpp +++ b/cpp_src/device/lasp_streammgr.cpp @@ -107,37 +107,12 @@ void StreamMgr::rescanDAQDevices(bool background, _pool.push_task(&StreamMgr::rescanDAQDevices_impl, this, callback); } } -#if LASP_HAS_PORTAUDIO && LASP_HAS_PA_ALSA -#include -void empty_handler(const char *file, int line, const char *function, int err, - const char *fmt, ...) {} - -// Temporarily set the ALSA eror handler to something that does nothing, to -// prevent ALSA from spitting out all kinds of misconfiguration errors. -class MuteErrHandler { - private: - snd_lib_error_handler_t _default_handler; - - public: - explicit MuteErrHandler() { - _default_handler = snd_lib_error; - snd_lib_error_set_handler(empty_handler); - } - - ~MuteErrHandler() { snd_lib_error_set_handler(_default_handler); } -}; -#else -// Does nothin in case of no ALSA -class MuteErrHandler {}; -#endif - void StreamMgr::rescanDAQDevices_impl(std::function callback) { DEBUGTRACE_ENTER; assert(!_inputStream && !_outputStream); Lck lck(_mtx); // Alsa spits out annoying messages that are not useful { - MuteErrHandler guard; _devices = DeviceInfo::getDeviceInfo(); } diff --git a/cpp_src/device/portaudio/lasp_portaudiodaq.cpp b/cpp_src/device/portaudio/lasp_portaudiodaq.cpp index 05e7cc7..e22c461 100644 --- a/cpp_src/device/portaudio/lasp_portaudiodaq.cpp +++ b/cpp_src/device/portaudio/lasp_portaudiodaq.cpp @@ -16,6 +16,33 @@ using std::endl; using std::string; using std::to_string; +#if LASP_HAS_PA_ALSA +#include +void empty_handler(const char *file, int line, const char *function, int err, + const char *fmt, ...) { + + // cerr << "Test empty error handler...\n"; + } + +// Temporarily set the ALSA eror handler to something that does nothing, to +// prevent ALSA from spitting out all kinds of misconfiguration errors. +class MuteErrHandler { + private: + snd_lib_error_handler_t _default_handler; + + public: + explicit MuteErrHandler() { + _default_handler = snd_lib_error; + snd_lib_error_set_handler(empty_handler); + } + + ~MuteErrHandler() { snd_lib_error_set_handler(_default_handler); } +}; +#else +// Does nothin in case of no ALSA +class MuteErrHandler {}; +#endif + inline void throwIfError(PaError e) { DEBUGTRACE_ENTER; if (e != paNoError) { @@ -44,6 +71,7 @@ class OurPaDeviceInfo : public DeviceInfo { void fillPortAudioDeviceInfo(DeviceInfoList &devinfolist) { DEBUGTRACE_ENTER; bool shouldPaTerminate = false; + MuteErrHandler guard; try { PaError err = Pa_Initialize(); /// PortAudio says that Pa_Terminate() should not be called whenever there @@ -348,6 +376,7 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen, void PortAudioDaq::start(InDaqCallback inCallback, OutDaqCallback outCallback) { DEBUGTRACE_ENTER; assert(_stream); + MuteErrHandler guard; if (Pa_IsStreamActive(_stream)) { throw rte("Stream is already running");