Hello,
I am trying to implement an algorithm that uses sensor data, but I am having trouble accessing the sensor data and storing it in a data array. For example, here is the basic code I'm using to try to access Quaternion and store it in an array:
import UIKit
import CoreMotion
import CoreML
import UserNotifications
protocol Numeric {
var asDouble: Double { get }
init(_: Double)
}
extension Int: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Float: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Double: Numeric {var asDouble: Double { get {return Double(self)}}}
extension CGFloat: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Array where Element: Numeric {
var mean : Element { get { return Element(self.reduce(0, {$0.asDouble + $1.asDouble}) / Double(self.count))}}
var sd : Element { get {
let sss = self.reduce((0.0, 0.0)){ return ($0.0 + $1.asDouble, $0.1 + ($1.asDouble * $1.asDouble))}
let n = Double(self.count)
return Element(sqrt(sss.1/n - (sss.0/n * sss.0/n)))
}}
}
extension Array where Element: Hashable {
func allEqual(to value: Element) -> Bool {
let set = Set(self)
return (set.count == 1 && set.first == value)
}
}
class ViewController: UIViewController {
@IBOutlet weak var quaternionX: UILabel!
@IBOutlet weak var quaternionY: UILabel!
@IBOutlet weak var quaternionZ: UILabel!
@IBOutlet weak var quaternionW: UILabel!
@IBOutlet weak var predicted_activity: UILabel!
struct ModelConstants {
static let predictionWindowSize = 50
static let sensorsUpdateInterval = 1.0 / 50.0
static let stateInLength = 400
}
var pred_action = "Nothing yet"
let activityClassificationModel = TC_RF()
var currentIndexInPredictionWindow = 0
var quaternionDataX = Array(repeating: Double(0), count: ModelConstants.predictionWindowSize)
var quaternionDataY = Array(repeating: Double(0), count: ModelConstants.predictionWindowSize)
var quaternionDataZ = Array(repeating: Double(0), count: ModelConstants.predictionWindowSize)
var quaternionDataW = Array(repeating: Double(0), count: ModelConstants.predictionWindowSize)
var quaternionDataX_mean = Double(0)
var quaternionDataY_mean = Double(0)
var quaternionDataZ_mean = Double(0)
var quaternionDataW_mean = Double(0)
var quaternionDataX_std = Double(0)
var quaternionDataY_std = Double(0)
var quaternionDataZ_std = Double(0)
var quaternionDataW_std = Double(0)
var quaternionDataX_min = Double(0)
var quaternionDataY_min = Double(0)
var quaternionDataZ_min = Double(0)
var quaternionDataW_min = Double(0)
var quaternionDataX_max = Double(0)
var quaternionDataY_max = Double(0)
var quaternionDataZ_max = Double(0)
var quaternionDataW_max = Double(0)
let motionManager = CMMotionManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
notif_log.delegate = self
notif_log.dataSource = self
UNUserNotificationCenter.current().delegate = self
MyQuaternion()
self.scheduleNotifications(content_body: self.pred_action)
}
func MyQuaternion(){
guard motionManager.isDeviceMotionAvailable else {
print("Device Motion is not available on the device")
return }
motionManager.deviceMotionUpdateInterval = TimeInterval(ModelConstants.sensorsUpdateInterval)
motionManager.startDeviceMotionUpdates(to: OperationQueue.current!){ (quaternionData, error) in
if let quaternionData = quaternionData {
self.quaternionX.text = "\(quaternionData.attitude.quaternion.x)"
self.quaternionY.text = "\(quaternionData.attitude.quaternion.y)"
self.quaternionZ.text = "\(quaternionData.attitude.quaternion.z)"
self.quaternionW.text = "\(quaternionData.attitude.quaternion.w)"
// Add the current data sample to the data array
self.addQuaternionSampleToDataArray(deviceMotionSample: quaternionData.attitude.quaternion)
}
}
}
func addQuaternionSampleToDataArray (deviceMotionSample: CMQuaternion) {
// Add the current gyroscope reading to the data array
quaternionDataX[currentIndexInPredictionWindow] = deviceMotionSample.x
quaternionDataY[currentIndexInPredictionWindow] = deviceMotionSample.y
quaternionDataZ[currentIndexInPredictionWindow] = deviceMotionSample.z
quaternionDataW[currentIndexInPredictionWindow] = deviceMotionSample.w
// Update the index in the prediction window data array
currentIndexInPredictionWindow += 1
// If the data array is full, call the prediction method to get a new model prediction.
// We assume here for simplicity that the Gyro data was added to the data arrays as well.
if (currentIndexInPredictionWindow == ModelConstants.predictionWindowSize) {
quaternionDataX_mean = Double(quaternionDataX.mean)
quaternionDataY_mean = Double(quaternionDataY.mean)
quaternionDataZ_mean = Double(quaternionDataZ.mean)
quaternionDataW_mean = Double(quaternionDataW.mean)
quaternionDataX_std = Double(quaternionDataX.sd)
quaternionDataY_std = Double(quaternionDataY.sd)
quaternionDataZ_std = Double(quaternionDataZ.sd)
quaternionDataW_std = Double(quaternionDataW.sd)
quaternionDataX_min = Double(quaternionDataX.min() ?? 0)
quaternionDataY_min = Double(quaternionDataY.min() ?? 0)
quaternionDataZ_min = Double(quaternionDataZ.min() ?? 0)
quaternionDataW_min = Double(quaternionDataW.min() ?? 0)
quaternionDataX_max = Double(quaternionDataX.max() ?? 0)
quaternionDataY_max = Double(quaternionDataY.max() ?? 0)
quaternionDataZ_max = Double(quaternionDataZ.max() ?? 0)
quaternionDataW_max = Double(quaternionDataW.max() ?? 0)
if let predictedActivity = performModelPrediction() {
// Use the predicted activity here
// ...
switch predictedActivity {
case "0":
self.predicted_activity.text = "Eating"
self.pred_action = "Eating"
self.scheduleNotifications(content_body: self.pred_action)
case "1":
self.predicted_activity.text = "Eye rubbing light"
self.pred_action = "Eye rubbing light"
self.scheduleNotifications(content_body: self.pred_action)
default:
print("Have you done something ?")
}
//self.predicted_activity.setText(predictedActivity)
// Start a new prediction window
currentIndexInPredictionWindow = 0
}
}
}
I'm not sure exactly where it's going wrong. Any advice would be appeciated.