Skip to main content

Activity Analysis

Once an activity has been recorded and processed, you can run an analysis to extract meaningful metrics—provided a built-in analysis module is available for that activity.

Available Analysis Types

The SDK currently supports 12 analysis types:

  • Overground walking: Straight walking, no turns
  • Treadmill walking: Walking on a treadmill
  • Overground running: Straight running, no turns
  • Treadmill running: Running on a treadmill
  • Counter movement jump: Single or double leg, 1+ repetitions
  • Drop vertical jump: Single or double leg, 1+ repetitions
  • Hop: Single, double, or triple (crossover)
  • Squat: Single or double leg, 1+ repetitions
  • 505 test: Agility test involving a 180° turn
  • Cut: Change of direction (eg, 45° and 90° cuts)
  • Range of motion (ROM) assessment: ROM measured throughout the trial (activity-independent)
  • Sit-to-stand transfer: 1+ repetitions

Starting Analysis

// Ensure activity is ready
let status = try await service.activityStatus(for: activity)

guard case .ready = status else {
print("Activity not ready for analysis")
return
}

// Start analysis
let task = try await service.startAnalysis(
.counterMovementJump,
for: activity,
in: session
)

print("Analysis task started: \(task.id)")

Monitoring Analysis Progress

Analysis should take less than 30 seconds to complete. Poll the status:

var analysisStatus = try await service.analysisStatus(for: task)

while case .processing = analysisStatus {
print("Analysis in progress...")
try await Task.sleep(nanoseconds: 10_000_000_000) // 10 seconds
analysisStatus = try await service.analysisStatus(for: task)
}

switch analysisStatus {
case .completed:
print("Analysis complete!")
case .failed:
print("Analysis failed")
default:
break
}

Downloading Results

Once analysis is complete, download the results:

if case .completed = analysisStatus {
let results = await service.analysisData(ofType: [.metrics], for: activity)
if let metricsEntry = results.first(where: { $0.type == .metrics }),
let json = try? JSONSerialization.jsonObject(with: metricsEntry.data) as? [String: Any] {
// json contains analysis_title, analysis_description, metrics dictionary, etc.
print("Metrics:", json)
}
}

Result Types

The analysis result contains:

  • Metrics - JSON with key metrics and their descriptions
  • Report - PDF report of the analysis
  • Data - Zip with CSV files containing joint angles and positions, angular velocities and speeds, and extended metrics list

Complete Example

Here's a complete workflow from recording to analysis:

// Record
let activity = try await service.startRecording(activityNamed: "cmj", in: session)
// ... subject performs jump ...
try await service.stopRecording(session)

// Wait for processing
var activityStatus = try await service.activityStatus(for: activity)
while case .processing = activityStatus {
try await Task.sleep(nanoseconds: 10_000_000_000)
activityStatus = try await service.activityStatus(for: activity)
}

// Start analysis
guard case .ready = activityStatus else {
print("Activity failed processing")
return
}

let task = try await service.startAnalysis(.counterMovementJump, for: activity, in: session)

// Wait for analysis
var analysisStatus = try await service.analysisStatus(for: task)
while case .processing = analysisStatus {
try await Task.sleep(nanoseconds: 10_000_000_000)
analysisStatus = try await service.analysisStatus(for: task)
}

// Download results
if case .completed = analysisStatus {
let results = await service.analysisData(ofType: [.metrics], for: activity)
if let metricsEntry = results.first(where: { $0.type == .metrics }),
let json = try? JSONSerialization.jsonObject(with: metricsEntry.data) as? [String: Any],
let metrics = json["metrics"] as? [String: [String: Any]] {
for (key, metric) in metrics {
print("\(key):", metric)
}
}
}

Error Handling

Always handle potential errors during analysis:

do {
let task = try await service.startAnalysis(.counterMovementJump, for: activity, in: session)
// Monitor and download results...
} catch {
print("Analysis error: \(error)")
// Handle error appropriately
}