From a1a7b411f1f054152cfb3e50623227ef10c718dc Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Tue, 16 May 2023 12:12:36 +0200 Subject: [PATCH 1/3] Updates and bugfixes on fromnpy in Measurement --- src/lasp/lasp_measurement.py | 62 ++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/lasp/lasp_measurement.py b/src/lasp/lasp_measurement.py index cbe0d91..9f05a3b 100644 --- a/src/lasp/lasp_measurement.py +++ b/src/lasp/lasp_measurement.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +from __future__ import annotations """! Author: J.A. de Jong - ASCEE @@ -113,7 +114,7 @@ class IterRawData: nblocks = fa.shape[0] blocksize = fa.shape[1] self.blocksize = blocksize - nchannels = fa.shape[2] + # nchannels = fa.shape[2] self.channels = channels self.istart = kwargs.pop('istart', 0) @@ -143,7 +144,7 @@ class IterRawData: """Return the next block.""" fa = self.fa - nblocks_to_return = self.lastblock-self.firstblock+1 + # nblocks_to_return = self.lastblock-self.firstblock+1 block = self.firstblock + self.i @@ -162,7 +163,7 @@ class IterRawData: # print(f'block: {block}, starto: {start_offset}, stopo {stop_offset}') self.i += 1 - return self.fa[block, start_offset:stop_offset, :][:, self.channels] + return fa[block, start_offset:stop_offset, :][:, self.channels] class IterData(IterRawData): @@ -771,23 +772,32 @@ class Measurement: samplerate, sensitivity, mfn, - timestamp=None): - """Converts a numpy array to a LASP Measurement file, opens the - associated Measurement object and returns it. The measurement file will - have the same file name as the txt file, except with h5 extension. + timestamp=None, + qtys: List[SIQtys] = None, + channelNames: List[str] = None, + force=False) -> Measurement: + """ + Creates a LASP measurement file from input numpy array data. + Opens the associated Measurement object and returns it. Args: data: Numpy array, first column is sample, second is channel. Can - also be specified with a single column for single-channel data + also be specified with a single column for single-channel data. + samplerate: Sampling frequency in [Hz] - sensitivity: 1D array of channel sensitivities [Pa^-1] - mfn: Filepath where measurement file is stored. + + sensitivity: 1D array of channel sensitivities in [U^-1], where U is + the recorded unit. + + mfn: Filepath of the file where the data is stored. + timestamp: If given, a custom timestamp for the measurement - (integer containing seconds since epoch). If not given, the - timestamp is obtained from the last modification time. - delimiter: Column delimiter - firstcoltime: If true, the first column is the treated as the - sample time. + (integer containing seconds since epoch). + + qtys: If a list of physical quantity data is given here + + channelNames: Name of the channels + force: If True, overwrites existing files with specified `mfn` name. """ @@ -801,24 +811,44 @@ class Measurement: if data.ndim != 2: data = data[:, np.newaxis] + try: len(sensitivity) except: raise ValueError('Sensitivity should be given as array-like data type') sensitivity = np.asarray(sensitivity) - nchannels = data.shape[1] if nchannels != sensitivity.shape[0]: raise ValueError( f'Invalid sensitivity length given. Should be: {nchannels}') + if channelNames is not None: + if len(channelNames) != nchannels: + raise RuntimeError("Illegal length of channelNames list given") + + if qtys is None: + qtys = [SIQtys.AP]*nchannels + else: + if len(qtys) != nchannels: + raise RuntimeError("Illegal length of qtys list given") + + qtyvals = [qty.value for qty in qtys] + with h5.File(mfn, 'w') as hf: hf.attrs['samplerate'] = samplerate hf.attrs['sensitivity'] = sensitivity hf.attrs['time'] = timestamp hf.attrs['blocksize'] = 1 hf.attrs['nchannels'] = nchannels + + # Add physical quantity indices + hf.attrs['qtys_enum_idx'] = [qtyval.toInt() for qtyval in qtyvals] + + # Add channel names in case given + if channelNames is not None: + hf.attrs['channelNames'] = channelNames + ad = hf.create_dataset('audio', (1, data.shape[0], data.shape[1]), dtype=data.dtype, maxshape=(1, data.shape[0], data.shape[1]), From 9ec2abecedde81f661276daf1f0cd8a9861a7cc0 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Tue, 16 May 2023 12:13:21 +0200 Subject: [PATCH 2/3] Changed remote of uldaq to asceenl --- third_party/uldaq | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/uldaq b/third_party/uldaq index 1d84041..6e5940e 160000 --- a/third_party/uldaq +++ b/third_party/uldaq @@ -1 +1 @@ -Subproject commit 1d8404159c0fb6d2665461b80acca5bbef5c610a +Subproject commit 6e5940eae0d44df49ff64fc7dedd49f86db56cd0 From 43cf2427eaed08a70eaae9b8220355f6012093e9 Mon Sep 17 00:00:00 2001 From: "J.A. de Jong - Redu-Sone B.V., ASCEE V.O.F" Date: Thu, 25 May 2023 16:52:55 +0200 Subject: [PATCH 3/3] Workaround for bug in RtAudio when first channel not equal to 0 --- src/lasp/device/lasp_rtaudiodaq.cpp | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/lasp/device/lasp_rtaudiodaq.cpp b/src/lasp/device/lasp_rtaudiodaq.cpp index 7c0742c..f2fef80 100644 --- a/src/lasp/device/lasp_rtaudiodaq.cpp +++ b/src/lasp/device/lasp_rtaudiodaq.cpp @@ -1,5 +1,5 @@ -#include /* #define DEBUGTRACE_ENABLED */ +#include #include "debugtrace.hpp" #include "lasp_mathtypes.h" @@ -177,23 +177,22 @@ public: inParams = std::make_unique(); - // +1 to get the count. - inParams->nChannels = getHighestEnabledInChannel() + 1; - if (inParams->nChannels < 1) { - throw rte("Invalid input number of channels"); - } + /// RtAudio lacks good bookkeeping when the first channel is not equal to + /// 0. For now, our fix is to shift out the channels we want, and let + /// RtAudio pass on all channels. inParams->firstChannel = 0; + inParams->nChannels = devinfo_gen.ninchannels; inParams->deviceId = devinfo._api_devindex; } else { outParams = std::make_unique(); - outParams->nChannels = getHighestEnabledOutChannel() + 1; - if (outParams->nChannels < 1) { - throw rte("Invalid output number of channels"); - } + /// RtAudio lacks good bookkeeping when the first channel is not equal to + /// 0. For now, our fix is to shift out the channels we want, and let + /// RtAudio pass on all channels. outParams->firstChannel = 0; + outParams->nChannels = devinfo_gen.noutchannels; outParams->deviceId = devinfo._api_devindex; } @@ -355,15 +354,16 @@ public: const us ch_min = getLowestEnabledInChannel(); const us ch_max = getHighestEnabledInChannel(); - us i = 0; + assert(ch_min < ninchannels); + assert(ch_max < ninchannels); + + /// Only pass on the pointers of the channels we want for (us ch = ch_min; ch <= ch_max; ch++) { if (inchannel_config.at(ch).enabled) { byte_t *ptr = - static_cast(inputBuffer) + sw * i * nFramesPerBlock; - DEBUGTRACE_PRINT((us)ptr); + static_cast(inputBuffer) + sw * ch * nFramesPerBlock; ptrs.push_back(ptr); } - i++; } DaqData d{nFramesPerBlock, neninchannels, dtype}; d.copyInFromRaw(ptrs); @@ -384,14 +384,14 @@ public: const us ch_min = getLowestEnabledOutChannel(); const us ch_max = getHighestEnabledOutChannel(); - us i = 0; + assert(ch_min < noutchannels); + assert(ch_max < noutchannels); + /// Only pass on the pointers of the channels we want for (us ch = ch_min; ch <= ch_max; ch++) { if (outchannel_config.at(ch).enabled) { - ptrs.push_back(static_cast(outputBuffer) + - sw * i * nFramesPerBlock); + sw * ch * nFramesPerBlock); } - i++; } DaqData d{nFramesPerBlock, nenoutchannels, dtype};