Skip to content

Commit

Permalink
Merge branch 'release/v3.2.9' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
StokesMIDE committed Jul 14, 2023
2 parents ad91ef5 + 56c0a08 commit 02ba494
Show file tree
Hide file tree
Showing 16 changed files with 132 additions and 121,002 deletions.
48 changes: 27 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,31 +70,37 @@ Each `Channel` object has a `subchannels` member, which is a list of

The below table lists current conventions for channels across all enDAQ sensors:

| (Abbreviated) Product No. | Description | Example Product Nos. |
|--------------------------:|-----------------------------------------------------------------------------------|-------------------------|
| S-D | enDAQ S-series devices with single digital accelerometers | S3-D16, S4-D40 |
| S-DD | enDAQ S-series devices with dual digital accelerometers | S1-D100D40, S2-D25D16 |
| S-ED | enDAQ S-series devices with an analog electrocapacitive and digital accelerometer | S5-E25D40, S4-E100D40 |
| S-RD | enDAQ S-series devices with an analog piezoresistive and digital accelerometer | S4-R500D40, S5-R2000D40 |
| SSX | Midé Slam Stick X data recorders | SSX |
| SSC | Midé Slam Stick C data recorders | SSC |
| SSS | Midé Slam Stick S data recorders | SSS |
| (Abbreviated) Product No. | Description | Example Product Nos. |
|--------------------------:|--------------------------------------------------------------------------------|-------------------------|
| S-D | enDAQ S-series devices with a single digital accelerometer | S3-D16, S4-D40 |
| S-DD | enDAQ S-series devices with dual digital accelerometers | S1-D100D40, S2-D25D16 |
| S-ED | enDAQ S-series devices with an analog piezoelectric and digital accelerometer | S5-E25D40, S4-E100D40 |
| S-RD | enDAQ S-series devices with an analog piezoresistive and digital accelerometer | S4-R500D40, S5-R2000D40 |
| W-D | enDAQ W-series devices with a single digital accelerometer | W5-D40 |
| W-ED | enDAQ W-series devices with an analog piezoelectric and digital accelerometer | W8-E100D40, W8-E2000D40 |
| W-RD | enDAQ W-series devices with an analog piezoresistive and digital accelerometer | W8-R500D40, W8-R2000D40 |
| SSX | Midé Slam Stick X data recorders | SSX |
| SSC | Midé Slam Stick C data recorders | SSC |
| SSS | Midé Slam Stick S data recorders | SSS |

The below table lists channel ID numbers used in a recording file based on the
recording device’s product number (device series numbers and accelerometer
sensitivity ranges are omitted when applicable to all such devices):

| Sensor | Channel | Valid Devices | Suchannels |
|----------------------:|:--------|------------------------------------|----------------------------------------------|
| Main Accelerometer | 8 | S-RD, S-ED, SSS, SSX | X-, Y-, Z-axis Acceleration |
| 16/200g Accelerometer | 32 | S-DD, SSX, SSS, SSC, S-D16, S-D200 | X-, Y-, Z-axis Acceleration |
| 8/40g Accelerometer | 80 | S-RD, S-DD, S-ED, S-D40, S-D8 | X-, Y-, Z-axis Acceleration |
| IMU Gyroscope | 47 | All<sup>1</sup> | X-, Y-, Z-axis Rotation |
| Absolute Orientation | 65 | All<sup>1</sup> | X-, Y-, Z-, W-axis Quaternion; Acc |
| Relative Orientation | 70 | All<sup>1</sup> | X-, Y-, Z-, W-axis Quaternion |
| MPL3115 | 36 | All<sup>1</sup> | Pressure, Temperature <sup>2</sup> |
| MS8607 | 59 | All<sup>1</sup> | Pressure, Temperature, Humidity <sup>3</sup> |
| SI1133 | 76 | All<sup>1</sup> | Lux, UV |
| Sensor | Channel | Valid Devices | Suchannels |
|------------------------:|:--------|-----------------------------------------|------------------------------------|
| Main Accelerometer | 8 | S-RD, S-ED, SSS, SSX | X-, Y-, Z-axis Acceleration |
| 16/200g Accelerometer | 32 | S-DD, SSX, SSS, SSC, S-D16, S-D200 | X-, Y-, Z-axis Acceleration |
| 8/40g Accelerometer | 80 | S-RD, S-DD, S-ED, S-D40, S-D8 | X-, Y-, Z-axis Acceleration |
| IMU Gyroscope | 47 | All<sup>1</sup> | X-, Y-, Z-axis Rotation |
| Absolute Orientation | 65 | All<sup>1</sup> | X-, Y-, Z-, W-axis Quaternion; Acc |
| Relative Orientation | 70 | All<sup>1</sup> | X-, Y-, Z-, W-axis Quaternion |
| MPL3115 | 36 | S-D16, All<sup>1</sup> before Mid-2023 | Pressure, Temperature <sup>2</sup> |
| MS8607 Internal | 20 | All<sup>1</sup> after Mid-2023 | Pressure, Temperature, Humidity |
| MS8607 Control Pad | 59 | All<sup>1</sup> | Pressure, Temperature, Humidity |
| SI1133 | 76 | All<sup>1</sup> | Lux, UV |
| BMI270/BMG250 Gyroscope | 84 | All<sup>1</sup> after Mid-2023 | X-, Y-, Z-axis Rotation |
| CAM-M8Q GPS | 88 | W-D, W-ED, W-RD | Latitude, Longitude, Time, Speed |

