-
Notifications
You must be signed in to change notification settings - Fork 19
/
periodfit.m
89 lines (77 loc) · 2.58 KB
/
periodfit.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
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
function varargout=periodfit(yofx,perdx,x,comp)
% [vard,resd,pred,contr,perdb]=PERIODFIT(yofx,perdx,x,comp)
%
% Performs a direct inversion for the periodic (sin/cos) components of a
% given signal - including an offset. But see POLYFIT for scaling on x.
%
% INPUT:
%
% yofx The data, i.e. the dependent variable
% perdx The target period, in the units of the independent variable
% x The independent variable (if not present, equally spaced)
% comp 'series' searches for all periods individually, keeps best and
% returns the variance reduction for all tried
% 'parallel' searches for all periods at the same time
%
% OUTPUT:
%
% vard Variance reduction of all periods tried
% resd Residual of the best-fitting period
% pred Prediction based on the best-fitting period
% contr The estimated expansion coefficients (sin/cos)
% perdb The best-fitting period from the set
% perdx The target period if you didn't remember it
%
% Last modified by fjsimons-at-alum.mit.edu, 12/10/2021
defval('comp','series')
% Single-column data
yofx=yofx(:);
% Equally spaced data assumed by default
defval('x',[1:length(yofx)]')
% Faux output if nothing else
perdb=perdx;
if length(perdx)==1
% The "design" matrix also includes an offset
argm=x/perdx;
F=[ones(size(yofx)) sin(2*pi*argm) cos(2*pi*argm)];
% Do the inversion
[contr,pred,resd,vard]=doinversion(F,yofx);
else
switch comp
case 'series'
% Recursive algorithm
vard=nan(size(perdx));
% Do them all
for index=1:length(perdx)
vard(index)=periodfit(yofx,perdx(index),x);
end
% Redo the best
[~,vi]=max(vard);
% Redefine the output to give us the best period
perdb=perdx(vi);
[~,resd,pred,contr]=periodfit(yofx,perdb,x);
case 'parallel'
% The "design" matrix also includes an offset
argm=[1./perdx'*x']';
F=[ones(size(yofx)) sin(2*pi*argm) cos(2*pi*argm)];
% Do the inversion
[contr,pred,resd,vard]=doinversion(F,yofx);
otherwise
error('Pick a valid option, refer to the help')
end
end
% Optional output
varns={vard,resd,pred,contr,perdb,perdx};
varargout=varns(1:nargout);
% Do the actual inversion
function [contr,pred,resd,vard]=doinversion(A,y)
% Let's find the contributions from these periods
contr=inv(A'*A)*A'*y;
% Plot the prediction from this model
pred=A*contr;
% Let's look at the residuals
resd=pred-y;
% Compare the variance of the residual to the variance of the data: if
% the fit does a good job, the variance of the residuals should be a
% small fraction of the variance of the data
vard=100*[1-var(resd)/var(y)];