From edd17c1dbe0612897d357399bd0086b365d01ae3 Mon Sep 17 00:00:00 2001 From: Martin Donnelly Date: Thu, 23 Jun 2016 13:40:47 +0100 Subject: [PATCH] FFT Work --- app/js/device/CC2650/cc2650_accelerometer.js | 115 +++- app/js/standards/capability.js | 3 +- gulpfile.js | 9 +- .../2.2.1/taskArtifacts/cache.properties.lock | Bin 17 -> 17 bytes .../2.2.1/taskArtifacts/fileHashes.bin | Bin 155367 -> 155699 bytes .../2.2.1/taskArtifacts/fileSnapshots.bin | Bin 11360782 -> 11360782 bytes .../2.2.1/taskArtifacts/taskArtifacts.bin | Bin 61031 -> 61031 bytes www/js/index.js | 599 ------------------ 8 files changed, 122 insertions(+), 604 deletions(-) delete mode 100644 www/js/index.js diff --git a/app/js/device/CC2650/cc2650_accelerometer.js b/app/js/device/CC2650/cc2650_accelerometer.js index d724221..c7edec7 100644 --- a/app/js/device/CC2650/cc2650_accelerometer.js +++ b/app/js/device/CC2650/cc2650_accelerometer.js @@ -115,6 +115,7 @@ CC2650_ACCEL = function(p) { this.startService = function() { + this.maxLength = 255; if (this.deviceID !== null) { console.log('Starting CC2650 Accelerometer Service on ', this.deviceID); @@ -154,6 +155,114 @@ CC2650_ACCEL = function(p) { }; + this.advancedGraphFFT = function(mode, data, subID) { + var xstep; + var scalePos; + var lm; + var ceiling; + var elm; + var text2ID; + var ceilingLimit; + var calcArray; + var floor; + var _subID; + var _data; + var text1ID; + var lineID; + var max; + + var reducer = function(p, v) { + return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v)); + }; + + + var parts = ['x', 'y', 'z']; + var _newData = {x: [],y: [],z: []}; + + _data = data || this.data; + + _subID = subID || ''; + + // LineID = [this.frameID , _subID , '-line'].join(''); + text1ID = [this.frameID, _subID, '-txt1'].join(''); + text2ID = [this.frameID, _subID, '-txt2'].join(''); + ceiling = 0; + if (_data.x.length > 0) { + + max = 2; + + for (var lineMode = 0; lineMode < parts.length; lineMode++) { + + + lm = parts[lineMode]; + + var data = new complex_array.ComplexArray(_data[lm]); + + + data.FFT(); + + data.forEach(function(c_value, i) { + ceiling = reducer(c_value.real ,ceiling); + _newData[lm].push(c_value.real); + }); + + //Ceiling = _data[lm].reduce(reducer); + + console.log('ceiling:', ceiling); + + + } + + if (ceiling > 500) { + max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 50) * 50) : max; + } else { + max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 10) * 10) : max; + } + ceiling = max; + + floor = ceiling * -1; + ceilingLimit = ceiling; + console.log('ceiling:',ceiling); + + scalePos = (124 / 2) / ceiling; + + xstep = (680 - 46) / this.maxLength; + + //Var xstep = 2.34; + + for (lineMode = 0; lineMode < parts.length; lineMode++) { + + lm = parts[lineMode]; + var startX = 46 + (this.maxLength - _newData[lm].length) * xstep; + + calcArray = []; + + lineID = this.frameID + _subID + '-' + lm + '-line'; + for (var x = 0; x < _newData[lm].length; x++) { + + calcArray.push((startX + (x * xstep)).toFixed(2) + ',' + (71 - ((_newData[lm][x]) * scalePos)).toFixed( + 2)); + + } + + elm = document.getElementById(lineID); + + elm.setAttribute('points', calcArray.join(' ')); + + } + + elm = document.getElementById(text1ID); + elm.textContent = ceilingLimit; + + elm = document.getElementById(text2ID); + elm.textContent = floor; + + } + + this.previousCeil = ceiling; + }; + + this.advancedGraph = function(mode, data, subID) { var xstep; @@ -212,14 +321,14 @@ CC2650_ACCEL = function(p) { scalePos = (124 / 2) / ceiling; - xstep = (680 - 46) / 100; + xstep = (680 - 46) / this.maxLength; //Var xstep = 2.34; for (lineMode = 0; lineMode < parts.length; lineMode++) { lm = parts[lineMode]; - var startX = 46 + (100 - _data[lm].length) * xstep; + var startX = 46 + (this.maxLength - _data[lm].length) * xstep; calcArray = []; @@ -252,7 +361,7 @@ CC2650_ACCEL = function(p) { // Nothing to animate yet // return -1; - this.advancedGraph(0, this.data.gyro, 'gyro'); + this.advancedGraphFFT(0, this.data.gyro, 'gyro'); this.advancedGraph(0, this.data.accel, 'accel'); this.advancedGraph(0, this.data.mag, 'mag'); // This.simpleGraph(this.data.temp, 'temp'); diff --git a/app/js/standards/capability.js b/app/js/standards/capability.js index 7c108a8..ac9eab6 100644 --- a/app/js/standards/capability.js +++ b/app/js/standards/capability.js @@ -45,6 +45,7 @@ var CAPABILITY = function(p) { this.target = null; this.$frame = null; + this.maxLength = 99; this.previousCeil = 0; @@ -114,7 +115,7 @@ CAPABILITY.prototype.storeData = function(data, alt) { } var target = alt || this.data; - if (target.length === 99) { + if (target.length === this.maxLength) { target = target.slice(1); } diff --git a/gulpfile.js b/gulpfile.js index 2e38c35..d6b8d6a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -70,10 +70,17 @@ gulp.task('devices', function() { .pipe(gulp.dest('www/js')); }); +/* + + + + */ gulp.task('vendor', function() { return gulp.src(['app/libs/jquery/dist/jquery.min.js', 'app/libs/mui/packages/cdn/js/mui.min.js', - 'app/libs/ejs/ejs_production.js']) + 'app/libs/ejs/ejs_production.js', + 'app/libs/jsfft/complex_array.js', + 'app/libs/jsfft/fft.js']) .pipe(concat('vendor.js')) .pipe(uglify({mangle: false})) .pipe(gulp.dest('www/libs')); diff --git a/platforms/android/.gradle/2.2.1/taskArtifacts/cache.properties.lock b/platforms/android/.gradle/2.2.1/taskArtifacts/cache.properties.lock index 2792132315c725ae9a5d4316b29dfc21f58fb489..d0619099d7cd890eff4903b92950e0bce24d3bf1 100644 GIT binary patch literal 17 WcmZQx&{6#8*tO}73?RTNs{sH%8U;T9 literal 17 WcmZQx&{6#8*tO}73?RVrgBt)qum$`8 diff --git a/platforms/android/.gradle/2.2.1/taskArtifacts/fileHashes.bin b/platforms/android/.gradle/2.2.1/taskArtifacts/fileHashes.bin index 81da1bf2b5ce7e7f1e8c6f71fad4e0b54cdcdcff..5102f1fa6b2c9ec2821e21a9c6eb104a4b9430e4 100644 GIT binary patch delta 31753 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 delta 6448 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', - {id: newId, class: 'mui-panel deviceRow', style: 'min-height:75px;'}); - - newRow = $('
', {class: 'mui-row'}); - - newRow.append($('
', - {class: 'mui-col-xs-12 mui--text-title', text: device.id})); - - newPanel.append(newRow); - - newRow = $('
', {class: 'mui-row'}); - newRow.append($('
', {class: 'mui-col-xs-3', text: 'Name:'})); - newRow.append($('
', {class: 'mui-col-xs-3', text: title})); - - if (typeof otherData !== 'undefined' && otherData !== null && otherData.hasOwnProperty( - 'txpower')) { - if (device.hasOwnProperty('rssiBuffer') && (device.rssiBuffer.length > 0)) { - sum = device.rssiBuffer.reduce(function(a, b) { return a + b; }); - avg = sum / device.rssiBuffer.length; - accuracy = app.calculateDistance(otherData.txpower, avg); - } else { - accuracy = app.calculateDistance(otherData.txpower, device.rssi); - } - - dString = (accuracy <= 30.00) ? accuracy.toFixed(2) + ' m' : 'Far'; - newRow.append($('
', {class: 'mui-col-xs-3', text: 'Distance:'})); - newRow.append($('
', {class: 'mui-col-xs-3', text: dString})); - - } else { - newRow.append($('
', {class: 'mui-col-xs-3', text: 'RSSI:'})); - newRow.append($('
', - {class: 'mui-col-xs-3', text: device.rssi + ' dB'})); - - } - - newPanel.append(newRow); - - if (typeof otherData !== 'undefined' && otherData !== null) { - if (otherData.hasOwnProperty('msg')) { - newRow = $('
', {class: 'mui-row'}); - newRow.append($('
', {class: 'mui-col-xs-3', text: 'Details:'})); - newRow.append($('
', {class: 'mui-col-xs-8', text: otherData.msg})); - newPanel.append(newRow); - } - } - - return newPanel; - }, extractPData: function(prev) { - 'use strict'; - - if (typeof prev === 'undefined' || prev === null) { - return {}; - } - return prev.pData; - - }, extractRSSIBuffer: function(prev) { - 'use strict'; - - if (typeof prev === 'undefined' || prev === null) { - return []; - } - return prev.rssiBuffer; - - }, - - processPData: function(newData, oldData) { - 'use strict'; - var output = {}; - var wa = []; - if (newData === null || newData.data === null) { - return {}; - } - - for (var key in newData.data) { - - if (newData.data.hasOwnProperty(key)) { - - if (Object.keys(oldData).indexOf(key) !== -1) { - wa = oldData[key]; - } - - if (wa.length === 99) { - wa = wa.slice(1); - } - - wa.push(newData.data[key]); - - output[key] = wa; - } - } - - return output; - }, processRSSIData: function(rssi, oldBuffer) { - 'use strict'; - if (typeof oldBuffer === 'undefined' || oldBuffer === null) { - return []; - } - var wa = oldBuffer; - - if (wa.length === 10) { - wa = wa.slice(1); - } - - wa.push(rssi); - - return wa; - }, doScan: function(mode) { - 'use strict'; - app.mode = mode; - $('#ripple').show(); - if (mode !== 2) { - $('#tbody').empty(); - } - - ble.startScan([], app.foundDevice.bind(this), function(e) { - console.error(e); - }); - - var _t = [5000, 60000, 200][mode]; - - setTimeout(ble.stopScan, _t, app.scanComplete, function() { - console.log('stopScan failed'); - $('#ripple').hide(); - }); - - }, populateObject: function(source, dest) { - var rObj = dest; - for (var item in source) { - if (source.hasOwnProperty(item)) { - rObj[item] = source[item]; - } - } - - return rObj; - }, - /** - * - * @param device - * @param device.advertising - * @param device.rssi - * @param device.id - */ - - foundDevice: function(device) { - var rssiBuffer; - var oldRSSIBuffer; - var newPData; - var oldPdata; - var parsed; - var hexBuffer; - var advertBuffer; - var newTR; - var newId = 'd-' + device.id.replace(/:/g, '').split('-')[0]; - var _device = app.foundDevices[newId] || {}; - var $newID; - var otherData; - - _device = app.populateObject(device, _device); - // _device.pData = {}; - - otherData = null; - this.list[newId] = _device.id; - - if (_device.hasOwnProperty('advertising')) { - - advertBuffer = app.arrayBufferToIntArray(_device.advertising); - - hexBuffer = app.makeHexBuffer(advertBuffer); - - parsed = app.parseAdvertisingData(advertBuffer); - - if (parsed.hasOwnProperty('9')) { - - var name = app.makeChars(parsed['9']); - - _device.name = name.join(''); - console.log('Name: ', name.join('')); - - } - - if (parsed.hasOwnProperty('255')) { - - otherData = app.handle255(parsed['255']); - console.log(otherData); - _device.otherData = otherData; - } - _device.advertBuffer = advertBuffer; - _device.hexBuffer = hexBuffer; - _device.parsed = parsed; - } - - // OldPdata = app.extractPData(app.log[newId]); - oldPdata = app.extractPData(_device); - - newPData = app.processPData(otherData, oldPdata); - - // OldRSSIBuffer = app.extractRSSIBuffer(app.log[newId]); - oldRSSIBuffer = app.extractRSSIBuffer(_device); - rssiBuffer = app.processRSSIData(_device.rssi, oldRSSIBuffer); - - _device.pData = newPData; - _device.rssiBuffer = rssiBuffer; - - newTR = app.buildNewDeviceResultPanel(_device); - - $newID = $('div#' + newId); - if ($newID.length > 0) { - $newID.replaceWith(newTR); - } else { - $('#scanResults').append(newTR); - } - - app.log[newId] = _device; - app.foundDevices[newId] = _device; - - console.log(JSON.stringify(_device)); - - }, scanComplete: function() { - console.log('Scan complete'); - - if (app.mode === 1) { - app.saveLog(); - $('#ripple').hide(); - } - - if (app.mode === 2) { - if (!app.stop) { - setTimeout(function() { - app.doScan(2); - }.bind(this), 200); - } else { - app.saveLog(); - $('#ripple').hide(); - } - - } - - }, writeFile: function(fileEntry, dataObj) { - // Create a FileWriter object for our FileEntry (log.txt). - fileEntry.createWriter(function(fileWriter) { - - fileWriter.onwriteend = function() { - console.log('Successful file write...'); - // ReadFile(fileEntry); - }; - - fileWriter.onerror = function(e) { - console.error('Failed file write: ' + e.toString()); - }; - - // If data object is not passed in, - // create a new Blob instead. - if (!dataObj) { - dataObj = new Blob(['some file data'], {type: 'text/plain'}); - } - - fileWriter.write(dataObj); - }); - }, saveLog: function() { - 'use strict'; - var dt = new Date().toISOString().replace(/:|-/g, '').replace(/(\.\w+)/g, - ''); - var payload = JSON.stringify(app.log); - var filename = 'sensortoy-' + dt + '.json'; - - // Var dataObj = new Blob(payload, { type: 'text/plain' }); - window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) { - - console.log('file system open: ' + fs.name); - fs.root.getFile(filename, - {create: true, exclusive: false}, - function(fileEntry) { - - console.log('fileEntry is file?' + fileEntry.isFile.toString()); - // FileEntry.name == 'someFile.txt' - // fileEntry.fullPath == '/someFile.txt' - console.log('Path: ', fileEntry.fullPath); - app.writeFile(fileEntry, payload); - - app.log = []; - - }, - app.onError); - - }, app.onError); - }, forceStop: function() { - 'use strict'; - app.stop = true; - $('#scan').show(); - $('#stop').hide(); - }, - - // Bind Event Listeners - // - // Bind any events that are required on startup. Common events are: - // 'load', 'deviceready', 'offline', and 'online'. - bindEvents: function() { - var self = this; - document.addEventListener('deviceready', this.onDeviceReady, false); - $('#scan').on('click', function() { - 'use strict'; - this.stop = false; - this.doScan(2); - $('#scan').hide(); - $('#stop').show(); - }.bind(this)); - - $('#stop').on('click', function() { - 'use strict'; - app.forceStop(); - - }.bind(this)); - - $('#longScan').on('click', function() { - 'use strict'; - this.doScan(1); - }.bind(this)); - - $('#scanResults').on('click', 'div.mui-panel.deviceRow', function() { - 'use strict'; - var tID = $(this).context.id; - var id = self.list[tID]; - - console.log(tID, id); - - app.forceStop(); - self.connect(id); - }); - - }, addTab: function(tID) { - var appTabs = $('#app-tabs'); - var panes = $('#tab-panes'); - - var paneID = 'pane-' + tID; - - var _device = app.foundDevices[tID]; - var _name = _device.name || _device.id; - - console.log('Found:', _device); - - $('
', {class: 'mui-tabs__pane', id: paneID}).appendTo(panes); - - var li = $('
  • ').append($('', - {'data-mui-toggle': 'tab', 'data-mui-controls': paneID, text: _name})); - - appTabs.append(li); - - return paneID; - - }, - - // Deviceready Event Handler - // - // The scope of 'this' is the event. In order to call the 'receivedEvent' - // function, we must explicitly call 'app.receivedEvent(...);' - onDeviceReady: function() { - - }, - - doAnimate: function() { - for (var item in app.activeServices) { - if (app.activeServices.hasOwnProperty(item)) { - var activeService = app.activeServices[item]; - for (var t = 0; t < activeService.length; t++) { - activeService[t].animateGraph(); - } - } - } - window.requestAnimFrame(app.doAnimate.bind(this)); - }, connect: function(deviceId) { - - $('#results').slideUp(); - console.log('Connect to ', deviceId); - - var tID = 'd-' + deviceId.replace(/:/g, '').split('-')[0]; - - /** - * - * @param a - * @param a.services - */ - var onConnect = function(a) { - var services = []; - - services = a.services; - - console.log('Searching services for ', tID); - var usedServices = []; - - var target = app.addTab(tID); - - var _params = { - deviceID: deviceId, target: target - }; - - for (var t = 0; t < services.length; t++) { - - var ident = services[t].toUpperCase(); - - var SERVICE = capabilityManager.discover(ident); - - if (SERVICE !== null) { - - var newService = new SERVICE(_params); - newService.startService(); - usedServices.push(newService); - } else { - console.error('Unknown service: ', ident); - } - - } - - app.activeServices[tID] = usedServices; - - mui.tabs.activate(target); - window.requestAnimFrame(app.doAnimate.bind(this)); - }; - - if (!app.activeServices.hasOwnProperty(tID)) { - - ble.connect(deviceId, onConnect, function(e) { - 'use strict'; - console.log(e); - console.error(e); - - }); - - } - - }, onError: function(reason) { - console.error('ERROR: ' + reason); // Real apps should use notification.alert - } -}; - -window.requestAnimFrame = (function() { - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - function(callback) { - window.setTimeout(callback, 1000 / 60); - }; -})(); - -app.initialize();