<sup>1</sup> excluding early SSC/SSS/SSX models

Expand Down Expand Up @@ -126,7 +132,7 @@ For channels, this will be a (c+1)-by-n array, where n is the number of samples
recorded and c is the number of subchannels; `eventarray[1:]` indexes the
samples, `eventarray[0]` indexes the respective timestamps.

### Getting metadta
### Getting metadata

`Dataset` makes available some basic metadata. Some useful pieces of information
are stored directly as members:
Expand Down
5 changes: 3 additions & 2 deletions idelib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
"""

__author__ = "David Randall Stokes"
__copyright__ = "Copyright (c) 2022 Midé Technology"
__copyright__ = "Copyright (c) 2023 Midé Technology"

__maintainer__ = "Midé Technology"
__email__ = "help@mide.com"

__version__ = (3, 2, 4)
__version__ = '3.2.9'

__status__ = "Production/Stable"

from .importer import importFile
Expand Down
64 changes: 44 additions & 20 deletions idelib/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,12 @@
__all__ = ['Channel', 'Dataset', 'EventArray', 'Plot', 'Sensor', 'Session',
'SubChannel', 'WarningRange', 'Cascading', 'Transformable']

from bisect import bisect_right
from collections.abc import Iterable, Sequence
from datetime import datetime
from threading import Lock
import warnings

from functools import partial
import os.path
import random
import struct
import sys
from time import sleep
Expand All @@ -70,16 +67,13 @@
SCHEMA_FILE = 'mide_ide.xml'

#===============================================================================
# DEBUGGING: XXX: Remove later!
#
#===============================================================================

import logging
logger = logging.getLogger('idelib')
logging.basicConfig(format="%(asctime)s %(levelname)s: %(message)s")


# __DEBUG__ = False

__DEBUG__ = str(os.environ.get('MIDE_DEV', 0)) == '1'

if __DEBUG__:
Expand All @@ -91,6 +85,13 @@
# logger.info("Loaded python-ebml from %s" % os.path.abspath(ebml.__file__))


def mapRange(x, in_min, in_max, out_min, out_max):
""" Given a value `x` between `in_min` and `in_max`, get the equivalent
value relative to `out_min` and `out_max`.
"""
return ((x - in_min + 0.0) * (out_max - out_min) /
(in_max - in_min) + out_min)

#===============================================================================
# Mix-In Classes
#===============================================================================
Expand Down Expand Up @@ -1948,8 +1949,17 @@ def getEventIndexBefore(self, t):
block = self._data[blockIdx]
except IndexError:
block = self._data[-1]
return int(block.indexRange[0] + \
((t - block.startTime) / self._getBlockSampleTime(blockIdx)))

if t > block.endTime:
# Time falls within a gap between blocks
return block.indexRange[-1]

return int(mapRange(t,
block.startTime, block.endTime,
block.indexRange[0], block.indexRange[1]-1))

# return int((block.indexRange[0] +
# ((t - block.startTime) / self._getBlockSampleTime(blockIdx))))


def getEventIndexNear(self, t):
Expand Down Expand Up @@ -1990,15 +2000,20 @@ def getRangeIndices(self, startTime, endTime):
return startIdx, endIdx

if startTime is None or startTime <= self._data[0].startTime:
startIdx = startBlockIdx = 0
startBlock = self._data[0]
startIdx = 0
else:
startBlockIdx = self._getBlockIndexWithTime(startTime)
startBlock = self._data[startBlockIdx]
startIdx = int(startBlock.indexRange[0] + \
((startTime - startBlock.startTime) / \
self._getBlockSampleTime(startBlockIdx)) + 1)


if startTime < startBlock.endTime:
# Start time is within a block (the usual case)
startIdx = int((startBlock.indexRange[0] +
((startTime - startBlock.startTime) /
self._getBlockSampleTime(startBlockIdx)) + 1))
else:
# Start time falls within a gap between blocks
startIdx = startBlock.indexRange[1]

if endTime is None:
endIdx = self._data[-1].indexRange[1]
elif endTime <= self._data[0].startTime:
Expand Down Expand Up @@ -2170,6 +2185,8 @@ def arrayMinMeanMax(self, startTime=None, endTime=None, padding=0,
:return: A structured array of data block statistics (min, mean,
and max, respectively).
"""
if not self._data:
return None

