Compare commits
No commits in common. "master" and "v1.6.6" have entirely different histories.
@ -4,7 +4,6 @@ project(LASP LANGUAGES C CXX VERSION 1.6.3)
|
|||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED)
|
set(CMAKE_CXX_STANDARD_REQUIRED)
|
||||||
|
|
||||||
# Experimental: support for Raspberry Pi (64-bit architectures)
|
|
||||||
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
||||||
set(RPI TRUE)
|
set(RPI TRUE)
|
||||||
else()
|
else()
|
||||||
@ -56,6 +55,7 @@ cmake_policy(SET CMP0079 NEW)
|
|||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
|
||||||
|
include_directories(/usr/include/python3.8)
|
||||||
include("BuildType")
|
include("BuildType")
|
||||||
include("QueryPythonForPybind11")
|
include("QueryPythonForPybind11")
|
||||||
|
|
||||||
|
26
README.md
26
README.md
@ -44,17 +44,15 @@ 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).
|
If you have any question(s), please feel free to contact us: [email](info@ascee.nl).
|
||||||
|
|
||||||
|
|
||||||
# Installation - Linux (Ubuntu-based)
|
# Installation - Linux (Ubuntu-based)
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
Run the following on the command line to install all prerequisites on
|
Run the following on the command line to install all prerequisites on
|
||||||
Debian-based Linux, x86-64:
|
Debian-based Linux:
|
||||||
|
|
||||||
- `sudo apt install python3-pip libfftw3-3 libopenblas-base libusb-1.0-0 libpulse0`
|
- `sudo apt install python3-pip libfftw3-3 libopenblas-base libusb-1.0-0 libpulse0`
|
||||||
|
|
||||||
|
|
||||||
## Installation from wheel (recommended for non-developers)
|
## Installation from wheel (recommended for non-developers)
|
||||||
|
|
||||||
Go to: [LASP releases](https://code.ascee.nl/ASCEE/lasp/releases/latest/) and
|
Go to: [LASP releases](https://code.ascee.nl/ASCEE/lasp/releases/latest/) and
|
||||||
@ -84,28 +82,6 @@ If building RtAudio with the Jack Audio Connection Kit (JACK) backend, you will
|
|||||||
- `$ cd lasp`
|
- `$ cd lasp`
|
||||||
- `pip install -e .`
|
- `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
|
# Installation - (x86_64) Windows (with WinPython), build with MSYS2
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
@ -107,12 +107,37 @@ void StreamMgr::rescanDAQDevices(bool background,
|
|||||||
_pool.push_task(&StreamMgr::rescanDAQDevices_impl, this, callback);
|
_pool.push_task(&StreamMgr::rescanDAQDevices_impl, this, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if LASP_HAS_PORTAUDIO && LASP_HAS_PA_ALSA
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
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<void()> callback) {
|
void StreamMgr::rescanDAQDevices_impl(std::function<void()> callback) {
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
assert(!_inputStream && !_outputStream);
|
assert(!_inputStream && !_outputStream);
|
||||||
Lck lck(_mtx);
|
Lck lck(_mtx);
|
||||||
// Alsa spits out annoying messages that are not useful
|
// Alsa spits out annoying messages that are not useful
|
||||||
{
|
{
|
||||||
|
MuteErrHandler guard;
|
||||||
|
|
||||||
_devices = DeviceInfo::getDeviceInfo();
|
_devices = DeviceInfo::getDeviceInfo();
|
||||||
}
|
}
|
||||||
|
@ -16,33 +16,6 @@ using std::endl;
|
|||||||
using std::string;
|
using std::string;
|
||||||
using std::to_string;
|
using std::to_string;
|
||||||
|
|
||||||
#if LASP_HAS_PA_ALSA
|
|
||||||
#include <alsa/asoundlib.h>
|
|
||||||
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) {
|
inline void throwIfError(PaError e) {
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
if (e != paNoError) {
|
if (e != paNoError) {
|
||||||
@ -71,7 +44,6 @@ class OurPaDeviceInfo : public DeviceInfo {
|
|||||||
void fillPortAudioDeviceInfo(DeviceInfoList &devinfolist) {
|
void fillPortAudioDeviceInfo(DeviceInfoList &devinfolist) {
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
bool shouldPaTerminate = false;
|
bool shouldPaTerminate = false;
|
||||||
MuteErrHandler guard;
|
|
||||||
try {
|
try {
|
||||||
PaError err = Pa_Initialize();
|
PaError err = Pa_Initialize();
|
||||||
/// PortAudio says that Pa_Terminate() should not be called whenever there
|
/// PortAudio says that Pa_Terminate() should not be called whenever there
|
||||||
@ -376,7 +348,6 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
|
|||||||
void PortAudioDaq::start(InDaqCallback inCallback, OutDaqCallback outCallback) {
|
void PortAudioDaq::start(InDaqCallback inCallback, OutDaqCallback outCallback) {
|
||||||
DEBUGTRACE_ENTER;
|
DEBUGTRACE_ENTER;
|
||||||
assert(_stream);
|
assert(_stream);
|
||||||
MuteErrHandler guard;
|
|
||||||
|
|
||||||
if (Pa_IsStreamActive(_stream)) {
|
if (Pa_IsStreamActive(_stream)) {
|
||||||
throw rte("Stream is already running");
|
throw rte("Stream is already running");
|
||||||
|
@ -5,7 +5,7 @@ requires-python = ">=3.10"
|
|||||||
description = "Library for Acoustic Signal Processing"
|
description = "Library for Acoustic Signal Processing"
|
||||||
license = { "file" = "LICENSE" }
|
license = { "file" = "LICENSE" }
|
||||||
authors = [{ "name" = "J.A. de Jong", "email" = "j.a.dejong@ascee.nl" }]
|
authors = [{ "name" = "J.A. de Jong", "email" = "j.a.dejong@ascee.nl" }]
|
||||||
version = "1.6.8"
|
version = "1.6.6"
|
||||||
|
|
||||||
keywords = ["DSP", "DAQ", "Signal processing"]
|
keywords = ["DSP", "DAQ", "Signal processing"]
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ from .lasp_cpp import *
|
|||||||
|
|
||||||
# from .lasp_imptube import * # TwoMicImpedanceTube
|
# from .lasp_imptube import * # TwoMicImpedanceTube
|
||||||
from .lasp_measurement import * # Measurement, scaleBlockSens
|
from .lasp_measurement import * # Measurement, scaleBlockSens
|
||||||
from .lasp_octavefilter import * # OverallFilterBank, SosOctaveFilterBank, SosThirdOctaveFilterBank
|
from .lasp_octavefilter import *
|
||||||
from .lasp_slm import * # SLM, Dummy
|
from .lasp_slm import * # SLM, Dummy
|
||||||
from .lasp_record import * # RecordStatus, Recording
|
from .lasp_record import * # RecordStatus, Recording
|
||||||
from .lasp_daqconfigs import * # DaqConfigurations
|
from .lasp_daqconfigs import *
|
||||||
from .lasp_measurementset import * # MeasurementSet
|
from .lasp_measurementset import *
|
||||||
|
|
||||||
# from .lasp_siggen import * # SignalType, NoiseType, SiggenMessage, SiggenData, Siggen
|
# from .lasp_siggen import * # SignalType, NoiseType, SiggenMessage, SiggenData, Siggen
|
||||||
# from .lasp_weighcal import * # WeighCal
|
# from .lasp_weighcal import * # WeighCal
|
||||||
|
@ -121,7 +121,7 @@ class SIQtys(Enum):
|
|||||||
unit_name='Pascal',
|
unit_name='Pascal',
|
||||||
unit_symb='Pa',
|
unit_symb='Pa',
|
||||||
level_unit=('dB SPL','dBPa'),
|
level_unit=('dB SPL','dBPa'),
|
||||||
level_ref_name=('20 micropascal', '1 pascal',),
|
level_ref_name=('2 micropascal', '1 pascal',),
|
||||||
level_ref_value=(P_REF, 1),
|
level_ref_value=(P_REF, 1),
|
||||||
cpp_enum = DaqChannel.Qty.AcousticPressure
|
cpp_enum = DaqChannel.Qty.AcousticPressure
|
||||||
)
|
)
|
||||||
|
@ -16,28 +16,13 @@ else:
|
|||||||
LASP_NUMPY_COMPLEX_TYPE = np.float64
|
LASP_NUMPY_COMPLEX_TYPE = np.float64
|
||||||
|
|
||||||
|
|
||||||
def zeros(shape, dtype=float, order='F'):
|
def zeros(shape):
|
||||||
if dtype == float:
|
return np.zeros(shape, dtype=LASP_NUMPY_FLOAT_TYPE, order='F')
|
||||||
return np.zeros(shape, dtype=LASP_NUMPY_FLOAT_TYPE, order=order)
|
|
||||||
elif dtype == complex:
|
|
||||||
return np.zeros(shape, dtype=LASP_NUMPY_COMPLEX_TYPE, order=order)
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f"Unknown dtype: {dtype}")
|
|
||||||
|
|
||||||
|
|
||||||
def ones(shape, dtype=float, order='F'):
|
def ones(shape):
|
||||||
if dtype == float:
|
return np.ones(shape, dtype=LASP_NUMPY_FLOAT_TYPE, order='F')
|
||||||
return np.ones(shape, dtype=LASP_NUMPY_FLOAT_TYPE, order=order)
|
|
||||||
elif dtype == complex:
|
|
||||||
return np.ones(shape, dtype=LASP_NUMPY_COMPLEX_TYPE, order=order)
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f"Unknown dtype: {dtype}")
|
|
||||||
|
|
||||||
def empty(shape, dtype=float, order='F'):
|
|
||||||
if dtype == float:
|
|
||||||
return np.empty(shape, dtype=LASP_NUMPY_FLOAT_TYPE, order=order)
|
|
||||||
elif dtype == complex:
|
|
||||||
return np.empty(shape, dtype=LASP_NUMPY_COMPLEX_TYPE, order=order)
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f"Unknown dtype: {dtype}")
|
|
||||||
|
|
||||||
|
def empty(shape):
|
||||||
|
return np.empty(shape, dtype=LASP_NUMPY_FLOAT_TYPE, order='F')
|
||||||
|
@ -1156,8 +1156,11 @@ class Measurement:
|
|||||||
if data.ndim != 2:
|
if data.ndim != 2:
|
||||||
data = data[:, np.newaxis]
|
data = data[:, np.newaxis]
|
||||||
|
|
||||||
if not (isinstance(sensitivity, np.ndarray) and sensitivity.ndim >= 1):
|
try:
|
||||||
sensitivity = np.asarray(sensitivity)[np.newaxis]
|
len(sensitivity)
|
||||||
|
except:
|
||||||
|
raise ValueError("Sensitivity should be given as array-like data type")
|
||||||
|
sensitivity = np.asarray(sensitivity)
|
||||||
|
|
||||||
nchannels = data.shape[1]
|
nchannels = data.shape[1]
|
||||||
if nchannels != sensitivity.shape[0]:
|
if nchannels != sensitivity.shape[0]:
|
||||||
@ -1170,7 +1173,7 @@ class Measurement:
|
|||||||
raise RuntimeError("Illegal length of channelNames list given")
|
raise RuntimeError("Illegal length of channelNames list given")
|
||||||
|
|
||||||
if qtys is None:
|
if qtys is None:
|
||||||
qtys = [SIQtys.fromInt(1)] * nchannels # Acoustic pressure is default
|
qtys = [SIQtys.AP] * nchannels
|
||||||
else:
|
else:
|
||||||
if len(qtys) != nchannels:
|
if len(qtys) != nchannels:
|
||||||
raise RuntimeError("Illegal length of qtys list given")
|
raise RuntimeError("Illegal length of qtys list given")
|
||||||
|
@ -6,10 +6,12 @@ Author: J.A. de Jong - ASCEE
|
|||||||
Provides the implementations of (fractional) octave filter banks
|
Provides the implementations of (fractional) octave filter banks
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
__all__ = ['FirOctaveFilterBank', 'FirThirdOctaveFilterBank',
|
||||||
|
'OverallFilterBank', 'SosOctaveFilterBank',
|
||||||
|
'SosThirdOctaveFilterBank']
|
||||||
|
|
||||||
__all__ = ["OverallFilterBank", "SosOctaveFilterBank", "SosThirdOctaveFilterBank"]
|
from .filter.filterbank_design import (OctaveBankDesigner,
|
||||||
|
ThirdOctaveBankDesigner)
|
||||||
from .filter.filterbank_design import OctaveBankDesigner, ThirdOctaveBankDesigner
|
|
||||||
from .lasp_cpp import BiquadBank
|
from .lasp_cpp import BiquadBank
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@ -17,7 +19,7 @@ import numpy as np
|
|||||||
class OverallFilterBank:
|
class OverallFilterBank:
|
||||||
"""
|
"""
|
||||||
Dummy type filter bank. Does nothing special, only returns output in a
|
Dummy type filter bank. Does nothing special, only returns output in a
|
||||||
way compatible with SosFilterBank.
|
sensible way
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, fs):
|
def __init__(self, fs):
|
||||||
@ -49,13 +51,174 @@ class OverallFilterBank:
|
|||||||
t = np.linspace(tstart, tend, Ncur, endpoint=False)
|
t = np.linspace(tstart, tend, Ncur, endpoint=False)
|
||||||
self.N += Ncur
|
self.N += Ncur
|
||||||
|
|
||||||
output["Overall"] = {"t": t, "data": data, "x": 0}
|
output['Overall'] = {'t': t, 'data': data, 'x': 0}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def decimation(self, x):
|
def decimation(self, x):
|
||||||
return [1]
|
return [1]
|
||||||
|
|
||||||
|
|
||||||
|
class FirFilterBank:
|
||||||
|
"""
|
||||||
|
Single channel (fractional) octave filter bank implementation, based on FIR
|
||||||
|
filters and sample rate decimation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, fs, xmin, xmax):
|
||||||
|
"""
|
||||||
|
Initialize a OctaveFilterBank object.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fs: Sampling frequency of base signal
|
||||||
|
|
||||||
|
"""
|
||||||
|
assert np.isclose(fs, 48000), "Only sampling frequency" \
|
||||||
|
" available is 48 kHz"
|
||||||
|
|
||||||
|
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 = []
|
||||||
|
for dec in maxdecimation:
|
||||||
|
self.decimators.append(Decimator(1, dec))
|
||||||
|
|
||||||
|
xs_d1 = []
|
||||||
|
xs_d4 = []
|
||||||
|
xs_d16 = []
|
||||||
|
xs_d64 = []
|
||||||
|
xs_d256 = []
|
||||||
|
|
||||||
|
self.filterbanks = []
|
||||||
|
# Sort the x values in categories according to the required decimation
|
||||||
|
for x in self.xs:
|
||||||
|
dec = self.designer.firDecimation(x)
|
||||||
|
if len(dec) == 1 and dec[0] == 1:
|
||||||
|
xs_d1.append(x)
|
||||||
|
elif len(dec) == 1 and dec[0] == 4:
|
||||||
|
xs_d4.append(x)
|
||||||
|
elif len(dec) == 2:
|
||||||
|
xs_d16.append(x)
|
||||||
|
elif len(dec) == 3:
|
||||||
|
xs_d64.append(x)
|
||||||
|
elif len(dec) == 4:
|
||||||
|
xs_d256.append(x)
|
||||||
|
else:
|
||||||
|
raise ValueError(f'No decimation found for x={x}')
|
||||||
|
|
||||||
|
xs_all = [xs_d1, xs_d4, xs_d16, xs_d64, xs_d256]
|
||||||
|
for xs in xs_all:
|
||||||
|
nominals_txt = []
|
||||||
|
if len(xs) > 0:
|
||||||
|
firs = np.empty((self.designer.firFilterLength, len(xs)), order='F')
|
||||||
|
for i, x in enumerate(xs):
|
||||||
|
# These are the filters that do not require lasp_decimation
|
||||||
|
# prior to filtering
|
||||||
|
nominals_txt.append(self.designer.nominal_txt(x))
|
||||||
|
firs[:, i] = self.designer.createFirFilter(x)
|
||||||
|
filterbank = {'fb': pyxFilterBank(firs, 1024),
|
||||||
|
'xs': xs,
|
||||||
|
'nominals': nominals_txt}
|
||||||
|
self.filterbanks.append(filterbank)
|
||||||
|
|
||||||
|
# Sample input counter.
|
||||||
|
self.N = 0
|
||||||
|
|
||||||
|
self.dec = [1, 4, 16, 64, 256]
|
||||||
|
|
||||||
|
# Filter output counters
|
||||||
|
# These intial delays are found 'experimentally' using a toneburst
|
||||||
|
# response.
|
||||||
|
self.Nf = [915, 806, 780, 582, 338]
|
||||||
|
|
||||||
|
def filterd(self, dec_stage, data):
|
||||||
|
"""
|
||||||
|
Filter data for a given decimation stage
|
||||||
|
|
||||||
|
Args:
|
||||||
|
dec_stage: decimation stage
|
||||||
|
data: Pre-filtered data
|
||||||
|
"""
|
||||||
|
output = {}
|
||||||
|
if data.shape[0] == 0:
|
||||||
|
return output
|
||||||
|
|
||||||
|
filtered = self.filterbanks[dec_stage]['fb'].filter_(data)
|
||||||
|
Nf = filtered.shape[0]
|
||||||
|
if Nf > 0:
|
||||||
|
dec = self.dec[dec_stage]
|
||||||
|
fd = self.fs/dec
|
||||||
|
|
||||||
|
oldNf = self.Nf[dec_stage]
|
||||||
|
tstart = oldNf/fd
|
||||||
|
tend = tstart + Nf/fd
|
||||||
|
|
||||||
|
t = np.linspace(tstart, tend, Nf, endpoint=False)
|
||||||
|
self.Nf[dec_stage] += Nf
|
||||||
|
for i, nom_txt in enumerate(self.filterbanks[dec_stage]['nominals']):
|
||||||
|
x = self.designer.nominal_txt_tox(nom_txt)
|
||||||
|
output[nom_txt] = {'t': t, 'data': filtered[:, [i]], 'x': x}
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
def filter_(self, data):
|
||||||
|
"""
|
||||||
|
Filter input data
|
||||||
|
"""
|
||||||
|
assert data.ndim == 2
|
||||||
|
assert data.shape[1] == 1, "invalid number of channels, should be 1"
|
||||||
|
|
||||||
|
if data.shape[0] == 0:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
# Output given as a dictionary with x as the key
|
||||||
|
output = {}
|
||||||
|
output_unsorted = {}
|
||||||
|
self.N += data.shape[0]
|
||||||
|
|
||||||
|
output_unsorted = {**output_unsorted, **self.filterd(0, data)}
|
||||||
|
|
||||||
|
for i in range(len(self.decimators)):
|
||||||
|
dec_stage = i+1
|
||||||
|
if data.shape[0] > 0:
|
||||||
|
# Apply a decimation stage
|
||||||
|
data = self.decimators[i].decimate(data)
|
||||||
|
output_unsorted = {**output_unsorted,
|
||||||
|
**self.filterd(dec_stage, data)}
|
||||||
|
|
||||||
|
# Create sorted output
|
||||||
|
for x in self.xs:
|
||||||
|
nom_txt = self.designer.nominal_txt(x)
|
||||||
|
output[nom_txt] = output_unsorted[nom_txt]
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
def decimation(self, x):
|
||||||
|
return self.designer.firDecimation(x)
|
||||||
|
|
||||||
|
|
||||||
|
class FirOctaveFilterBank(FirFilterBank):
|
||||||
|
"""
|
||||||
|
Filter bank which uses FIR filtering for each octave frequency band
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, fs, xmin, xmax):
|
||||||
|
self.designer = OctaveBankDesigner(fs)
|
||||||
|
FirFilterBank.__init__(self, fs, xmin, xmax)
|
||||||
|
|
||||||
|
|
||||||
|
class FirThirdOctaveFilterBank(FirFilterBank):
|
||||||
|
"""
|
||||||
|
Filter bank which uses FIR filtering for each one-third octave frequency
|
||||||
|
band.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, fs, xmin, xmax):
|
||||||
|
self.designer = ThirdOctaveBankDesigner(fs)
|
||||||
|
FirFilterBank.__init__(self, fs, xmin, xmax)
|
||||||
|
|
||||||
|
|
||||||
class SosFilterBank:
|
class SosFilterBank:
|
||||||
def __init__(self, fs, xmin, xmax):
|
def __init__(self, fs, xmin, xmax):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user