Bugfix for float32 data type. Neoformat comment markup

This commit is contained in:
Anne de Jong 2020-04-29 15:00:00 +02:00
parent 7cc77b073a
commit 82ec7faa45

View File

@ -45,12 +45,10 @@ import time
class BlockIter: class BlockIter:
""" """Iterate over the blocks in the audio data of a h5 file."""
Iterate over the blocks in the audio data of a h5 file
"""
def __init__(self, f): def __init__(self, f):
""" """Initialize a BlockIter object.
Initialize a BlockIter object
Args: Args:
faudio: Audio dataset in the h5 file, accessed as f['audio'] faudio: Audio dataset in the h5 file, accessed as f['audio']
@ -63,9 +61,7 @@ class BlockIter:
return self return self
def __next__(self): def __next__(self):
""" """Return the next block."""
Return the next block
"""
if self.i == self.nblocks: if self.i == self.nblocks:
raise StopIteration raise StopIteration
self.i += 1 self.i += 1
@ -73,8 +69,7 @@ class BlockIter:
def getSampWidth(dtype): def getSampWidth(dtype):
""" """Returns the width of a single sample in bytes.
Returns the width of a single sample in bytes.
Args: Args:
dtype: numpy dtype dtype: numpy dtype
@ -82,7 +77,7 @@ def getSampWidth(dtype):
Returns: Returns:
Size of a sample in bytes (int) Size of a sample in bytes (int)
""" """
if dtype == np.int32: if dtype in (np.int32, np.float32):
return 4 return 4
elif dtype == np.int16: elif dtype == np.int16:
return 2 return 2
@ -93,15 +88,12 @@ def getSampWidth(dtype):
def scaleBlockSens(block, sens): def scaleBlockSens(block, sens):
""" """Scale a block of raw data to return raw acoustic pressure data.
Scale a block of raw data to return raw acoustic
pressure data.
Args: Args:
block: block of raw data with integer data type block: block of raw data with integer data type
sensitivity: array of sensitivity coeficients for sensitivity: array of sensitivity coeficients for
each channel each channel
""" """
assert sens.ndim == 1 assert sens.ndim == 1
assert sens.size == block.shape[1] assert sens.size == block.shape[1]
@ -129,14 +121,11 @@ def exportAsWave(fn, fs, data, force=False):
class Measurement: class Measurement:
""" """Provides access to measurement data stored in the h5 measurement file
Provides access to measurement data stored in the h5 measurement file format."""
format.
"""
def __init__(self, fn): def __init__(self, fn):
""" """Initialize a Measurement object based on the filename."""
Initialize a Measurement object based on the filename
"""
if '.h5' not in fn: if '.h5' not in fn:
fn += '.h5' fn += '.h5'
@ -190,9 +179,7 @@ class Measurement:
@property @property
def name(self): def name(self):
""" """Returns filename base without extension."""
Returns filename base without extension
"""
return os.path.splitext(self.fn_base)[0] return os.path.splitext(self.fn_base)[0]
@property @property
@ -201,8 +188,7 @@ class Measurement:
@contextmanager @contextmanager
def file(self, mode='r'): def file(self, mode='r'):
""" """Contextmanager which opens the storage file and yields the file.
Contextmanager which opens the storage file and yields the file.
Args: Args:
mode: Opening mode for the file. Should either be 'r', or 'r+' mode: Opening mode for the file. Should either be 'r', or 'r+'
@ -214,8 +200,7 @@ class Measurement:
@property @property
def comment(self): def comment(self):
""" """Return the measurement comment.
Return the measurement comment
Returns: Returns:
The measurement comment (text string) The measurement comment (text string)
@ -224,8 +209,7 @@ class Measurement:
@comment.setter @comment.setter
def comment(self, cmt): def comment(self, cmt):
""" """Set the measurement comment.
Set the measurement comment
Args: Args:
cmt: Comment text string to set cmt: Comment text string to set
@ -237,24 +221,19 @@ class Measurement:
@property @property
def recTime(self): def recTime(self):
""" """Returns the total recording time of the measurement, in float
Returns seconds."""
the total recording time of the measurement, in float seconds.
"""
return self.blocksize * self.nblocks / self.samplerate return self.blocksize * self.nblocks / self.samplerate
@property @property
def time(self): def time(self):
""" """Returns the measurement time in seconds since the epoch."""
Returns the measurement time in seconds since the epoch.
"""
return self._time return self._time
def scaleBlock(self, block): def scaleBlock(self, block):
""" """When the data is stored as integers, we assume dB full-scale
When the data is stored as integers, we assume dB full-scale scaling. scaling. Hence, when we convert the data to floats, we divide by the
Hence, when we convert the data to floats, we divide by the maximum maximum possible value.
possible value.
Returns: Returns:
Block of measurement data, scaled using sensitivity values and Block of measurement data, scaled using sensitivity values and
@ -264,8 +243,7 @@ class Measurement:
@property @property
def prms(self): def prms(self):
""" """Returns the root mean square of the uncalibrated rms sound pressure
Returns the root mean square of the uncalibrated rms sound pressure
level (equivalend SPL). level (equivalend SPL).
Returns: Returns:
@ -287,10 +265,8 @@ class Measurement:
return self._prms return self._prms
def praw(self, block=None): def praw(self, block=None):
""" """Returns the uncalibrated acoustic pressure signal, converted to
Returns the uncalibrated acoustic pressure signal, converted to floating point acoustic pressure values [Pa]."""
floating point acoustic pressure values [Pa].
"""
if block is not None: if block is not None:
with self.file() as f: with self.file() as f:
blocks = f['audio'][block] blocks = f['audio'][block]
@ -308,8 +284,7 @@ class Measurement:
return blocks return blocks
def iterBlocks(self, opened_file): def iterBlocks(self, opened_file):
""" """Iterate over all the audio blocks in the opened file.
Iterate over all the audio blocks in the opened file
Args: Args:
opened_file: The h5File with the data opened_file: The h5File with the data
@ -318,20 +293,19 @@ class Measurement:
@property @property
def sensitivity(self): def sensitivity(self):
""" """Sensitivity of the data in Pa^-1, from floating point data scaled
Sensitivity of the data in Pa^-1, from floating point data scaled between -1.0 and 1.0 to Pascal.
between -1.0 and 1.0 to Pascal. If the sensitivity is not stored in
the measurement file, this function returns 1.0 If the sensitivity is not stored in the measurement file, this
function returns 1.0
""" """
return self._sens return self._sens
def checkOverflow(self): def checkOverflow(self):
""" """Coarse check for overflow in measurement.
Coarse check for overflow in measurement
Return: Return:
True if overflow is possible, else False True if overflow is possible, else False
""" """
with self.file() as f: with self.file() as f:
@ -347,17 +321,16 @@ class Measurement:
return False return False
return False return False
@sensitivity.setter @sensitivity.setter
def sensitivity(self, sens): def sensitivity(self, sens):
""" """Set the sensitivity of the measurement in the file.
Set the sensitivity of the measurement in the file
Args: Args:
sens: sensitivity data, should be a float, or an array of floats sens: sensitivity data, should be a float, or an array of floats
equal to the number of channels. equal to the number of channels.
""" """
if isinstance(sens, float): if isinstance(sens, float):
# Put all sensitivities equal
sens = sens * np.ones(self.nchannels) sens = sens * np.ones(self.nchannels)
valid = sens.ndim == 1 valid = sens.ndim == 1
@ -370,9 +343,8 @@ class Measurement:
self._sens = sens self._sens = sens
def exportAsWave(self, fn=None, force=False, newsampwidth=2, normalize=True): def exportAsWave(self, fn=None, force=False, newsampwidth=2, normalize=True):
""" """Export measurement file as wave. In case the measurement data is
Export measurement file as wave. In case the measurement data is stored stored as floats, the values are scaled between 0 and 1.
as floats, the values are scaled between 0 and 1
Args: Args:
fn: If given, this will be the filename to write to. If the fn: If given, this will be the filename to write to. If the
@ -386,8 +358,6 @@ class Measurement:
floating point values, otherwise an error is thrown floating point values, otherwise an error is thrown
normalize: If set: normalize the level to something sensible. normalize: If set: normalize the level to something sensible.
""" """
if fn is None: if fn is None:
fn = self.fn fn = self.fn
@ -442,10 +412,9 @@ class Measurement:
timestamp=None, timestamp=None,
delimiter='\t', delimiter='\t',
firstcoltime=True): firstcoltime=True):
""" """Converts a txt file to a LASP Measurement file, opens the associated
Converts a txt file to a LASP Measurement file, opens the associated Measurement object and returns it. The measurement file will have the
Measurement object and returns it. The measurement file will have same file name as the txt file, except with h5 extension.
the same file name as the txt file, except with h5 extension.
Args: Args:
fn: Filename of text file fn: Filename of text file
@ -460,7 +429,6 @@ class Measurement:
delimiter: Column delimiter delimiter: Column delimiter
firstcoltime: If true, the first column is the treated as the firstcoltime: If true, the first column is the treated as the
sample time. sample time.
""" """
if not os.path.exists(fn): if not os.path.exists(fn):
raise ValueError(f'File {fn} does not exist.') raise ValueError(f'File {fn} does not exist.')
@ -497,7 +465,6 @@ class Measurement:
compression='gzip') compression='gzip')
ad[0] = dat ad[0] = dat
return Measurement(mfn) return Measurement(mfn)
@staticmethod @staticmethod
def fromnpy(data, def fromnpy(data,
@ -505,14 +472,12 @@ class Measurement:
sensitivity, sensitivity,
mfn, mfn,
timestamp=None): timestamp=None):
""" """Converts a numpy array to a LASP Measurement file, opens the
Converts a numpy array to a LASP Measurement file, opens the associated associated Measurement object and returns it. The measurement file will
Measurement object and returns it. The measurement file will have have the same file name as the txt file, except with h5 extension.
the same file name as the txt file, except with h5 extension.
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] sensitivity: 1D array of channel sensitivities [Pa^-1]
@ -523,7 +488,6 @@ class Measurement:
delimiter: Column delimiter delimiter: Column delimiter
firstcoltime: If true, the first column is the treated as the firstcoltime: If true, the first column is the treated as the
sample time. sample time.
""" """
if os.path.exists(mfn): if os.path.exists(mfn):
raise ValueError(f'File {mfn} already exist.') raise ValueError(f'File {mfn} already exist.')