startBlock, endBlock = self._getBlockRange(startTime, endTime)
shape = (3, max(1, len(self._npType)) + int(times), endBlock - startBlock)
Expand Down Expand Up @@ -2224,10 +2241,14 @@ def arrayMinMeanMax(self, startTime=None, endTime=None, padding=0,
xform.inplace(out[m, :, :], out=out[m, :, :])

# iterate through the arrayMinMeanMaxes specific to each subchannel
for i in range(int(times), out.shape[1]):
# swap mins and maxes if a (negative) transform has made min > max
if out[0, i, 0] > out[2, i, 0]:
out[:, i] = np.flipud(out[:, i])
try:
for i in range(int(times), out.shape[1]):
# swap mins and maxes if a (negative) transform has made min > max
if out[0, i, 0] > out[2, i, 0]:
out[:, i] = np.flipud(out[:, i])
except IndexError:
logger.warning('Channel contains no data')
return None

return out

Expand Down Expand Up @@ -2276,7 +2297,7 @@ def getRangeMinMeanMax(self, startTime=None, endTime=None, subchannel=None,
stats = self.arrayMinMeanMax(startTime, endTime, times=False,
display=display, iterator=iterator)

if stats.size == 0:
if stats is None or stats.size == 0:
return None
if self.hasSubchannels and subchannel is not None:
return (
Expand Down Expand Up @@ -2521,6 +2542,9 @@ def getMean(self, startTime=None, endTime=None, display=False, iterator=iter):
means = self.arrayMinMeanMax(startTime, endTime, times=False,
display=display, iterator=iterator)[1]

if means is None:
return None

mean = np.mean(np.average(means, weights=[d.numSamples for d in self._data], axis=-1))

if startTime is None and endTime is None:
Expand Down
3 changes: 2 additions & 1 deletion idelib/matfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,8 @@ def startArray(self, name, cols, rows=1, arrayNumber=0,
self.packStr(sanitizeName(name))

# Write the start of the 'PR' element; the size will be filled in later.
self._write(struct.pack('II', self.arrayDType, self.rowFormatter.size * rows))
size = min(self.rowFormatter.size * rows, 2 ** 32 - 1)
self._write(struct.pack('II', self.arrayDType, size))
self.prSize = self.stream.tell() - 4


Expand Down
22 changes: 18 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import codecs
import os
import setuptools

with open('README.md', 'r', encoding='utf-8') as fh:
long_description = fh.read()
def read(rel_path):
here = os.path.abspath(os.path.dirname(__file__))
with codecs.open(os.path.join(here, rel_path), 'r') as fp:
return fp.read()


def get_version(rel_path):
for line in read(rel_path).splitlines():
if line.startswith('__version__'):
delim = '"' if '"' in line else "'"
return line.split(delim)[1]
else:
raise RuntimeError("Unable to find version string.")


INSTALL_REQUIRES = [
'numpy',
Expand Down Expand Up @@ -29,11 +43,11 @@

setuptools.setup(
name='idelib',
version='3.2.8',
version=get_version('idelib/__init__.py'),
author='Mide Technology',
author_email='help@mide.com',
description='Python API for accessing IDE data recordings',
long_description=long_description,
long_description=read('README.md'),
long_description_content_type='text/markdown',
url='https://github.com/MideTechnology/idelib',
license='MIT',
Expand Down
Binary file added testing/Discontinuities.IDE
Binary file not shown.
Loading

0 comments on commit 02ba494

Please sign in to comment.