-
Notifications
You must be signed in to change notification settings - Fork 2
/
VectorRollingStatistics.cs
144 lines (124 loc) · 5 KB
/
VectorRollingStatistics.cs
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
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using UnityEngine;
namespace HoloToolkit.Unity
{
/// <summary>
/// Vector Statistics used in gaze stabilization.
/// </summary>
public class VectorRollingStatistics
{
/// <summary>
/// Current standard deviation of the positions of the vectors
/// </summary>
public float CurrentStandardDeviation;
/// <summary>
/// Difference to standardDeviation when the latest sample was added.
/// </summary>
public float StandardDeviationDeltaAfterLatestSample;
/// <summary>
/// How many standard deviations the latest sample was away.
/// </summary>
public float StandardDeviationsAwayOfLatestSample;
/// <summary>
/// The average position.
/// </summary>
public Vector3 Average;
/// <summary>
/// The number of samples in the current set (may be 0 - maxSamples)
/// </summary>
public float ActualSampleCount;
/// <summary>
/// Keeps track of the index into the sample list for the rolling average.
/// </summary>
private int currentSampleIndex;
/// <summary>
/// An array of samples for calculating standard deviation.
/// </summary>
private Vector3[] samples;
/// <summary>
/// The sum of all of the samples.
/// </summary>
private Vector3 cumulativeFrame;
/// <summary>
/// The sum of all of the samples squared.
/// </summary>
private Vector3 cumulativeFrameSquared;
/// <summary>
/// The total number of samples taken.
/// </summary>
private int cumulativeFrameSamples;
/// <summary>
/// The maximum number of samples to include in
/// the average and standard deviation calculations.
/// </summary>
private int maxSamples;
/// <summary>
/// Initialize the rolling stats.
/// </summary>
/// <param name="sampleCount"></param>
public void Init(int sampleCount)
{
maxSamples = sampleCount;
samples = new Vector3[sampleCount];
Reset();
}
/// <summary>
/// Resets the stats to zero.
/// </summary>
public void Reset()
{
currentSampleIndex = 0;
ActualSampleCount = 0;
cumulativeFrame = Vector3.zero;
cumulativeFrameSquared = Vector3.zero;
cumulativeFrameSamples = 0;
CurrentStandardDeviation = 0.0f;
StandardDeviationDeltaAfterLatestSample = 0.0f;
StandardDeviationsAwayOfLatestSample = 0.0f;
Average = Vector3.zero;
if (samples != null)
{
for (int index = 0; index < samples.Length; index++)
{
samples[index] = Vector3.zero;
}
}
}
/// <summary>
/// Adds a new sample to the sample list and updates the stats.
/// </summary>
/// <param name="value">The new sample to add</param>
public void AddSample(Vector3 value)
{
if (maxSamples == 0)
{
return;
}
// remove the old sample from our accumulation
Vector3 oldSample = samples[currentSampleIndex];
cumulativeFrame -= oldSample;
cumulativeFrameSquared -= (oldSample.Mul(oldSample));
// Add the new sample to the accumulation
samples[currentSampleIndex] = value;
cumulativeFrame += value;
cumulativeFrameSquared += value.Mul(value);
// Keep track of how many samples we have
cumulativeFrameSamples++;
ActualSampleCount = Mathf.Min(maxSamples, cumulativeFrameSamples);
// see how many standard deviations the current sample is from the previous average
Vector3 deltaFromAverage = (Average - value);
float oldStandardDeviation = CurrentStandardDeviation;
StandardDeviationsAwayOfLatestSample = oldStandardDeviation == 0 ? 0 : (deltaFromAverage / oldStandardDeviation).magnitude;
// And calculate new averages and standard deviations
// (note that calculating a standard deviation of a Vector3 might not
// be done properly, but the logic is working for the gaze stabalization scenario)
Average = cumulativeFrame / ActualSampleCount;
float newStandardDev = Mathf.Sqrt((cumulativeFrameSquared / ActualSampleCount - Average.Mul(Average)).magnitude);
StandardDeviationDeltaAfterLatestSample = oldStandardDeviation - newStandardDev;
CurrentStandardDeviation = newStandardDev;
// update the next list position
currentSampleIndex = (currentSampleIndex + 1) % maxSamples;
}
}
}