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
- Swift
- TypeScript
// 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)")
// Ensure activity is ready
const status = await service.activityStatus(activity);
if (status.type !== "ready") {
console.log("Activity not ready for analysis");
return;
}
// Start analysis
const task = await service.startAnalysis(
"counter_movement_jump",
activity,
session
);
console.log("Analysis task started:", task.taskId);
Monitoring Analysis Progress
Analysis should take less than 30 seconds to complete. Poll the status:
- Swift
- TypeScript
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
}
let analysisStatus = await service.analysisStatus(task);
while (analysisStatus.type === "processing") {
console.log("Analysis in progress...");
await new Promise(resolve => setTimeout(resolve, 10000));
analysisStatus = await service.analysisStatus(task);
}
if (analysisStatus.type === "completed") {
console.log("Analysis complete!");
} else if (analysisStatus.type === "failed") {
console.log("Analysis failed");
}
Downloading Results
Once analysis is complete, download the results:
- Swift
- TypeScript
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)
}
}
if (analysisStatus.type === "completed") {
const results = await service.analysisDataForActivity(activity, ["metrics"]);
const metricsEntry = results.find((r) => r.type === "metrics");
if (metricsEntry?.data) {
const result = JSON.parse(new TextDecoder().decode(metricsEntry.data));
// result contains biomechanical metrics
const jumpHeight = result.metrics?.["00_jump_height_COM"]?.value?.value;
const peakVelocity = result.metrics?.["04_peak_vertical_COM_speed_during_takeoff"]?.value?.value;
if (jumpHeight != null) console.log("Jump height:", jumpHeight, "cm");
if (peakVelocity != null) console.log("Peak velocity:", peakVelocity, "m/s");
}
}
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:
- Swift
- TypeScript
// 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)
}
}
}
// Record
const activity = await service.startRecording("cmj", session);
// ... subject performs jump ...
await service.stopRecording(session);
// Wait for processing
let activityStatus = await service.activityStatus(activity);
while (activityStatus.type === "processing" || activityStatus.type === "uploading") {
await new Promise(resolve => setTimeout(resolve, 10000));
activityStatus = await service.activityStatus(activity);
}
// Start analysis
if (activityStatus.type !== "ready") {
console.log("Activity failed processing");
return;
}
const task = await service.startAnalysis("counter_movement_jump", activity, session);
// Wait for analysis
let analysisStatus = await service.analysisStatus(task);
while (analysisStatus.type === "processing") {
await new Promise(resolve => setTimeout(resolve, 10000));
analysisStatus = await service.analysisStatus(task);
}
// Download results
if (analysisStatus.type === "completed") {
const results = await service.analysisDataForActivity(activity, ["metrics"]);
const metricsEntry = results.find((r) => r.type === "metrics");
if (metricsEntry?.data) {
const result = JSON.parse(new TextDecoder().decode(metricsEntry.data));
console.log("Analysis complete:", result.analysis_title);
for (const [key, metric] of Object.entries(result.metrics || {})) {
console.log(`${metric.label}:`, metric.value);
}
}
}
Error Handling
Always handle potential errors during analysis:
- Swift
- TypeScript
do {
let task = try await service.startAnalysis(.counterMovementJump, for: activity, in: session)
// Monitor and download results...
} catch {
print("Analysis error: \(error)")
// Handle error appropriately
}
try {
const task = await service.startAnalysis("counter_movement_jump", activity, session);
// Monitor and download results...
} catch (error) {
console.error("Analysis error:", error);
// Handle error appropriately
}