detectSteps method
Detects individual steps in accelerometer data using peak detection.
Implements a step detection algorithm optimized for walking analysis:
- Applies smoothing using a moving average window
- Detects peaks in the smoothed acceleration data
- Validates peaks against threshold and timing constraints
- Prevents false positives with minimum step interval
The algorithm uses state tracking to avoid detecting multiple peaks for the same step and enforces a minimum interval between consecutive steps.
Returns a list of Step objects containing the timestamp indices of detected steps.
Implementation
List<Step> detectSteps({
required List<double> acc,
required double threshold,
int smoothingWindow = 10,
int minStepIntervalMs = 300,
}) {
// Apply smoothing using moving average window
List<double> smoothedAcc = List<double>.filled(acc.length, 0.0);
for (int i = 0; i < acc.length; i++) {
double sum = 0.0;
int count = 0;
// Calculate moving average within window bounds
for (
int j = (i - smoothingWindow ~/ 2).clamp(0, acc.length - 1);
j <= (i + smoothingWindow ~/ 2).clamp(0, acc.length - 1);
j++
) {
sum += acc[j];
count++;
}
smoothedAcc[i] = sum / count;
}
// Calculate minimum interval between steps in samples
final minStepIntervalSamples =
(minStepIntervalMs / (1000 / config.accelerometerSamplingRate)).round();
int lastStepIndex = -minStepIntervalSamples;
List<Step> steps = [];
bool stepDetected = false; // State tracking to prevent duplicate detection
// Scan for peaks that indicate steps
for (int i = 1; i < smoothedAcc.length - 1; i++) {
// Check if current point is a local maximum
bool isPeak =
smoothedAcc[i] > smoothedAcc[i - 1] &&
smoothedAcc[i] > smoothedAcc[i + 1];
// Validate peak against threshold and timing constraints
if (isPeak && smoothedAcc[i] > threshold && !stepDetected) {
// Ensure minimum interval since last detected step
if ((i - lastStepIndex) >= minStepIntervalSamples) {
steps.add(Step(i));
lastStepIndex = i;
stepDetected = true; // Set flag to prevent duplicate detection
}
} else if (smoothedAcc[i] < threshold) {
stepDetected = false; // Reset flag when signal drops below threshold
}
}
return steps;
}