-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOneEuroFilter.m
More file actions
164 lines (145 loc) · 5.37 KB
/
OneEuroFilter.m
File metadata and controls
164 lines (145 loc) · 5.37 KB
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
156
157
158
159
160
161
162
163
164
classdef OneEuroFilter < matlab.mixin.SetGet
% Brief: A 1D real-time signal filter that balances jitter reduction and lag.
% Details:
% This is a MATLAB implementation of the One-Euro Filter algorithm. It uses
% two low-pass filters: one for the signal and one for its derivative. The
% cutoff frequency of the signal filter is adapted based on the signal's
% speed, reducing lag during fast movements and increasing smoothing during
% slow movements or pauses. This makes it ideal for filtering noisy
% real-time data from sensors or user input without introducing noticeable delay.
%
% Syntax:
% obj = OneEuroFilter(freq)
% obj = OneEuroFilter(freq, 'mincutoff', mc, 'beta_', b, 'dcutoff', dc)
% value_hat = obj.filter(value)
% value_hat = obj.filter(value, timestamp)
%
% Inputs:
% freq - (1,1) double, Sampling frequency of the signal in Hz (>0).
% mincutoff - (1,1) double, Name-Value. Minimum cutoff frequency in Hz (>0). Lower values increase smoothing.
% beta_ - (1,1) double, Name-Value. Speed coefficient (>=0). Higher values reduce lag.
% dcutoff - (1,1) double, Name-Value. Cutoff frequency for the derivative filter in Hz (>0).
% value - (1,1) double, The raw input value to be filtered.
% timestamp - (1,1) double, Optional. The timestamp of the value in seconds, used to dynamically update the frequency.
%
% Outputs:
% obj - The constructed OneEuroFilter object.
% value_hat - (1,1) double, The filtered output value.
%
% Example:
% % Setup filter for a 120Hz signal
% one_euro = OneEuroFilter(120, 'mincutoff', 1.0, 'beta_', 0.1);
% t = 0:1/120:2;
% noisy_signal = sin(2*pi*t) + 0.2*randn(size(t));
% filtered_signal = arrayfun(@(v, ts) one_euro.filter(v, ts), noisy_signal, t);
% plot(t, noisy_signal, 'r-', t, filtered_signal, 'b-');
% legend('Noisy', 'Filtered');
%
% See also: LowPassFilter
% Author: cuixingxing
% Email: cuixingxing150@gmail.com
% Created: 13-Jan-2026 17:27:23
% Version history revision notes:
% None
% Implementation In Matlab R2026a
% Copyright © 2026 xingxingcui.All Rights Reserved.
%
properties (Constant)
UndefinedTime = -1.0
end
properties (SetAccess = protected)
Freq double
MinCutOff double
Beta double
DCutOff double
X LowPassFilter
dX LowPassFilter
LastTime double
end
methods
function obj = OneEuroFilter(freq, options)
arguments
freq (1,1) double
options.mincutoff (1,1) double = 1.0
options.beta_ (1,1) double = 0.0
options.dcutoff (1,1) double = 1.0
end
obj.Freq = freq;
obj.MinCutOff = options.mincutoff;
obj.Beta = options.beta_;
obj.DCutOff = options.dcutoff;
obj.X = LowPassFilter(obj.alpha(obj.MinCutOff));
obj.dX = LowPassFilter(obj.alpha(obj.DCutOff));
obj.LastTime = obj.UndefinedTime;
end
function value_hat = filter(obj, value, timestamp)
arguments
obj
value (1,1) double
timestamp (1,1) double = obj.UndefinedTime
end
% update frequency from timestamps
if obj.LastTime ~= obj.UndefinedTime && ...
timestamp ~= obj.UndefinedTime && ...
timestamp > obj.LastTime
obj.Freq = 1.0 / (timestamp - obj.LastTime);
end
obj.LastTime = timestamp;
% estimate derivative
if obj.X.hasLastRawValue()
dvalue = (value - obj.X.lastFilteredValue()) * obj.Freq;
else
dvalue = 0.0;
end
edvalue = obj.dX.filterWithAlpha(dvalue, obj.alpha(obj.DCutOff));
% adaptive cutoff
cutoff = obj.MinCutOff + obj.Beta * abs(edvalue);
% filter signal
value_hat = obj.X.filterWithAlpha(value, obj.alpha(cutoff));
end
function set.Freq(obj, f)
arguments
obj
f (1,1) double
end
if f <= 0
error('freq should be > 0');
end
obj.Freq = f;
end
function set.MinCutOff(obj, mc)
arguments
obj
mc (1,1) double
end
if mc <= 0
error('mincutoff should be > 0');
end
obj.MinCutOff = mc;
end
function set.Beta(obj, b)
arguments
obj
b (1,1) double
end
obj.Beta = b;
end
function set.DCutOff(obj, dc)
arguments
obj
dc (1,1) double
end
if dc <= 0
error('dcutoff should be > 0');
end
obj.DCutOff = dc;
end
end
methods (Access = private)
function a = alpha(obj, cutoff)
te = 1.0 / obj.Freq;
tau = 1.0 / (2 * pi * cutoff);
a = 1.0 / (1.0 + tau / te);
end
end
end