-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpwl_fit_l1.m
50 lines (42 loc) · 1.13 KB
/
pwl_fit_l1.m
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
function x = pwl_fit_l1(y,idx,x0,lambda)
% x = pwl_fit_l1(y,idx,x0,lambda)
%
% finds a piecewise fit for y given change point index
%
% INPUT:
% y : n-vector; original signal
% idx : k-vector; index of change point
% x0 : n-vector; approximate solution of the l1 trend estimation
% lambda : scalar; regularization parameter
%
% OUTPUT:
% x : n-vector; piecewise linear fit of y
%
n = length(y); % length of signal x
I2 = speye(n-2,n-2);
O2 = zeros(n-2,1);
D = [I2 O2 O2]+[O2 -2*I2 O2]+[O2 O2 I2];
% add both end points if not included
if (idx(1) ~= 1) , idx = [1; idx]; end
if (idx(end) ~= n), idx = [idx; n]; end
r = length(idx);
P = zeros(n,r);
for i = 1:r-1
prev = idx(i);
next = idx(i+1);
k = [prev:next-1]';
P(k,i:i+1) = [(next-k)/(next-prev),(k-prev)/(next-prev)];
end
P(end,end) = 1;
P = sparse(P);
dist= diff(idx);
d1 = 1./dist(1:end-1);
d2 = 1./dist(2:end);
v = x0(idx);
G = spdiags([d1 -(d1+d2) d2],0:2,r-2,r);
vv = ((P'*P)\(P'*y-lambda*(G'*sign(G*v))));
if ( sign(G*v)~=sign(G*vv) )
disp('possible sign change in v');
disp('try l1t_primal_trim');
end
x = P*vv;