UNPKG

@iotile/iotile-device

Version:

A typescript library for interfacing with IOTile BLE devices

245 lines 9.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var iotile_common_1 = require("@iotile/iotile-common"); var heatshrink_ts_1 = require("heatshrink-ts"); var constants_1 = require("./constants"); var flexible_dict_report_1 = require("../../common/flexible-dict-report"); /** * Calculate the maximum time that a given threshold is exceeded. * * @param data A list of samples along a single axis in G's * @param threshold The threshold that we should count time above * @param samplingRate The sampling rate of the data in Hz * * @returns The number of ms that data is above threshold in a single continuous * event. */ function timeAboveThreshold(data, threshold, samplingRate) { var maxCount = 0; var currCount = 0; var above = false; var lastSample = 0.0; for (var _i = 0, data_1 = data; _i < data_1.length; _i++) { var sample = data_1[_i]; if (above === false && Math.abs(sample) >= threshold) { above = true; currCount = 0; } else if (above) { currCount += 1; if (Math.abs(sample) < threshold || lastSample * sample < 0.0) { above = false; if (currCount > maxCount) maxCount = currCount; } } lastSample = sample; } if (above && currCount > maxCount) maxCount = currCount; return maxCount / samplingRate * 1000.0; } exports.timeAboveThreshold = timeAboveThreshold; function calculateDeltaV(data, threshold, samplingRate) { var maxDV = 0; var currDV = 0; var above = false; var lastSample = 0.0; var G_CONST = 9.80665; for (var _i = 0, data_2 = data; _i < data_2.length; _i++) { var sample = data_2[_i]; if (above === false && Math.abs(sample) >= threshold) { above = true; currDV = sample; } else if (above) { currDV += sample; if (Math.abs(sample) < threshold || lastSample * sample < 0.0) { above = false; if (Math.abs(currDV) > Math.abs(maxDV)) maxDV = currDV; } } lastSample = sample; } if (above && Math.abs(currDV) > Math.abs(maxDV)) maxDV = currDV; return maxDV / samplingRate * G_CONST; } exports.calculateDeltaV = calculateDeltaV; function maxAbs(data) { var max = 0.0; for (var _i = 0, data_3 = data; _i < data_3.length; _i++) { var value = data_3[_i]; if (Math.abs(value) > max) { max = Math.abs(value); } } return max; } exports.maxAbs = maxAbs; function summarizeAxis(data, threshold, samplingRate) { return { deltaV: calculateDeltaV(data, threshold, samplingRate), peak: maxAbs(data), timeAboveThreshold: timeAboveThreshold(data, threshold, samplingRate) }; } exports.summarizeAxis = summarizeAxis; function summarizeWaveform(wave) { var xSummary = summarizeAxis(wave.acceleration_data.x, 1.0, wave.sampling_rate); var ySummary = summarizeAxis(wave.acceleration_data.y, 1.0, wave.sampling_rate); var zSummary = summarizeAxis(wave.acceleration_data.z, 1.0, wave.sampling_rate); var peakAxis = 'x'; var peak = xSummary.peak; var duration = xSummary.timeAboveThreshold; if (ySummary.peak > peak) { peakAxis = 'y'; peak = ySummary.peak; duration = ySummary.timeAboveThreshold; } if (zSummary.peak > peak) { peakAxis = 'z'; peak = zSummary.peak; duration = zSummary.timeAboveThreshold; } return { peak: peak, axis: peakAxis, duration: duration, delta_v_x: xSummary.deltaV, delta_v_y: ySummary.deltaV, delta_v_z: zSummary.deltaV }; } exports.summarizeWaveform = summarizeWaveform; /** * Unpack an array buffer that corresponds to a list of VLE encoded integers. * * The function assumes that the input buffer was created from a list of integers * in the range of -4095 to 4095 that were processed in the following way to * create this binary buffer: * * - They were delta encoded, so all entries after the first were stored as * the difference between the value and the last value. * - They were zig-zag encoded so that all negative values became positive. * - They were packed as variable length integers where 7-bit values are stored * as a single byte and all other values are stored as two bytes. * * This function undoes all three of these packing steps * * @param input A list of integers that have been encoded in the following * way: first they were delta encoded, then they were zigzag * encoded and finally they were delta encoded. */ function unpackVLEIntegerList(input) { var inputBytes = new Uint8Array(input); var outputNumbers = []; var accum = 0; var shift = 0; /* * First undo the variant length encoding, in which numbers * between -64 and 63, inclusive are encoded in a single byte * with the 7th bit clear and other numbers are encoded in * two bytes with the 7th bit of the first byte set. The * packing is little-endian. * * We simultaneously remove the zig-zag encoding to turn these * values back into signed integers. */ for (var i = 0; i < inputBytes.byteLength; ++i) { var val = inputBytes[i]; if (val & (1 << 7)) { accum |= (val & (0x7f)); shift = 7; } else { accum |= ((val & 0x7f) << shift); var zigzag = ((accum >>> 1)) ^ -(accum & 1); accum = 0; shift = 0; outputNumbers.push(zigzag); } } /** * Undo the delta encoding on each of the numbers now that * we have them back in their pristine state. */ for (var i = 1; i < outputNumbers.length; ++i) { outputNumbers[i] += outputNumbers[i - 1]; } return outputNumbers; } exports.unpackVLEIntegerList = unpackVLEIntegerList; function decompressWaveforms(rawWaveforms) { var decoder = new heatshrink_ts_1.HeatshrinkDecoder(constants_1.WINDOW_BITS, constants_1.LOOKAHEAD_BITS, constants_1.INPUT_BUFFER_LENGTH); var accelerationData = []; var waveforms = {}; for (var wave in rawWaveforms) { var rawWaveform = rawWaveforms[wave]; accelerationData = []; /* * Un-heatshrink each waveform separately since they are encoded separately. * In particular, we do not want any sliding window shared between subsequent * waveforms. */ decoder.reset(); decoder.process(rawWaveforms[wave].rawWaveform); var expanded = decoder.getOutput(); // variable length decoding var vleDecoded = unpackVLEIntegerList(expanded.buffer); if (vleDecoded.length != 3072) { throw new iotile_common_1.InvalidDataError('Waveform Decompression Error', "Received number of data points is incorrect; parsed " + vleDecoded.length + " of 3072"); } // convert from device internal storage to Gs for (var _i = 0, vleDecoded_1 = vleDecoded; _i < vleDecoded_1.length; _i++) { var v = vleDecoded_1[_i]; accelerationData.push(v * .049); } var waveformData = { acceleration_data: { x: accelerationData.slice(0, 1024), y: accelerationData.slice(1024, 2048), z: accelerationData.slice(2048) }, sampling_rate: constants_1.SAMPLING_RATE, crc_code: rawWaveform.crcCode }; waveforms[wave] = { deviceTimestamp: rawWaveform.timestamp, utcTimestamp: tryConvertUTCTimestamp(rawWaveform.timestamp), summary: summarizeWaveform(waveformData), waveform: waveformData }; /** * If the waveform has an embedded UTC timestamp, promote it to the waveform's UTC time. */ } return waveforms; } exports.decompressWaveforms = decompressWaveforms; function tryConvertUTCTimestamp(deviceTimestamp) { if (deviceTimestamp === 0xFFFFFFFF) return null; if (!(deviceTimestamp & (1 << 31))) return null; //Mask out the high bit to leave the lower 31 bits var y2kDelta = deviceTimestamp & ((1 << 31) - 1); var y2k = new Date('2000-01-01T00:00:00Z'); var timestamp = y2k.getTime() + y2kDelta * 1000; var utcDate = new Date(timestamp); return utcDate; } exports.tryConvertUTCTimestamp = tryConvertUTCTimestamp; /** * Create IOTileEvents for all waveforms. */ function createWaveformEvents(waveforms) { var events = []; var streamID = 0x5020; for (var uniqueId in waveforms) { var waveform = waveforms[uniqueId]; var event_1 = new flexible_dict_report_1.IOTileEvent(streamID, waveform.deviceTimestamp, waveform.summary, waveform.waveform, +uniqueId, waveform.utcTimestamp); events.push(event_1); } return events; } exports.createWaveformEvents = createWaveformEvents; //# sourceMappingURL=utilities.js.map