Merge branch 'develop' of ssh://code.ascee.nl:12001/ASCEE/lasp into windows_ready
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Anne de Jong 2023-05-25 11:43:14 -07:00
commit 0d02779f2e
2 changed files with 64 additions and 34 deletions

View File

@ -1,5 +1,5 @@
#include <mutex>
/* #define DEBUGTRACE_ENABLED */ /* #define DEBUGTRACE_ENABLED */
#include <mutex>
#include "debugtrace.hpp" #include "debugtrace.hpp"
#include "lasp_mathtypes.h" #include "lasp_mathtypes.h"
@ -177,23 +177,22 @@ public:
inParams = std::make_unique<RtAudio::StreamParameters>(); inParams = std::make_unique<RtAudio::StreamParameters>();
// +1 to get the count. /// RtAudio lacks good bookkeeping when the first channel is not equal to
inParams->nChannels = getHighestEnabledInChannel() + 1; /// 0. For now, our fix is to shift out the channels we want, and let
if (inParams->nChannels < 1) { /// RtAudio pass on all channels.
throw rte("Invalid input number of channels");
}
inParams->firstChannel = 0; inParams->firstChannel = 0;
inParams->nChannels = devinfo_gen.ninchannels;
inParams->deviceId = devinfo._api_devindex; inParams->deviceId = devinfo._api_devindex;
} else { } else {
outParams = std::make_unique<RtAudio::StreamParameters>(); outParams = std::make_unique<RtAudio::StreamParameters>();
outParams->nChannels = getHighestEnabledOutChannel() + 1; /// RtAudio lacks good bookkeeping when the first channel is not equal to
if (outParams->nChannels < 1) { /// 0. For now, our fix is to shift out the channels we want, and let
throw rte("Invalid output number of channels"); /// RtAudio pass on all channels.
}
outParams->firstChannel = 0; outParams->firstChannel = 0;
outParams->nChannels = devinfo_gen.noutchannels;
outParams->deviceId = devinfo._api_devindex; outParams->deviceId = devinfo._api_devindex;
} }
@ -355,15 +354,16 @@ public:
const us ch_min = getLowestEnabledInChannel(); const us ch_min = getLowestEnabledInChannel();
const us ch_max = getHighestEnabledInChannel(); 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++) { for (us ch = ch_min; ch <= ch_max; ch++) {
if (inchannel_config.at(ch).enabled) { if (inchannel_config.at(ch).enabled) {
byte_t *ptr = byte_t *ptr =
static_cast<byte_t *>(inputBuffer) + sw * i * nFramesPerBlock; static_cast<byte_t *>(inputBuffer) + sw * ch * nFramesPerBlock;
DEBUGTRACE_PRINT((us)ptr);
ptrs.push_back(ptr); ptrs.push_back(ptr);
} }
i++;
} }
DaqData d{nFramesPerBlock, neninchannels, dtype}; DaqData d{nFramesPerBlock, neninchannels, dtype};
d.copyInFromRaw(ptrs); d.copyInFromRaw(ptrs);
@ -384,14 +384,14 @@ public:
const us ch_min = getLowestEnabledOutChannel(); const us ch_min = getLowestEnabledOutChannel();
const us ch_max = getHighestEnabledOutChannel(); 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++) { for (us ch = ch_min; ch <= ch_max; ch++) {
if (outchannel_config.at(ch).enabled) { if (outchannel_config.at(ch).enabled) {
ptrs.push_back(static_cast<byte_t *>(outputBuffer) + ptrs.push_back(static_cast<byte_t *>(outputBuffer) +
sw * i * nFramesPerBlock); sw * ch * nFramesPerBlock);
} }
i++;
} }
DaqData d{nFramesPerBlock, nenoutchannels, dtype}; DaqData d{nFramesPerBlock, nenoutchannels, dtype};

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import annotations
"""! """!
Author: J.A. de Jong - ASCEE Author: J.A. de Jong - ASCEE
@ -113,7 +114,7 @@ class IterRawData:
nblocks = fa.shape[0] nblocks = fa.shape[0]
blocksize = fa.shape[1] blocksize = fa.shape[1]
self.blocksize = blocksize self.blocksize = blocksize
nchannels = fa.shape[2] # nchannels = fa.shape[2]
self.channels = channels self.channels = channels
self.istart = kwargs.pop('istart', 0) self.istart = kwargs.pop('istart', 0)
@ -143,7 +144,7 @@ class IterRawData:
"""Return the next block.""" """Return the next block."""
fa = self.fa fa = self.fa
nblocks_to_return = self.lastblock-self.firstblock+1 # nblocks_to_return = self.lastblock-self.firstblock+1
block = self.firstblock + self.i block = self.firstblock + self.i
@ -162,7 +163,7 @@ class IterRawData:
# print(f'block: {block}, starto: {start_offset}, stopo {stop_offset}') # print(f'block: {block}, starto: {start_offset}, stopo {stop_offset}')
self.i += 1 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): class IterData(IterRawData):
@ -771,23 +772,32 @@ class Measurement:
samplerate, samplerate,
sensitivity, sensitivity,
mfn, mfn,
timestamp=None): timestamp=None,
"""Converts a numpy array to a LASP Measurement file, opens the qtys: List[SIQtys] = None,
associated Measurement object and returns it. The measurement file will channelNames: List[str] = None,
have the same file name as the txt file, except with h5 extension. force=False) -> Measurement:
"""
Creates a LASP measurement file from input numpy array data.
Opens the associated Measurement object and returns it.
Args: Args:
data: Numpy array, first column is sample, second is channel. Can 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] 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 timestamp: If given, a custom timestamp for the measurement
(integer containing seconds since epoch). If not given, the (integer containing seconds since epoch).
timestamp is obtained from the last modification time.
delimiter: Column delimiter qtys: If a list of physical quantity data is given here
firstcoltime: If true, the first column is the treated as the
sample time. channelNames: Name of the channels
force: If True, overwrites existing files with specified `mfn` force: If True, overwrites existing files with specified `mfn`
name. name.
""" """
@ -801,24 +811,44 @@ class Measurement:
if data.ndim != 2: if data.ndim != 2:
data = data[:, np.newaxis] data = data[:, np.newaxis]
try: try:
len(sensitivity) len(sensitivity)
except: except:
raise ValueError('Sensitivity should be given as array-like data type') raise ValueError('Sensitivity should be given as array-like data type')
sensitivity = np.asarray(sensitivity) sensitivity = np.asarray(sensitivity)
nchannels = data.shape[1] nchannels = data.shape[1]
if nchannels != sensitivity.shape[0]: if nchannels != sensitivity.shape[0]:
raise ValueError( raise ValueError(
f'Invalid sensitivity length given. Should be: {nchannels}') 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: with h5.File(mfn, 'w') as hf:
hf.attrs['samplerate'] = samplerate hf.attrs['samplerate'] = samplerate
hf.attrs['sensitivity'] = sensitivity hf.attrs['sensitivity'] = sensitivity
hf.attrs['time'] = timestamp hf.attrs['time'] = timestamp
hf.attrs['blocksize'] = 1 hf.attrs['blocksize'] = 1
hf.attrs['nchannels'] = nchannels 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]), ad = hf.create_dataset('audio', (1, data.shape[0], data.shape[1]),
dtype=data.dtype, dtype=data.dtype,
maxshape=(1, data.shape[0], data.shape[1]), maxshape=(1, data.shape[0], data.shape[1]),