-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathautomaticVectorFitting.m
155 lines (147 loc) · 4.93 KB
/
automaticVectorFitting.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
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
function [model, funVF, rmse] = automaticVectorFitting(s, fun, settings)
%% automaticVectorFitting searches for the VF model automatically
% This function searches for the VF model based on complex frequency,
% complex function samples and specified settings.
%
% INPUTS
% s: complex frequency, double [1 x nS]
% fun: function samples, double [1 x nS]
% settings: struct [1 x 1]
% .rmse: wanted rmse value, double [1 x 1]
% .maxTrials: max VF runs, double [1 x 1]
% .isPeaks: are peaks in the function, logical [1 x 1]
% .poleDistribution: ioit pole distribution ('lin'/'log'), char [1 x 3]
% .nIters: number of iterations per VF run, double [1 x 1]
% .choiceType: take 'first' with good rmse or 'best' from all, d. [1 x 1]
%
% OUTPUTS
% model: VF model, struct
% .poles: complex poles, double [nP x 1]
% .residues: complex rsidues, double [nP x 1]
% .d: VF coeff., double [1 x 1]
% .d: VF coeff., double [1 x 1]
% funVF: VF function approsimation, double [1 x nS]
% rmse: root mean square error value, double [1 x 1]
%
% SYNTAX
%
% [model, funVF, rmse] = automaticVectorFitting(s, fun, settings)
%
% Function automaticVectorFitting searches for the VF model in automatic regime.
% It saves either the 'first' model satisfying the rmse criterion, or the model
% with the OK rmse value and minimal nuber of poles ('best').
%
% © 2019, Petr Kadlec, BUT, kadlecp@feec.vutbr.cz
nSamples = size(s, 2);
if nargin == 2
settings.rmse = 1e-13;
settings.maxTrials = 20;
settings.isPeaks = true;
settings.poleDistribution = 'linear';
settings.nIters = 1;
settings.choiceType = 'best';
else
if ~isfield(settings, 'rmse')
settings.rmse = 1e-3;
end
if ~isfield(settings, 'maxTrials')
settings.maxTrials = 20;
end
if ~isfield(settings, 'isPeaks')
settings.isPeaks = true;
end
if ~isfield(settings, 'poleDistribution')
settings.poleDistribution = 'linear';
end
if ~isfield(settings, 'nIters')
settings.nIters = 1;
end
if ~isfield(settings, 'choiceType')
settings.choiceType = 'best';
end
end
[peaks, ~] = findPeaks(abs(fun));
nPeaks = 2*floor(numel(peaks)/2);
if nPeaks < 2
initPoles = 2;
elseif nPeaks > 20
initPoles = 30;
else
initPoles = 2*nPeaks;
end
cikCak2 = 0:2:2*settings.maxTrials;
cikCak2(3:2:end) = -cikCak2(3:2:end);
cikCak2 = initPoles + cikCak2;
allModels = struct('poles', [], 'residues', [], 'd', [], 'e', []);
allFunVF = zeros(settings.maxTrials, nSamples);
allRmse = inf(1, settings.maxTrials);
if strcmp(settings.choiceType, 'best')
%% take the best from all satisfying the rmse criteria
for iIter = 1:settings.maxTrials
curN = cikCak2(iIter);
try
allModels(iIter) = vectorFitting(s, fun, curN, ...
settings.nIters, settings.isPeaks, settings.poleDistribution);
if ~isempty(allModels(iIter).poles)
allFunVF(iIter, :) = reconstructFun(s, allModels(iIter));
stat = computeStats(fun, allFunVF(iIter, :));
allRmse(iIter) = stat.rmse;
end
catch
end
end
isBetter = allRmse < settings.rmse;
if any(isBetter)
cikCak2 = cikCak2(isBetter);
allModels = allModels(isBetter);
allRmse = allRmse(isBetter);
allFunVF = allFunVF(isBetter, :);
% take the one is minimum # of poles
[~, ind] = min(cikCak2);
allModels = allModels(ind);
allRmse = allRmse(ind);
allFunVF = allFunVF(ind, :);
end
elseif strcmp(settings.choiceType, 'first')
%% take first satisfying the rmse critria
curRmse = 1;
iIter = 1;
while curRmse > settings.rmse && iIter <= settings.maxTrials
curN = cikCak2(iIter);
try
allModels(iIter) = vectorFitting(s, fun, curN, ...
settings.nIters, settings.isPeaks, settings.poleDistribution);
if ~isempty(allModels(iIter).poles)
allFunVF(iIter, :) = reconstructFun(s, allModels(iIter));
stat = computeStats(fun, allFunVF(iIter, :));
curRmse = stat.rmse;
allRmse(iIter) = curRmse;
end
catch
end
iIter = iIter + 1;
end
end
[rmseMin, ind] = min(allRmse);
%% try to make the best result better by adding
if rmseMin > settings.rmse
try
bestModel = vectorFitting(s, fun, cikCak2(ind), ...
settings.nIters + 1, settings.isPeaks, settings.poleDistribution);
if ~isempty(bestModel.poles)
bestFunVF = reconstructFun(s, bestModel);
stat = computeStats(fun, bestFunVF);
bestRmse = stat.rmse;
if bestRmse < rmseMin
allModels(ind) = bestModel;
allFunVF(ind, :) = bestFunVF;
allRmse(ind) = bestRmse;
end
end
catch
end
end
model = allModels(ind);
funVF = allFunVF(ind, :);
rmse = allRmse(ind);
end