///|
/// 3D Vector for sensor data
pub(all) struct Vec3 {
x : Double
y : Double
z : Double
} derive(Show, Eq)
///|
/// Create a new 3D vector
pub fn Vec3::new(x : Double, y : Double, z : Double) -> Vec3 {
{ x, y, z }
}
///|
/// Zero vector
pub fn Vec3::zero() -> Vec3 {
{ x: 0.0, y: 0.0, z: 0.0 }
}
///|
/// Vector magnitude
pub fn Vec3::magnitude(self : Vec3) -> Double {
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
}
///|
/// Normalize vector
pub fn Vec3::normalize(self : Vec3) -> Vec3 {
let mag = self.magnitude()
if mag == 0.0 {
Vec3::zero()
} else {
{ x: self.x / mag, y: self.y / mag, z: self.z / mag }
}
}
///|
/// Vector addition
pub fn Vec3::add(self : Vec3, other : Vec3) -> Vec3 {
{ x: self.x + other.x, y: self.y + other.y, z: self.z + other.z }
}
///|
/// Vector subtraction
pub fn Vec3::sub(self : Vec3, other : Vec3) -> Vec3 {
{ x: self.x - other.x, y: self.y - other.y, z: self.z - other.z }
}
///|
/// Scalar multiplication
pub fn Vec3::scale(self : Vec3, scalar : Double) -> Vec3 {
{ x: self.x * scalar, y: self.y * scalar, z: self.z * scalar }
}
///|
/// Dot product
pub fn Vec3::dot(self : Vec3, other : Vec3) -> Double {
self.x * other.x + self.y * other.y + self.z * other.z
}
///|
/// Cross product
pub fn Vec3::cross(self : Vec3, other : Vec3) -> Vec3 {
{
x: self.y * other.z - self.z * other.y,
y: self.z * other.x - self.x * other.z,
z: self.x * other.y - self.y * other.x,
}
}
///|
/// Quaternion for 3D rotation
pub(all) struct Quaternion {
w : Double
x : Double
y : Double
z : Double
} derive(Show, Eq)
///|
/// Create identity quaternion
pub fn Quaternion::identity() -> Quaternion {
{ w: 1.0, x: 0.0, y: 0.0, z: 0.0 }
}
///|
/// Create quaternion from axis and angle (in radians)
pub fn Quaternion::from_axis_angle(axis : Vec3, angle : Double) -> Quaternion {
let half_angle = angle / 2.0
let s = @math.sin(half_angle)
let normalized = axis.normalize()
{
w: @math.cos(half_angle),
x: normalized.x * s,
y: normalized.y * s,
z: normalized.z * s,
}
}
///|
/// Quaternion multiplication
pub fn Quaternion::multiply(
self : Quaternion,
other : Quaternion,
) -> Quaternion {
{
w: self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z,
x: self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
y: self.w * other.y - self.x * other.z + self.y * other.w + self.z * other.x,
z: self.w * other.z + self.x * other.y - self.y * other.x + self.z * other.w,
}
}
///|
/// Normalize quaternion
pub fn Quaternion::normalize(self : Quaternion) -> Quaternion {
let mag = (self.w * self.w +
self.x * self.x +
self.y * self.y +
self.z * self.z).sqrt()
if mag == 0.0 {
Quaternion::identity()
} else {
{ w: self.w / mag, x: self.x / mag, y: self.y / mag, z: self.z / mag }
}
}
///|
/// Convert quaternion to Euler angles (roll, pitch, yaw in radians)
pub fn Quaternion::to_euler(self : Quaternion) -> (Double, Double, Double) {
// Roll (x-axis rotation)
let sinr_cosp = 2.0 * (self.w * self.x + self.y * self.z)
let cosr_cosp = 1.0 - 2.0 * (self.x * self.x + self.y * self.y)
let roll = @math.atan2(sinr_cosp, cosr_cosp)
// Pitch (y-axis rotation)
let sinp = 2.0 * (self.w * self.y - self.z * self.x)
let pitch = if sinp.abs() >= 1.0 {
// Use 90 degrees if out of range, with sign of sinp
if sinp < 0.0 {
-@math.PI / 2.0
} else {
@math.PI / 2.0
}
} else {
@math.asin(sinp)
}
// Yaw (z-axis rotation)
let siny_cosp = 2.0 * (self.w * self.z + self.x * self.y)
let cosy_cosp = 1.0 - 2.0 * (self.y * self.y + self.z * self.z)
let yaw = @math.atan2(siny_cosp, cosy_cosp)
(roll, pitch, yaw)
}
///|
/// Accelerometer reading (m/s²)
pub(all) struct AccelReading {
data : Vec3
timestamp : Int64
} derive(Show, Eq)
///|
/// Gyroscope reading (rad/s)
pub(all) struct GyroReading {
data : Vec3
timestamp : Int64
} derive(Show, Eq)
///|
/// Magnetometer reading (μT - microtesla)
pub(all) struct MagReading {
data : Vec3
timestamp : Int64
} derive(Show, Eq)
///|
/// Motion state combining all sensor data
pub(all) struct MotionState {
acceleration : Vec3
angular_velocity : Vec3
magnetic_field : Vec3
orientation : Quaternion
timestamp : Int64
} derive(Show)
///|
/// Create initial motion state
pub fn MotionState::new() -> MotionState {
{
acceleration: Vec3::zero(),
angular_velocity: Vec3::zero(),
magnetic_field: Vec3::zero(),
orientation: Quaternion::identity(),
timestamp: 0L,
}
}
///|
/// Gesture types for motion detection
pub enum Gesture {
Stationary
Shaking
Tilting(Double, Double) // pitch, roll
Rotating(Double) // angular velocity magnitude
FreeFall
Impact(Double) // impact force
} derive(Show, Eq)
///|
/// Sensor configuration
pub(all) struct SensorConfig {
accel_range : Double // ±g
gyro_range : Double // ±rad/s
mag_range : Double // ±μT
sample_rate : Int // Hz
} derive(Show, Eq)
///|
/// Default sensor configuration
pub fn SensorConfig::default() -> SensorConfig {
{
accel_range: 16.0, // ±16g
gyro_range: 34.9, // ±2000 deg/s = ±34.9 rad/s
mag_range: 4800.0, // ±4800μT
sample_rate: 100,
} // 100Hz
}