///|
/// Feature extraction for motion signals and benchmark diagnostics.
pub struct SignalPeak2 {
index : Int
value : Double
prominence : Double
width : Int
} derive(Debug)
///|
pub fn SignalPeak2::index(self : SignalPeak2) -> Int {
self.index
}
///|
pub fn SignalPeak2::value(self : SignalPeak2) -> Double {
self.value
}
///|
pub fn SignalPeak2::prominence(self : SignalPeak2) -> Double {
self.prominence
}
///|
pub fn SignalPeak2::width(self : SignalPeak2) -> Int {
self.width
}
///|
pub fn moving_average2(values : Array[Double], radius : Int) -> Array[Double] {
let result : Array[Double] = []
let window = radius.max(0)
for index in 0.. Array[Double] {
if values.length() == 0 {
return []
}
let result : Array[Double] = [values[0]]
let alpha = clamp01(factor)
for index in 1.. Array[Double] {
let result : Array[Double] = []
let window = radius.max(0)
for index in 0.. (Array[Double], Array[Double]) {
let lower : Array[Double] = []
let upper : Array[Double] = []
let window = radius.max(0)
for index in 0.. Array[SignalPeak2] {
let result : Array[SignalPeak2] = []
if values.length() < 3 {
return result
}
for index in 1..<(values.length() - 1) {
if values[index] >= threshold &&
values[index] >= values[index - 1] &&
values[index] >= values[index + 1] {
let allowed = if result.length() == 0 {
true
} else {
index - result[result.length() - 1].index >= minimum_distance.max(1)
}
if allowed {
let prominence = values[index] -
values[index - 1].min(values[index + 1])
result.push({ index, value: values[index], prominence, width: 1 })
} else if values[index] > result[result.length() - 1].value {
result[result.length() - 1] = {
index,
value: values[index],
prominence: values[index] - values[index - 1].min(values[index + 1]),
width: 1,
}
}
}
}
result
}
///|
pub fn signal_rms2(values : Array[Double]) -> Double {
if values.length() == 0 {
return 0.0
}
let mut sum = 0.0
for value in values {
sum = sum + value * value
}
@math.pow(sum / values.length().to_double(), 0.5)
}
///|
pub fn signal_mean2(values : Array[Double]) -> Double {
if values.length() == 0 {
return 0.0
}
values.fold(init=0.0, fn(sum, value) { sum + value }) /
values.length().to_double()
}
///|
pub fn signal_variance2(values : Array[Double]) -> Double {
if values.length() == 0 {
return 0.0
}
let mean = signal_mean2(values)
values.fold(init=0.0, fn(sum, value) {
let delta = value - mean
sum + delta * delta
}) /
values.length().to_double()
}
///|
pub fn signal_autocorrelation2(values : Array[Double], lag : Int) -> Double {
let offset = lag.max(0)
if offset >= values.length() {
return 0.0
}
let mean = signal_mean2(values)
let mut numerator = 0.0
let mut denominator = 0.0
for index in 0..<(values.length() - offset) {
numerator = numerator +
(values[index] - mean) * (values[index + offset] - mean)
}
for value in values {
let delta = value - mean
denominator = denominator + delta * delta
}
if denominator == 0.0 {
0.0
} else {
numerator / denominator
}
}
///|
pub fn signal_normalize2(values : Array[Double]) -> Array[Double] {
let mean = signal_mean2(values)
let deviation = @math.pow(signal_variance2(values), 0.5)
let result : Array[Double] = []
for value in values {
result.push(if deviation == 0.0 { 0.0 } else { (value - mean) / deviation })
}
result
}
///|
pub fn signal_residual2(
values : Array[Double],
smooth_radius : Int,
) -> Array[Double] {
let smooth = moving_average2(values, smooth_radius)
let result : Array[Double] = []
for index in 0.. Array[Double] {
let result : Array[Double] = []
let dt = 1.0 / frame_rate.max(0.001)
for index in 0.. Array[Double] {
let result : Array[Double] = [initial]
let dt = 1.0 / frame_rate.max(0.001)
for index in 1..