CbmRoot
Loading...
Searching...
No Matches
PronyFitter.cxx
Go to the documentation of this file.
1/* Copyright (C) 2020-2021 Institute for Nuclear Research, Moscow
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Nikolay Karpushkin [committer] */
4
5#include "PronyFitter.h"
6
8#include "PolynomRealRoots.h"
9
11{
12
13
14 PronyFitter::PronyFitter(int model_order, int exponent_number, int gate_beg, int gate_end)
15 {
16 Initialize(model_order, exponent_number, gate_beg, gate_end);
17 }
18
19 void PronyFitter::Initialize(int model_order, int exponent_number, int gate_beg, int gate_end)
20 {
21 fModelOrder = model_order;
22 fExpNumber = exponent_number;
23 fGateBeg = gate_beg;
24 fGateEnd = gate_end;
25 AllocData();
26 }
27
29 {
30 fz = new std::complex<float>[fExpNumber + 1];
31 fh = new std::complex<float>[fExpNumber + 1];
32 for (int i = 0; i < fExpNumber + 1; i++) {
33 fz[i] = {0., 0.};
34 fh[i] = {0., 0.};
35 }
36 }
37
38 void PronyFitter::SetWaveform(std::vector<uint16_t>& uWfm, uint16_t uZeroLevel)
39 {
40 fuWfm = uWfm;
41 fuZeroLevel = uZeroLevel;
42 fSampleTotal = fuWfm.size();
43 fuFitWfm.resize(fSampleTotal);
44 }
45
46 int PronyFitter::CalcSignalBegin(float front_time_beg_03, float front_time_end)
47 {
48 return std::ceil((3 * front_time_beg_03 - front_time_end) / 2.);
49 }
50
51 void PronyFitter::SetSignalBegin(int SignalBeg)
52 {
53 fSignalBegin = SignalBeg;
54 if (fIsDebug) printf("\nsignal begin %i zero level %u\n", fSignalBegin, fuZeroLevel);
55 }
56
58 {
59 float rho_f = 999;
60 float rho_b = 999;
61 std::vector<float> a_f;
62 std::vector<float> a_b;
63
64 CovarianceDirect(rho_f, a_f, rho_b, a_b);
65 //CovarianceQRmod(rho_f, a_f, rho_b, a_b);
66
67 if (fIsDebug) {
68 printf("LSerr %e, SLE roots forward ", rho_f);
69 for (uint8_t i = 0; i < a_f.size(); i++)
70 printf(" %e ", a_f.at(i));
71 printf("\n");
72 printf("LSerr %e, SLE roots backward ", rho_b);
73 for (uint8_t i = 0; i < a_b.size(); i++)
74 printf(" %e ", a_b.at(i));
75 printf("\n");
76 }
77
78 float* a_arr = new float[fModelOrder + 1];
79 for (int i = 0; i < fModelOrder + 1; i++)
80 a_arr[i] = 0.;
81
82 //for(uint8_t i = 0; i < a_f.size(); i++) a_arr[i+1] = 0.5*(a_f.at(i) + a_b.at(i));
83 for (uint8_t i = 0; i < a_f.size(); i++)
84 a_arr[i + 1] = a_f.at(i);
85 a_arr[0] = 1.;
86
87 float* zr = new float[fModelOrder];
88 float* zi = new float[fModelOrder];
89 for (int i = 0; i < fModelOrder; i++) {
90 zr[i] = 0.;
91 zi[i] = 0.;
92 }
93
94 int total_roots;
95 //polynomRealRoots(zr, fModelOrder, a_arr, total_roots);
96 polynomComplexRoots(zr, zi, fModelOrder, a_arr, total_roots);
97 if (fIsDebug) {
98 printf("forward polinom roots ");
99 for (int i = 0; i < fModelOrder; i++)
100 printf("%.5f%+.5fi ", zr[i], zi[i]);
101 printf("\n");
102
103 printf("forward freqs ");
104 for (int i = 0; i < fModelOrder; i++)
105 printf("%.5f ", log(zr[i]));
106 printf("\n");
107 }
108
109 std::complex<float>* z_arr = new std::complex<float>[fExpNumber + 1];
110 for (int i = 0; i < fExpNumber; i++) {
111 if (std::isfinite(zr[i])) z_arr[i + 1] = {zr[i], zi[i]};
112 else
113 z_arr[i + 1] = 0.;
114 }
115 z_arr[0] = {1., 0.};
116 SetHarmonics(z_arr);
117 fTotalPolRoots = total_roots;
118
119 delete[] a_arr;
120 delete[] zr;
121 delete[] zi;
122 delete[] z_arr;
123 }
124
125 void PronyFitter::CovarianceDirect(float& /*rho_f*/, std::vector<float>& a_f, float& /*rho_b*/,
126 std::vector<float>& /*a_b*/)
127 {
128 std::vector<int32_t> kiWfmSignal;
129 //filtering constant fraction
130 for (int sample_curr = fSignalBegin; sample_curr <= fGateEnd; sample_curr++)
131 kiWfmSignal.push_back(fuWfm.at(sample_curr) - fuZeroLevel);
132 int n = kiWfmSignal.size();
133
134 float** Rkm_arr = new float*[fModelOrder];
135 for (int i = 0; i < fModelOrder; i++) {
136 Rkm_arr[i] = new float[fModelOrder];
137 for (int j = 0; j < fModelOrder; j++)
138 Rkm_arr[i][j] = 0.;
139 }
140
141 float* R0k_arr = new float[fModelOrder];
142 for (int i = 0; i < fModelOrder; i++)
143 R0k_arr[i] = 0.;
144
145 //Regression via linear prediction forward
146 for (int i = 1; i <= fModelOrder; i++)
147 for (int j = 1; j <= fModelOrder; j++)
148 for (int sample_curr = fModelOrder; sample_curr < n; sample_curr++)
149 Rkm_arr[i - 1][j - 1] += (float) (kiWfmSignal.at(sample_curr - i) * kiWfmSignal.at(sample_curr - j));
150
151 for (int i = 1; i <= fModelOrder; i++)
152 for (int sample_curr = fModelOrder; sample_curr < n; sample_curr++)
153 R0k_arr[i - 1] -= (float) (kiWfmSignal.at(sample_curr) * kiWfmSignal.at(sample_curr - i));
154
155 if (fIsDebug) {
156 printf("system forward\n");
157 for (int i = 0; i < fModelOrder; i++) {
158 for (int j = 0; j < fModelOrder; j++)
159 printf("%e ", Rkm_arr[i][j]);
160 printf("%e\n", R0k_arr[i]);
161 }
162 }
163
164 float* a = new float[fModelOrder];
165 for (int i = 0; i < fModelOrder; i++)
166 a[i] = 0.;
167
168 SolveSLEGauss(a, Rkm_arr, R0k_arr, fModelOrder);
169 //SolveSLECholesky(a, Rkm_arr, R0k_arr, fModelOrder);
170 if (fIsDebug) {
171 printf("SLE roots ");
172 for (int i = 0; i < fModelOrder; i++)
173 printf(" %e ", a[i]);
174 printf("\n");
175 }
176
177 a_f.resize(fModelOrder);
178 for (int i = 0; i < fModelOrder; i++)
179 a_f.at(i) = a[i];
180
181 for (int i = 0; i < fModelOrder; i++)
182 delete[] Rkm_arr[i];
183 delete[] Rkm_arr;
184 delete[] R0k_arr;
185 delete[] a;
186 }
187
188 void PronyFitter::CovarianceQRmod(float& rho_f, std::vector<float>& a_f, float& rho_b, std::vector<float>& a_b)
189 {
190
191 /*
192% Copyright (c) 2019 by S. Lawrence Marple Jr.
193%
194%
195p
196--
197order of linear prediction/autoregressive filter
198%
199x
200--
201vector of data samples
202%
203rho_f
204--
205least squares estimate of forward linear prediction variance
206%
207a_f
208--
209vector of forward linear prediction/autoregressive
210parameters
211%
212rho_b
213--
214least squares estimate of backward linear prediction
215variance
216%
217a_b
218--
219vector of backward linear prediction/autoregressive
220parameters
221
222*/
223
224
225 //******** Initialization ********
226
227 std::vector<int32_t> kiWfmSignal;
228 //filtering constant fraction
229 for (int sample_curr = fSignalBegin; sample_curr <= fGateEnd; sample_curr++)
230 kiWfmSignal.push_back(fuWfm.at(sample_curr) - fuZeroLevel);
231 int n = kiWfmSignal.size();
232 if (2 * fModelOrder + 1 > n) {
233 if (fIsDebug) printf("ERROR: Order too high; will make solution singular\n");
234 return;
235 }
236
237 float r1 = 0.;
238 for (int k = 1; k <= n - 2; k++)
239 r1 += std::pow(kiWfmSignal.at(k), 2);
240
241 float r2 = std::pow(kiWfmSignal.front(), 2);
242 float r3 = std::pow(kiWfmSignal.back(), 2);
243
244 rho_f = r1 + r3;
245 rho_b = r1 + r2;
246 r1 = 1. / (rho_b + r3);
247
248 std::vector<float> c, d;
249 c.push_back(kiWfmSignal.back() * r1);
250 d.push_back(kiWfmSignal.front() * r1);
251
252 float gam = 0.;
253 float del = 0.;
254 std::vector<float> ef, eb, ec, ed;
255 std::vector<float> coeffs;
256 coeffs.resize(6);
257
258 for (int v_iter = 0; v_iter < n; v_iter++) {
259 ef.push_back(kiWfmSignal.at(v_iter));
260 eb.push_back(kiWfmSignal.at(v_iter));
261 ec.push_back(c.at(0) * kiWfmSignal.at(v_iter));
262 ed.push_back(d.at(0) * kiWfmSignal.at(v_iter));
263 }
264
265 //******** Main Recursion ********
266
267 for (int k = 1; k <= fModelOrder; k++) {
268 if (rho_f <= 0 || rho_b <= 0) {
269 if (fIsDebug)
270 printf("PsdPronyFitter::ERROR: prediction squared error was less "
271 "than or equal to zero\n");
272 return;
273 }
274
275 gam = 1. - ec.at(n - k);
276 del = 1. - ed.front();
277 if (gam <= 0 || gam > 1 || del <= 0 || del > 1) {
278 if (fIsDebug)
279 printf("PsdPronyFitter::ERROR: GAM or DEL gain factor not in "
280 "expected range 0 to 1\n");
281 return;
282 }
283
284 // computation for k-th order reflection coefficients
285 std::vector<float> eff, ebb;
286 eff.resize(n);
287 ebb.resize(n);
288 float delta = 0.;
289 for (int v_iter = 0; v_iter < n - 1; v_iter++) {
290 eff.at(v_iter) = ef.at(v_iter + 1);
291 ebb.at(v_iter) = eb.at(v_iter);
292 delta += eff.at(v_iter) * ebb.at(v_iter);
293 }
294
295 float k_f = -delta / rho_b;
296 float k_b = -delta / rho_f;
297
298 //% order updates for squared prediction errors rho_f and rho_b
299 rho_f = rho_f * (1 - k_f * k_b);
300 rho_b = rho_b * (1 - k_f * k_b);
301
302 //% order updates for linear prediction parameter arrays a_f and a_b
303 std::vector<float> temp_af = a_f;
304 std::reverse(std::begin(a_b), std::end(a_b));
305 for (uint8_t i = 0; i < a_f.size(); i++)
306 a_f.at(i) += k_f * a_b.at(i);
307 a_f.push_back(k_f);
308
309 std::reverse(std::begin(a_b), std::end(a_b));
310 std::reverse(std::begin(temp_af), std::end(temp_af));
311 for (uint8_t i = 0; i < a_b.size(); i++)
312 a_b.at(i) += k_b * temp_af.at(i);
313 a_b.push_back(k_b);
314
315 //% check if maximum order has been reached
316 if (k == fModelOrder) {
317 rho_f = rho_f / (n - fModelOrder);
318 rho_b = rho_b / (n - fModelOrder);
319 return;
320 }
321
322 //% order updates for prediction error arrays ef and eb
323 for (int v_iter = 0; v_iter < n; v_iter++) {
324 eb.at(v_iter) = ebb.at(v_iter) + k_b * eff.at(v_iter);
325 ef.at(v_iter) = eff.at(v_iter) + k_f * ebb.at(v_iter);
326 }
327
328 //% coefficients for next set of updates
329 coeffs.at(0) = ec.front();
330 coeffs.at(1) = coeffs.at(0) / del;
331 coeffs.at(2) = coeffs.at(0) / gam;
332
333 //% time updates for gain arrays c' and d"
334 std::vector<float> temp_c = c;
335 for (uint8_t v_iter = 0; v_iter < c.size(); v_iter++) {
336 c.at(v_iter) += coeffs.at(1) * d.at(v_iter);
337 d.at(v_iter) += coeffs.at(2) * temp_c.at(v_iter);
338 }
339
340 //% time updates for ec' and ed"
341 std::vector<float> temp_ec = ec;
342 for (int v_iter = 0; v_iter < n; v_iter++) {
343 ec.at(v_iter) += coeffs.at(1) * ed.at(v_iter);
344 ed.at(v_iter) += coeffs.at(2) * temp_ec.at(v_iter);
345 }
346
347 std::vector<float> ecc, edd;
348 ecc.resize(n);
349 edd.resize(n);
350 for (int v_iter = 0; v_iter < n - 1; v_iter++) {
351 ecc.at(v_iter) = ec.at(v_iter + 1);
352 edd.at(v_iter) = ed.at(v_iter);
353 }
354
355 if (rho_f <= 0 || rho_b <= 0) {
356 if (fIsDebug)
357 printf("PsdPronyFitter::ERROR2: prediction squared error was less "
358 "than or equal to zero\n");
359 return;
360 }
361 gam = 1 - ecc.at(n - k - 1); //n-k?
362 del = 1 - edd.front();
363 if (gam <= 0 || gam > 1 || del <= 0 || del > 1) {
364 if (fIsDebug)
365 printf("PsdPronyFitter::ERROR2: GAM or DEL gain factor not in "
366 "expected range 0 to 1\n");
367 return;
368 }
369
370
371 //% coefficients for next set of updates
372 coeffs.at(0) = ef.front();
373 coeffs.at(1) = eb.at(n - k - 1); //n-k?
374 coeffs.at(2) = coeffs.at(1) / rho_b;
375 coeffs.at(3) = coeffs.at(0) / rho_f;
376 coeffs.at(4) = coeffs.at(0) / del;
377 coeffs.at(5) = coeffs.at(1) / gam;
378
379 //% order updates for c and d; time updates for a_f' and a_b"
380 std::vector<float> temp_ab = a_b;
381 std::reverse(std::begin(temp_ab), std::end(temp_ab));
382 std::reverse(std::begin(c), std::end(c));
383
384 for (uint8_t i = 0; i < a_b.size(); i++)
385 a_b.at(i) += coeffs.at(5) * c.at(i);
386 std::reverse(std::begin(c), std::end(c));
387
388 for (uint8_t i = 0; i < c.size(); i++)
389 c.at(i) += coeffs.at(2) * temp_ab.at(i);
390 c.push_back(coeffs.at(2));
391
392 std::vector<float> temp_af2 = a_f;
393 for (uint8_t i = 0; i < a_f.size(); i++)
394 a_f.at(i) += coeffs.at(4) * d.at(i);
395
396 for (uint8_t i = 0; i < d.size(); i++)
397 d.at(i) += coeffs.at(3) * temp_af2.at(i);
398 d.insert(d.begin(), coeffs.at(3));
399
400 //% time updates for rho_f' and rho_b"
401 rho_f = rho_f - coeffs.at(4) * coeffs.at(0);
402 rho_b = rho_b - coeffs.at(5) * coeffs.at(1);
403
404 if (rho_f <= 0 || rho_b <= 0) {
405 if (fIsDebug)
406 printf("PsdPronyFitter::ERROR3: prediction squared error was less "
407 "than or equal to zero\n");
408 return;
409 }
410
411 //% order updates for ec and ed; time updates for ef' and eb"
412 for (int v_iter = 0; v_iter < n; v_iter++) {
413 ec.at(v_iter) = ecc.at(v_iter) + coeffs.at(2) * eb.at(v_iter);
414 eb.at(v_iter) = eb.at(v_iter) + coeffs.at(5) * ecc.at(v_iter);
415 ed.at(v_iter) = edd.at(v_iter) + coeffs.at(3) * ef.at(v_iter);
416 ef.at(v_iter) = ef.at(v_iter) + coeffs.at(4) * edd.at(v_iter);
417 }
418 }
419 }
420
421 void PronyFitter::SetHarmonics(std::complex<float>* z)
422 {
423 std::memcpy(fz, z, (fExpNumber + 1) * sizeof(std::complex<float>));
424 }
425
426 void PronyFitter::SetExternalHarmonics(std::complex<float> z1, std::complex<float> z2)
427 {
428 std::complex<float>* z_arr = new std::complex<float>[fExpNumber + 1];
429 for (int i = 0; i <= fExpNumber; i++)
430 z_arr[i] = {0., 0.};
431 z_arr[0] = {1., 0.};
432 z_arr[1] = z1;
433 z_arr[2] = z2;
434 SetHarmonics(z_arr);
435 delete[] z_arr;
436 }
437
438 std::complex<float>* PronyFitter::GetHarmonics() { return fz; }
439
441
442 void PronyFitter::MakePileUpRejection(int /*time_max*/) {}
443
445 {
446 std::complex<float>** Zik_arr = new std::complex<float>*[fExpNumber + 1];
447 for (int i = 0; i < fExpNumber + 1; i++) {
448 Zik_arr[i] = new std::complex<float>[fExpNumber + 1];
449 for (int j = 0; j < fExpNumber + 1; j++)
450 Zik_arr[i][j] = {0., 0.};
451 }
452
453 std::complex<float>* Zyk_arr = new std::complex<float>[fExpNumber + 1];
454 for (int i = 0; i < fExpNumber + 1; i++)
455 Zyk_arr[i] = {0., 0.};
456
457 int samples_in_gate = fGateEnd - fSignalBegin + 1;
458 const std::complex<float> unit = {1., 0.};
459
460 for (int i = 0; i <= fExpNumber; i++) {
461 for (int j = 0; j <= fExpNumber; j++) {
462 std::complex<float> temp = std::conj(fz[i]) * fz[j];
463 if (std::abs(temp - unit) > 1e-3) {
464 Zik_arr[i][j] = static_cast<std::complex<float>>((std::pow(temp, static_cast<float>(samples_in_gate)) - unit)
465 / (temp - unit));
466 }
467 else {
468 Zik_arr[i][j] = static_cast<std::complex<float>>(samples_in_gate);
469 }
470 }
471 }
472
473 std::complex<float>* z_power = new std::complex<float>[fExpNumber + 1];
474 for (int i = 0; i < fExpNumber + 1; i++)
475 z_power[i] = unit;
476
477 for (int i = 0; i <= fExpNumber; i++) {
478 for (int sample_curr = fSignalBegin; sample_curr <= fGateEnd; sample_curr++) {
479 Zyk_arr[i] += (std::complex<float>) (std::conj(z_power[i]) * (float) fuWfm.at(sample_curr));
480 z_power[i] *= fz[i];
481 }
482 }
483
484 if (fIsDebug) {
485 printf("\nampl calculation\n");
486 for (int i = 0; i <= fExpNumber; i++) {
487 for (int j = 0; j <= fExpNumber; j++)
488 printf("%e%+ei ", std::real(Zik_arr[i][j]), std::imag(Zik_arr[i][j]));
489 printf(" %e%+ei\n", std::real(Zyk_arr[i]), std::imag(Zyk_arr[i]));
490 }
491 }
492
493 SolveSLEGauss(fh, Zik_arr, Zyk_arr, fExpNumber + 1);
494
495 if (fIsDebug) {
496 printf("amplitudes\n%.0f%+.0fi ", std::real(fh[0]), std::imag(fh[0]));
497 for (int i = 1; i < fExpNumber + 1; i++)
498 printf("%e%+ei ", std::real(fh[i]), std::imag(fh[i]));
499 printf("\n\n");
500 }
501
502 for (int i = 0; i < fExpNumber + 1; i++)
503 z_power[i] = unit;
504
505 std::complex<float> fit_ampl_in_sample = {0., 0.};
506 fuFitZeroLevel = (uint16_t) std::real(fh[0]);
507 for (int sample_curr = 0; sample_curr < fSampleTotal; sample_curr++) {
508 fit_ampl_in_sample = {0., 0.};
509 if ((sample_curr >= fSignalBegin)) { //&& (sample_curr <= fGateEnd)) {
510 for (int i = 0; i < fExpNumber + 1; i++) {
511 fit_ampl_in_sample += fh[i] * z_power[i];
512 z_power[i] *= fz[i];
513 }
514 fuFitWfm.at(sample_curr) = (uint16_t) std::real(fit_ampl_in_sample);
515 }
516 else
517 fuFitWfm.at(sample_curr) = fuFitZeroLevel;
518 }
519
520 if (fIsDebug) {
521 printf("waveform:\n");
522 for (uint8_t i = 0; i < fuWfm.size(); i++)
523 printf("%u ", fuWfm.at(i));
524
525 printf("\nfit waveform:\n");
526 for (uint8_t i = 0; i < fuFitWfm.size(); i++)
527 printf("%u ", fuFitWfm.at(i));
528
529 printf("\nzero level %u\n\n", fuZeroLevel);
530 }
531
532 for (int i = 0; i < fExpNumber + 1; i++)
533 delete[] Zik_arr[i];
534 delete[] Zik_arr;
535 delete[] Zyk_arr;
536 delete[] z_power;
537 }
538
539
540 std::complex<float>* PronyFitter::GetAmplitudes() { return fh; }
541
542 float PronyFitter::GetIntegral(int gate_beg, int gate_end)
543 {
544 float integral = 0.;
545 for (int sample_curr = gate_beg; sample_curr <= gate_end; sample_curr++)
546 integral += (float) fuFitWfm.at(sample_curr) - fuFitZeroLevel;
547
548 if (std::isfinite(integral)) return integral;
549 return 0;
550 }
551
552 uint16_t PronyFitter::GetFitValue(int sample_number)
553 {
554 if (std::isfinite(fuFitWfm.at(sample_number))) return fuFitWfm.at(sample_number);
555 return 0;
556 }
557
559 {
560 std::complex<float> amplitude = {0., 0.};
561 if (x < GetSignalBeginFromPhase()) return std::real(fh[0]);
562 amplitude += fh[0];
563 for (int i = 1; i < fExpNumber + 1; i++)
564 amplitude += fh[i] * std::pow(fz[i], x - fSignalBegin);
565
566 if (std::isfinite(std::real(amplitude))) return std::real(amplitude);
567 return 0;
568 }
569
570 float PronyFitter::GetZeroLevel() { return (float) fuFitZeroLevel; }
571
573 {
574 return fSignalBegin
575 + std::real((std::log(-fh[2] * std::log(fz[2])) - std::log(fh[1] * log(fz[1])))
576 / (std::log(fz[1]) - std::log(fz[2])));
577 }
578
580 {
581 if (std::real(fh[2] / fh[1]) < 0)
582 return fSignalBegin + std::real(std::log(-fh[2] / fh[1]) / std::log(fz[1] / fz[2]));
583 return -999.;
584 }
585
587
588 float PronyFitter::GetX(float level, int first_sample, int last_sample)
589 {
590 int step = 0;
591 if (first_sample < last_sample) step = 1;
592 else
593 step = -1;
594 float result_sample = 0.;
595 int sample_to_check = first_sample;
596 float amplitude = 0.;
597 float amplitude_prev = GetFitValue(sample_to_check - step);
598 while ((first_sample - sample_to_check) * (last_sample - sample_to_check) <= 0) {
599 amplitude = GetFitValue(sample_to_check);
600 if ((level - amplitude) * (level - amplitude_prev) <= 0) {
601 result_sample = LevelBy2Points(sample_to_check, amplitude, sample_to_check - step, amplitude_prev, level);
602 return result_sample;
603 }
604 amplitude_prev = amplitude;
605 sample_to_check += step;
606 }
607
608 return 0;
609 }
610
611 float PronyFitter::GetX(float level, int first_sample, int last_sample, float step)
612 {
613 float result_sample = 0.;
614 float sample_to_check = (float) first_sample;
615 std::complex<float> amplitude = {0., 0.};
616 std::complex<float> amplitude_prev = GetFitValue(sample_to_check - step);
617 while ((first_sample - sample_to_check) * (last_sample - sample_to_check) <= 0) {
618 amplitude = GetFitValue(sample_to_check);
619 if ((level - std::real(amplitude)) * (level - std::real(amplitude_prev)) <= 0) {
620 if (amplitude != amplitude_prev)
621 result_sample = LevelBy2Points(sample_to_check, std::real(amplitude), sample_to_check - step,
622 std::real(amplitude_prev), level);
623 return result_sample;
624 }
625 amplitude_prev = amplitude;
626 sample_to_check += step;
627 }
628
629 return 0;
630 }
631
632 float PronyFitter::LevelBy2Points(float X1, float Y1, float X2, float Y2, float Y0)
633 {
634 return (X1 * Y0 - X1 * Y2 - X2 * Y0 + X2 * Y1) / (Y1 - Y2);
635 }
636
637 float PronyFitter::GetRSquare(int gate_beg, int gate_end)
638 {
639 float R2 = 0.;
640 float RSS = 0.;
641 float TSS = 0.;
642 int m = gate_end - gate_beg + 1;
643 int params_number = 1 + 2 * fModelOrder;
644 if (m <= params_number) return 999;
645 float average = 0.;
646 for (int sample_curr = gate_beg; sample_curr <= gate_end; sample_curr++)
647 average += fuWfm.at(sample_curr);
648 average /= m;
649
650 for (int sample_curr = gate_beg; sample_curr <= gate_end; sample_curr++) {
651 RSS += std::pow(fuFitWfm.at(sample_curr) - fuWfm.at(sample_curr), 2);
652 TSS += std::pow(fuWfm.at(sample_curr) - average, 2);
653 }
654 if (TSS == 0) return 999;
655 R2 = RSS / TSS; // correct definition is R2=1.-RSS/TSS, but R2=RSS/TSS is more convenient
656
657 float R2_adj = R2 * (m - 1) / (m - params_number);
658 return R2_adj;
659 }
660
662
663 float PronyFitter::GetChiSquare(int gate_beg, int gate_end, int time_max)
664 {
665 float chi2 = 0.;
666 int freedom_counter = 0;
667 int regions_number = 10;
668 float amplitude_max = std::abs(fuWfm.at(time_max) - fuZeroLevel);
669 if (amplitude_max == 0) return 999;
670
671 int* probability_exp = new int[regions_number];
672 int* probability_theor = new int[regions_number];
673 float* amplitude_regions = new float[regions_number + 1];
674 amplitude_regions[0] = 0.;
675 for (int i = 0; i < regions_number; i++) {
676 probability_exp[i] = 0;
677 probability_theor[i] = 0;
678 amplitude_regions[i + 1] = (i + 1) * amplitude_max / regions_number;
679 }
680
681 for (int sample_curr = gate_beg; sample_curr <= gate_end; sample_curr++) {
682 for (int i = 0; i < regions_number; i++) {
683 if ((std::abs(fuWfm.at(sample_curr) - fuZeroLevel) > amplitude_regions[i])
684 && (std::abs(fuWfm.at(sample_curr) - fuZeroLevel) <= amplitude_regions[i + 1]))
685 probability_exp[i]++;
686 if ((std::abs(fuFitWfm.at(sample_curr) - fuFitZeroLevel) > amplitude_regions[i])
687 && (std::abs(fuFitWfm.at(sample_curr) - fuFitZeroLevel) <= amplitude_regions[i + 1]))
688 probability_theor[i]++;
689 }
690 }
691
692 for (int i = 0; i < regions_number; i++) {
693 if (probability_exp[i] > 0) {
694 chi2 += std::pow(probability_exp[i] - probability_theor[i], 2.) / (probability_exp[i]);
695 freedom_counter++;
696 }
697 }
698
699 if (freedom_counter > 0) chi2 /= freedom_counter;
700 delete[] probability_exp;
701 delete[] probability_theor;
702 delete[] amplitude_regions;
703
704 return chi2;
705 }
706
707 float PronyFitter::GetDeltaInSample(int sample) { return fuFitWfm.at(sample) - fuWfm.at(sample); }
708
709 /*
710void PronyFitter::DrawFit(TObjArray *check_fit_arr, TString hist_title)
711{
712 float *sample_arr = new float[fSampleTotal];
713 for(int i = 0; i < fSampleTotal; i++)
714 sample_arr[i] = (float) i;
715
716 TGraph* tgr_ptr = new TGraph( fSampleTotal, sample_arr, fuWfm);
717 TGraph* tgr_ptr_fit = new TGraph( fSampleTotal, sample_arr, fuFitWfm);
718 TCanvas *canv_ptr = new TCanvas(hist_title.Data());
719 tgr_ptr->SetTitle(hist_title.Data());
720 tgr_ptr->Draw();
721
722 tgr_ptr_fit->SetLineColor(kRed);
723 tgr_ptr_fit->SetLineWidth(2);
724 tgr_ptr_fit->Draw("same");
725
726 check_fit_arr->Add(canv_ptr);
727
728 delete[] sample_arr;
729}
730*/
731
732 int PronyFitter::ChooseBestSignalBeginHarmonics(int first_sample, int last_sample)
733 {
734 float best_R2 = 0.;
735 int best_signal_begin = 0;
736 bool IsReasonableRoot;
737 bool IsGoodFit = false;
738 int good_fit_counter = 0;
739
740 for (int signal_begin = first_sample; signal_begin <= last_sample; signal_begin++) {
741 SetSignalBegin(signal_begin);
743 IsReasonableRoot = true;
744 for (int j = 0; j < fExpNumber; j++)
745 IsReasonableRoot = IsReasonableRoot && (std::abs(fz[j + 1]) > 1e-6) && (std::abs(fz[j + 1]) < 1e1);
746 IsGoodFit = (fTotalPolRoots > 0) && (IsReasonableRoot);
747
748 if (IsGoodFit) {
749 if (fIsDebug) printf("good fit candidate at signal begin %i\n", signal_begin);
750 good_fit_counter++;
752 float R2 = GetRSquare(fGateBeg, fGateEnd);
753 if (good_fit_counter == 1) {
754 best_R2 = R2;
755 best_signal_begin = signal_begin;
756 }
757 if (R2 < best_R2) {
758 best_R2 = R2;
759 best_signal_begin = signal_begin;
760 }
761 }
762 }
763
764 return best_signal_begin;
765 }
766
767 int PronyFitter::ChooseBestSignalBegin(int first_sample, int last_sample)
768 {
769 float best_R2 = 0.;
770 int best_signal_begin = first_sample;
771
772 for (int signal_begin = first_sample; signal_begin <= last_sample; signal_begin++) {
773 SetSignalBegin(signal_begin);
775 float R2 = GetRSquare(fGateBeg, fGateEnd);
776 if (signal_begin == first_sample) best_R2 = R2;
777 if (R2 < best_R2) {
778 best_R2 = R2;
779 best_signal_begin = signal_begin;
780 }
781 }
782
783 return best_signal_begin;
784 }
785
786 void PronyFitter::SolveSLEGauss(float* x, float** r, float* b, int n)
787 {
788 bool solvable = true;
789 int maxRow;
790 float maxEl, tmp, c;
791 float** a = new float*[n];
792 for (int i = 0; i < n; i++) {
793 a[i] = new float[n + 1];
794 for (int j = 0; j < n + 1; j++)
795 a[i][j] = 0.;
796 }
797
798 for (int i = 0; i < n; i++) {
799 for (int j = 0; j < n; j++)
800 a[i][j] = r[i][j];
801 a[i][n] = b[i];
802 }
803
804 for (int i = 0; i < n; i++) {
805 maxEl = std::abs(a[i][i]);
806 maxRow = i;
807 for (int k = i + 1; k < n; k++)
808 if (abs(a[k][i]) > maxEl) {
809 maxEl = std::abs(a[k][i]);
810 maxRow = k;
811 }
812
813 if (maxEl == 0) {
814 solvable = false;
815 if (fIsDebug) printf("SLE has not solution\n");
816 }
817
818 for (int k = i; k < n + 1; k++) {
819 tmp = a[maxRow][k];
820 a[maxRow][k] = a[i][k];
821 a[i][k] = tmp;
822 }
823
824 for (int k = i + 1; k < n; k++) {
825 c = -a[k][i] / a[i][i];
826 for (int j = i; j < n + 1; j++) {
827 if (i == j) a[k][j] = 0.;
828 else
829 a[k][j] += c * a[i][j];
830 }
831 }
832 }
833
834 for (int i = n - 1; i >= 0; i--) {
835 x[i] = a[i][n] / a[i][i];
836 for (int k = i - 1; k >= 0; k--)
837 a[k][n] -= a[k][i] * x[i];
838 }
839
840 if (!solvable) {
841 for (int i = n - 1; i >= 0; i--)
842 x[i] = 0.;
843 }
844
845 for (int i = 0; i < n; i++)
846 delete[] a[i];
847 delete[] a;
848 }
849
850 void PronyFitter::SolveSLEGauss(std::complex<float>* x, std::complex<float>** r, std::complex<float>* b, int n)
851 {
852 bool solvable = true;
853 int maxRow;
854 float maxEl;
855 std::complex<float> tmp, c;
856 std::complex<float>** a = new std::complex<float>*[n];
857 for (int i = 0; i < n; i++) {
858 a[i] = new std::complex<float>[n + 1];
859 for (int j = 0; j < n + 1; j++)
860 a[i][j] = {0., 0.};
861 }
862
863 for (int i = 0; i < n; i++) {
864 for (int j = 0; j < n; j++)
865 a[i][j] = r[i][j];
866 a[i][n] = b[i];
867 }
868
869 for (int i = 0; i < n; i++) {
870 maxEl = std::abs(a[i][i]);
871 maxRow = i;
872 for (int k = i + 1; k < n; k++)
873 if (std::abs(a[k][i]) > maxEl) {
874 maxEl = std::abs(a[k][i]);
875 maxRow = k;
876 }
877
878 if (maxEl == 0) {
879 solvable = false;
880 if (fIsDebug) printf("PsdPronyFitter:: SLE has not solution\n");
881 }
882
883 for (int k = i; k < n + 1; k++) {
884 tmp = a[maxRow][k];
885 a[maxRow][k] = a[i][k];
886 a[i][k] = tmp;
887 }
888
889 for (int k = i + 1; k < n; k++) {
890 c = -a[k][i] / a[i][i];
891 for (int j = i; j < n + 1; j++) {
892 if (i == j) a[k][j] = 0.;
893 else
894 a[k][j] += c * a[i][j];
895 }
896 }
897 }
898
899 for (int i = n - 1; i >= 0; i--) {
900 x[i] = a[i][n] / a[i][i];
901 for (int k = i - 1; k >= 0; k--)
902 a[k][n] -= a[k][i] * x[i];
903 }
904
905 if (!solvable) {
906 for (int i = n - 1; i >= 0; i--)
907 x[i] = {0., 0.};
908 }
909
910 for (int i = 0; i < n; i++)
911 delete[] a[i];
912 delete[] a;
913 }
914
915 void PronyFitter::SolveSLECholesky(float* x, float** a, float* b, int n)
916 {
917 float temp;
918 float** u = new float*[n];
919 for (int i = 0; i < n; i++) {
920 u[i] = new float[n];
921 for (int j = 0; j < n; j++)
922 u[i][j] = 0.;
923 }
924
925 float* y = new float[n];
926 for (int i = 0; i < n; i++)
927 y[i] = 0.;
928
929 for (int i = 0; i < n; i++) {
930 temp = 0.;
931 for (int k = 0; k < i; k++)
932 temp = temp + u[k][i] * u[k][i];
933 u[i][i] = std::sqrt(a[i][i] - temp);
934 for (int j = i; j < n; j++) {
935 temp = 0.;
936 for (int k = 0; k < i; k++)
937 temp = temp + u[k][i] * u[k][j];
938 u[i][j] = (a[i][j] - temp) / u[i][i];
939 }
940 }
941
942 for (int i = 0; i < n; i++) {
943 temp = 0.;
944 for (int k = 0; k < i; k++)
945 temp = temp + u[k][i] * y[k];
946 y[i] = (b[i] - temp) / u[i][i];
947 }
948
949 for (int i = n - 1; i >= 0; i--) {
950 temp = 0.;
951 for (int k = i + 1; k < n; k++)
952 temp = temp + u[i][k] * x[k];
953 x[i] = (y[i] - temp) / u[i][i];
954 }
955
956 for (int i = 0; i < n; i++)
957 delete[] u[i];
958 delete[] u;
959 delete[] y;
960 }
961
963 {
964 delete[] fz;
965 delete[] fh;
966 }
967
969 {
970 fModelOrder = 0;
971 fExpNumber = 0;
972 fGateBeg = 0;
973 fGateEnd = 0;
974 fSampleTotal = 0;
975 fuZeroLevel = 0.;
976 fSignalBegin = 0;
977 fTotalPolRoots = 0;
978 fuFitWfm.clear();
979 DeleteData();
980 }
981
982
983} // namespace PsdSignalFitting
friend fvec log(const fvec &a)
void polynomComplexRoots(float *wr, float *wi, int n, float *a, int &numr)
uint16_t GetFitValue(int sample_number)
void CovarianceDirect(float &rho_f, std::vector< float > &a_f, float &rho_b, std::vector< float > &a_b)
void SetSignalBegin(int SignalBeg)
void SetExternalHarmonics(std::complex< float > z1, std::complex< float > z2)
void SolveSLEGauss(float *x, float **r, float *b, int n)
std::complex< float > * fz
Definition PronyFitter.h:94
void CovarianceQRmod(float &rho_f, std::vector< float > &a_f, float &rho_b, std::vector< float > &a_b)
float GetRSquare(int gate_beg, int gate_end)
void SetHarmonics(std::complex< float > *z)
std::vector< uint16_t > fuWfm
Definition PronyFitter.h:92
int CalcSignalBegin(float front_time_beg_03, float front_time_end)
std::complex< float > * GetHarmonics()
int ChooseBestSignalBeginHarmonics(int first_sample, int last_sample)
std::complex< float > * GetAmplitudes()
void SetWaveform(std::vector< uint16_t > &uWfm, uint16_t uZeroLevel)
int ChooseBestSignalBegin(int first_sample, int last_sample)
float GetDeltaInSample(int sample)
float GetChiSquare(int gate_beg, int gate_end, int time_max)
float GetX(float level, int first_sample, int last_sample)
void Initialize(int model_order, int exponent_number, int gate_beg, int gate_end)
std::complex< float > * fh
Definition PronyFitter.h:95
float LevelBy2Points(float X1, float Y1, float X2, float Y2, float Y0)
void MakePileUpRejection(int time_max)
float GetIntegral(int gate_beg, int gate_end)
void SolveSLECholesky(float *x, float **a, float *b, int n)
std::vector< uint16_t > fuFitWfm
Definition PronyFitter.h:96