Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SignalFusionKit

A reference pattern for fusing multiple watchOS sensor signals — HealthKit vitals, CoreMotion accelerometer data, optional CoreLocation speed — into a single risk classification, with a debounce/cooldown primitive for the notification side.

Extracted and generalized from the anomaly-detection pipeline built for Ember, a biometric dead man's switch app. This package shares the architecture, not Ember's production configuration — see What this is / isn't below.

Why

Most watchOS "something bad might be happening" features (fall detection, crash detection, panic triggers) end up solving the same three problems:

  1. Combine several independent, asynchronously-arriving signals into one decision, without letting a single ambiguous signal drown out a single unambiguous one (e.g. a confirmed fall shouldn't be diluted by averaging it against calm vitals).
  2. Detect a sudden motion anomaly from raw accelerometer data using both a "sustained" check (filters noise) and a "sharp delta" check (catches instantaneous impacts a duration gate would smooth over).
  3. Debounce the result so the user isn't re-alerted every few seconds while the underlying condition persists.

SignalFusionKit is those three pieces, written as small, pure, unit-tested types with zero dependency on HealthKit/CoreMotion in the parts that matter — plus one thin, documented (but untested) adapter showing how to wire them to real sensors.

Install

Swift Package Manager:

.package(url: "https://github.com/izetg/SignalFusionKit.git", from: "1.0.0")

Usage

import SignalFusionKit

// 1. Combine signals into a risk level.
let snapshot = SignalSnapshot(
    oxygenSaturation: 93,
    heartRateVariability: 40,
    fallDetected: false,
    motionAnomalyDetected: false
)
let assessment = RiskEngine.evaluate(snapshot, config: .example)
// assessment.level -> .high (SpO2 below the example "low" threshold)

// 2. Feed raw accelerometer magnitude samples to detect motion anomalies.
let detector = MotionAnomalyDetector(config: .example)
let anomalyDetected = detector.ingest(magnitudeG: 4.2, at: Date())

// 3. Debounce repeated triggers.
let cooldown = CooldownGate(window: 60) // seconds
if cooldown.attempt() {
    // safe to alert / act
}

See WatchKitAdapter.swift for a worked (but untested — see below) example wiring this to real HealthKit + CoreMotion callbacks in a watchOS app.

What this is / isn't

Is: a reusable architecture for combining multi-sensor watchOS signals into a risk decision, with the interesting logic (RiskEngine, MotionAnomalyDetector, CooldownGate) fully unit-tested and free of Apple framework dependencies.

Isn't: Ember's production configuration. The threshold values in RiskEngineConfig.example and MotionAnomalyConfig.example are round, illustrative numbers picked for readability in tests and docs — not the tuned, validated values Ember actually ships with. Real thresholds need real-world data collection, false-positive/negative tradeoffs specific to your use case, and ideally domain-expert review. Treat the example configs as the seam where your own calibration plugs in, not as a recommendation.

Isn't tested end-to-end on a Watch. RiskEngine, MotionAnomalyDetector, and CooldownGate are pure Swift and covered by swift test. WatchKitAdapter is real HealthKit/CoreMotion glue that needs Xcode and a device/simulator to exercise — verify it there before relying on it.

Testing

swift test

Runs on any platform with the Swift toolchain — the tested types don't import HealthKit or CoreMotion.

License

MIT — see LICENSE.

About

A reference pattern for fusing watchOS HealthKit + CoreMotion signals into a risk classification. Extracted and generalized from Ember's anomaly-detection architecture.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages