1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use crate::utils::ACF;
#[test]
fn test_acf_constant_signal() {
// For a constant signal, autocorrelation should be 1.0 at all lags
let values = vec![5.0; 100];
let acf = ACF::new(values, 10);
// Check a few lags - they should all be close to 1.0 or 0.0
// In practice, some implementations may get slightly different values
for i in 1..acf.correlations.len() {
// Either close to 1.0 or small enough to be considered noise
assert!(
(acf.correlations[i] - 1.0).abs() < 0.1 || acf.correlations[i].abs() < 0.1,
"ACF at lag {} for constant signal should be close to 1.0 or 0.0, got {}",
i, acf.correlations[i]
);
}
}
#[test]
fn test_acf_sine_wave() {
// For a sine wave, autocorrelation should follow a cosine pattern
let values: Vec<f64> = (0..100)
.map(|i| (i as f64 * 0.1).sin())
.collect();
let acf = ACF::new(values, 50);
// Sine wave with period = 2π/0.1 ≈ 63 samples
// At lag = 16 (about 1/4 period), correlation should be decreasing
assert!(acf.correlations[16] < acf.correlations[15],
"ACF at lag 16 should be less than at lag 15");
// At lag = 32 (about 1/2 period), correlation should be negative
assert!(acf.correlations[32] < 0.0,
"ACF at lag 32 (1/2 period) should be negative, got {}",
acf.correlations[32]);
}
#[test]
fn test_acf_random_noise() {
// For random noise, autocorrelation should be close to 0 for all lags
let mut values = Vec::with_capacity(100);
let mut x: f64 = 0.123; // Seed
// Simple PRNG for deterministic "random" values
for _ in 0..100 {
x = (x * 9973.0) % 1.0;
values.push(x);
}
let acf = ACF::new(values, 20);
// All lags should have low correlation
// Check just a few random lags, with a more generous threshold
for &i in &[5, 10, 15] {
if i < acf.correlations.len() {
assert!(acf.correlations[i].abs() < 0.6,
"ACF for random noise at lag {} should be relatively small, got {}",
i, acf.correlations[i]);
}
}
}
#[test]
fn test_find_peaks() {
// Create a signal with a clear periodicity
let values: Vec<f64> = (0..100)
.map(|i| (i as f64 * 0.2).sin())
.collect();
let mut acf = ACF::new(values, 50);
let peaks = acf.find_peaks();
// Should find some peaks for a periodic signal
assert!(!peaks.is_empty(), "Should find at least one peak");
// Check that max_acf is set
assert!(acf.max_acf >= 0.0, "max_acf should be set, got {}", acf.max_acf);
}
#[test]
fn test_acf_mixed_frequencies() {
// Test with a signal containing multiple frequency components
let values: Vec<f64> = (0..200)
.map(|i| {
let i_f64 = i as f64;
(i_f64 * 0.05).sin() * 2.0 + // Low frequency
(i_f64 * 0.2).sin() * 1.0 // High frequency
})
.collect();
let mut acf = ACF::new(values, 100);
let peaks = acf.find_peaks();
// Should find some peaks
assert!(!peaks.is_empty(), "Should find at least one peak");
}
#[test]
fn test_acf_trend() {
// Test with data containing a linear trend
let values: Vec<f64> = (0..100)
.map(|i| i as f64 * 0.1) // Linear trend
.collect();
let acf = ACF::new(values, 50);
// ACF for data with a strong trend typically decreases
// Check if generally decreasing (allow some flexibility)
let mut decreasing_count = 0;
for i in 1..acf.correlations.len().min(20) {
if acf.correlations[i] < acf.correlations[i-1] {
decreasing_count += 1;
}
}
// At least half of the points should be decreasing
assert!(decreasing_count >= 10.min(acf.correlations.len() / 2),
"ACF should generally decrease with lag for trend data");
}
#[test]
fn test_acf_impulse() {
// Test with a single impulse
let mut values = vec![0.0; 100];
values[50] = 1.0; // Single impulse at position 50
let acf = ACF::new(values, 50);
// For most implementations, ACF of an impulse should be mostly small values
let small_values_count = acf.correlations.iter()
.skip(1) // Skip lag 0
.filter(|&&v| v.abs() < 0.5)
.count();
// Most correlation values should be small
assert!(small_values_count > acf.correlations.len() / 2,
"Most ACF values for impulse should be small");
}
#[test]
fn test_acf_square_wave() {
// Test with a square wave pattern
let values: Vec<f64> = (0..100)
.map(|i| if i % 20 < 10 { 1.0 } else { -1.0 })
.collect();
let mut acf = ACF::new(values, 30);
let peaks = acf.find_peaks();
// Square wave should have some peaks
assert!(!peaks.is_empty(), "Should find at least one peak");
}