1 package de.desy.acop.video.analysis;
2
3 import java.util.Arrays;
4
5 import org.apache.commons.math.FunctionEvaluationException;
6 import org.apache.commons.math.analysis.DifferentiableMultivariateVectorialFunction;
7 import org.apache.commons.math.analysis.MultivariateMatrixFunction;
8 import org.apache.commons.math.optimization.OptimizationException;
9 import org.apache.commons.math.optimization.VectorialPointValuePair;
10 import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer;
11
12
13
14
15
16
17
18
19
20 public class FittingUtilities {
21
22 private static class GaussWithOffset implements DifferentiableMultivariateVectorialFunction {
23
24 private static final long serialVersionUID = 1L;
25 private double[] x;
26
27
28
29
30
31
32
33 public GaussWithOffset(double[] x) {
34 this.x = x;
35 }
36
37
38
39
40
41 public MultivariateMatrixFunction jacobian() {
42 return new MultivariateMatrixFunction(){
43 private static final long serialVersionUID = 1L;
44 public double[][] value(double[] a) throws FunctionEvaluationException, IllegalArgumentException {
45 double[][] J = new double[x.length][a.length];
46 for (int i = 0; i < J.length; i++) {
47 J[i][0] = Math.exp(-a[1]*(x[i]-a[2])*(x[i]-a[2]));
48 J[i][1] = -J[i][0]*a[0]*(x[i]-a[2])*(x[i]-a[2]);
49 J[i][2] = a[0]*J[i][0]*a[1]*2*(x[i]-a[2]);
50 J[i][3] = 1;
51 }
52 return J;
53 }
54 };
55 }
56
57
58
59
60
61 public double[] value(double[] a) throws FunctionEvaluationException, IllegalArgumentException {
62 double[] f = new double[x.length];
63 for (int i = 0; i < x.length; i++) {
64 f[i] = a[0] * Math.exp(-a[1]*(x[i]-a[2])*(x[i]-a[2])) + a[3];
65 }
66 return f;
67 }
68 }
69
70 private static class GaussWithLinear implements DifferentiableMultivariateVectorialFunction {
71
72 private static final long serialVersionUID = 1L;
73 private double[] x;
74
75
76
77
78
79
80
81 public GaussWithLinear(double[] x) {
82 this.x = x;
83 }
84
85
86
87
88
89 public MultivariateMatrixFunction jacobian() {
90 return new MultivariateMatrixFunction(){
91 private static final long serialVersionUID = 1L;
92 public double[][] value(double[] a) throws FunctionEvaluationException, IllegalArgumentException {
93 double[][] J = new double[x.length][a.length];
94 for (int i = 0; i < J.length; i++) {
95 J[i][0] = Math.exp(-a[1]*(x[i]-a[2])*(x[i]-a[2]));
96 J[i][1] = -J[i][0]*a[0]*(x[i]-a[2])*(x[i]-a[2]);
97 J[i][2] = a[0]*J[i][0]*a[1]*2*(x[i]-a[2]);
98 J[i][3] = 1;
99 J[i][4] = x[i];
100 }
101 return J;
102 }
103 };
104 }
105
106
107
108
109
110 public double[] value(double[] a) throws FunctionEvaluationException, IllegalArgumentException {
111 double[] f = new double[x.length];
112 for (int i = 0; i < x.length; i++) {
113 f[i] = a[0] * Math.exp(-a[1]*(x[i]-a[2])*(x[i]-a[2])) + a[3] + a[4]*x[i];
114 }
115 return f;
116 }
117 }
118
119 private static class Gauss implements DifferentiableMultivariateVectorialFunction {
120
121 private static final long serialVersionUID = 1L;
122 private double[] x;
123
124
125
126
127
128
129
130 public Gauss(double[] x) {
131 this.x = x;
132 }
133
134
135
136
137
138 public MultivariateMatrixFunction jacobian() {
139 return new MultivariateMatrixFunction(){
140 private static final long serialVersionUID = 1L;
141 public double[][] value(double[] a) throws FunctionEvaluationException, IllegalArgumentException {
142 double[][] J = new double[x.length][a.length];
143 for (int i = 0; i < J.length; i++) {
144 J[i][0] = Math.exp(-a[1]*(x[i]-a[2])*(x[i]-a[2]));
145 J[i][1] = -J[i][0]*a[0]*(x[i]-a[2])*(x[i]-a[2]);
146 J[i][2] = a[0]*J[i][0]*a[1]*2*(x[i]-a[2]);
147 }
148 return J;
149 }
150 };
151 }
152
153
154
155
156
157 public double[] value(double[] a) throws FunctionEvaluationException, IllegalArgumentException {
158 double[] f = new double[x.length];
159 for (int i = 0; i < x.length; i++) {
160 f[i] = a[0] * Math.exp(-a[1]*(x[i]-a[2])*(x[i]-a[2]));
161 }
162 return f;
163 }
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 @Deprecated
239 public static double[] lmOffset(double[] x, double[] y, double[] weights, double[] startValues) throws OptimizationException, FunctionEvaluationException, IllegalArgumentException {
240 LevenbergMarquardtOptimizer lmo = new LevenbergMarquardtOptimizer();
241
242 lmo.setMaxIterations(500);
243 GaussWithOffset f = new GaussWithOffset(x);
244 VectorialPointValuePair pvp = lmo.optimize(f,y,weights,startValues);
245 double[] a = pvp.getPointRef();
246 a[1] = 1./Math.sqrt(2*a[1]);
247 return a;
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263 public static double[] lmLinear(double[] x, double[] y, double[] weights, double[] startValues) throws OptimizationException, FunctionEvaluationException, IllegalArgumentException {
264 LevenbergMarquardtOptimizer lmo = new LevenbergMarquardtOptimizer();
265 lmo.setInitialStepBoundFactor(0.3);
266 lmo.setMaxIterations(1000);
267 startValues[1] = 1/(2*startValues[1]);
268 GaussWithLinear f = new GaussWithLinear(x);
269 VectorialPointValuePair pvp = lmo.optimize(f,y,weights,startValues);
270 double[] a = pvp.getPointRef();
271 a[1] = 1./Math.sqrt(2*a[1]);
272 return a;
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288 public static double[] lmGauss(double[] x, double[] y, double[] weights, double[] startValues) throws OptimizationException, FunctionEvaluationException, IllegalArgumentException {
289 LevenbergMarquardtOptimizer lmo = new LevenbergMarquardtOptimizer();
290 lmo.setInitialStepBoundFactor(0.3);
291 lmo.setMaxIterations(1000);
292 startValues[1] = 1/(2*startValues[1]);
293 Gauss f = new Gauss(x);
294 VectorialPointValuePair pvp = lmo.optimize(f,y,weights,startValues);
295 double[] a = pvp.getPointRef();
296 a[1] = 1./Math.sqrt(2*a[1]);
297 return a;
298 }
299
300 public static void main(String[] args) throws MathException {
301 int n = 1000;
302 double[] x = new double[n];
303 for (int i = 0; i < x.length; i++) {
304 x[i] = 5*Math.exp(-(i-n/2)*(i-n/2)/(2*n*n/100));
305 }
306 double[] res = fit(x,0);
307 System.out.println(Arrays.toString(res));
308 }
309
310
311
312
313
314
315
316
317 public static double[] fit(double[] y, double constY) throws MathException {
318 double[][] A = new double[3][3];
319 double[] b = new double[3];
320 double val;
321 double length = y.length;
322 try {
323 int i = 0;
324 double v;
325 double x;
326 for (;;) {
327
328 val = (y[i]-constY)/length;
329 if (val <= 0) {
330 val = 0;
331 } else {
332 val = Math.log(val);
333 }
334
335 v = y[i]-constY;
336
337 x = i/length;
338 A[0][0] += x*x*x*x*v;
339 A[0][1] += x*x*x*v;
340 A[0][2] += x*x*v;
341 A[1][2] += x*v;
342 A[2][2] += v;
343 b[0] += val*x*x*v;
344 b[1] += val*x*v;
345 b[2] += val*v;
346 i++;
347 }
348 } catch (ArrayIndexOutOfBoundsException e) {}
349 A[1][1] = A[0][2];
350 A[1][0] = A[0][1];
351 A[2][0] = A[0][2];
352 A[2][1] = A[1][2];
353
354 LUDecomposition lu = new LUDecomposition(A);
355 double[] r = lu.solve(b);
356 double sigma = Math.sqrt(-0.5/r[0])*length;
357 double mean = -0.5*r[1]*length/r[0];
358 double amp = Math.exp(r[2] -0.25*r[1]*r[1]/r[0])*length;
359
360 return new double[]{amp,sigma,mean,constY,0};
361 }
362
363
364
365
366
367
368
369 public static boolean isNaN(double[] values) {
370 for (int i = 0; i < values.length; i++) {
371 if (Double.isNaN(values[i])) return true;
372 }
373 return false;
374 }
375
376
377
378
379
380
381
382 public static double[] smooth(double[] x) {
383 return smooth(x,false);
384 }
385
386
387
388
389
390
391
392
393 public static double[] smooth(double[] x, boolean lowPassFilterOn) {
394
395 int l = x.length;
396 int n = 6;
397 double[] xx = new double[l];
398 for (int i = n; i < l; i++) {
399 for (int j = 0; j < n; j++) {
400 xx[i] += x[i-j];
401 }
402 xx[i] /= n;
403 }
404 for (int i = 0; i < n; i++) {
405 xx[i] = xx[n];
406 }
407 if (!lowPassFilterOn) return xx;
408
409 if (l < 16) l = 16;
410 else if (l < 32) l = 32;
411 else if (l < 64) l = 64;
412 else if (l < 128) l = 128;
413 else if (l < 256) l = 256;
414 else if (l < 512) l = 512;
415 else if (l < 1024) l = 1024;
416 else if (l < 2048) l = 2048;
417 else if (l < 4096) l = 4096;
418 else if (l < 8192) l = 8192;
419
420 double[] d = new double[l];
421 double[] d1 = new double[l];
422 System.arraycopy(xx,0,d1,0,xx.length);
423 double[][] dd = new double[][]{d1,d};
424 dd = FFT1D(dd,true);
425 int q = (int)(dd[0].length*0.05 + 0.5);
426 int h = dd[0].length/2;
427 for (int i = q; i < h; i++) {
428 dd[0][i] = 0;
429 dd[0][h + i] = 0;
430 dd[1][i] = 0;
431 dd[1][h+i] = 0;
432 }
433
434 dd = FFT1D(dd,false);
435 double[] a = new double[xx.length];
436 System.arraycopy(dd[0],0,a,0,a.length);
437 return a;
438 }
439
440
441
442
443
444
445
446 public static double[][] FFT1D(double[][] x, boolean forward) {
447 if (x == null)
448 return null;
449 if (x.length != 2 || x[0].length != x[1].length) {
450 throw new IllegalArgumentException("bad x lengths");
451 }
452 int n = x[0].length;
453 int n2 = 1;
454 while (n2 < n) {
455 n2 *= 2;
456 if (n2 > n) {
457 throw new IllegalArgumentException("x length must be power of 2");
458 }
459 }
460 n2 = n / 2;
461 double[][] temp = new double[2][n2];
462 double angle = (-2.0 * Math.PI / n);
463 if (!forward)
464 angle = -angle;
465 for (int i = 0; i < n2; i++) {
466 temp[0][i] = Math.cos(i * angle);
467 temp[1][i] = Math.sin(i * angle);
468 }
469 double[][] y = FFT1D(x, temp);
470 if (!forward) {
471 for (int i = 0; i < n; i++) {
472 y[0][i] /= n;
473 y[1][i] /= n;
474 }
475 }
476 return y;
477 }
478
479 private static double[][] FFT1D(double[][] x, double[][] temp) {
480 int n = x[0].length;
481 int n2 = n / 2;
482 int k = 0;
483 int b;
484 int c = 0;
485 if (n == 1) {
486 double[][] z1 = {{x[0][0]}, {x[1][0]}};
487 return z1;
488 }
489
490 b = (temp[0].length / n2);
491
492 double[][] z = new double[2][n2];
493 double[][] w = new double[2][n2];
494
495 for (k = 0; k < n2; k++) {
496 int k2 = 2 * k;
497 z[0][k] = x[0][k2];
498 z[1][k] = x[1][k2];
499 w[0][k] = x[0][k2 + 1];
500 w[1][k] = x[1][k2 + 1];
501 }
502
503 z = FFT1D(z, temp);
504 w = FFT1D(w, temp);
505
506 double[][] y = new double[2][n];
507 for (k = 0; k < n2; k++) {
508 y[0][k] = z[0][k];
509 y[1][k] = z[1][k];
510
511 double re = w[0][k] * temp[0][c] - w[1][k] * temp[1][c];
512 double im = w[0][k] * temp[1][c] + w[1][k] * temp[0][c];
513 w[0][k] = re;
514 w[1][k] = im;
515
516 y[0][k] += w[0][k];
517 y[1][k] += w[1][k];
518 y[0][k + n2] = z[0][k] - w[0][k];
519 y[1][k + n2] = z[1][k] - w[1][k];
520 c += b;
521 }
522 return y;
523 }
524 }