libfitter.C 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. libfitter - a library to fit values to sinus using ROOT
  3. Copyright (C) 2015 Andrew A Savchenko <bircoph@gentoo.org>
  4. Dmitry Yu Okunev <dyokunev@ut.mephi.ru>
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU Affero General Public License as
  7. published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Affero General Public License for more details.
  13. You should have received a copy of the GNU Affero General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <TGraph.h>
  17. #include <TF1.h>
  18. #include <TVirtualFitter.h>
  19. #include <math.h>
  20. #include <stdlib.h>
  21. #include "malloc.h"
  22. #include <stdint.h>
  23. #include "configuration.h"
  24. #include "analyzer_root.h"
  25. #define MAX_THREADS 1
  26. double fitfunc(double *x, double *par)
  27. {
  28. return par[0] * sin(par[1] * (*x) + par[2]) + par[3];
  29. }
  30. //double *x[MAX_THREADS] = {NULL};
  31. //double *y[MAX_THREADS] = {NULL};
  32. static TGraph *gr[MAX_THREADS] = {NULL};
  33. static TF1 *f1[MAX_THREADS] = {NULL};
  34. static double amp = -1;
  35. static double avg = -1;
  36. static double phase = -1;
  37. int
  38. fitter_init(uint64_t history_size, double *par) {
  39. int i = 0;
  40. TVirtualFitter::SetDefaultFitter("Minuit2");
  41. //TVirtualFitter::SetPrecision(1E-4);
  42. //TVirtualFitter::SetMaxIterations(100);
  43. while (i < MAX_THREADS) {
  44. gr[i] = new TGraph(history_size);
  45. f1[i] = new TF1("f1", fitfunc, 0, 1, 4);
  46. i++;
  47. }
  48. if (par != NULL) {
  49. amp = par[0];
  50. phase = par[2];
  51. avg = par[3];
  52. }
  53. }
  54. int
  55. fitter_deinit() {
  56. int i = 0;
  57. while (i < MAX_THREADS) {
  58. delete gr[i];
  59. delete f1[i];
  60. i++;
  61. }
  62. }
  63. double
  64. fitter(int thread_id, history_item_t *history, uint64_t filled, float frequency, double *par)
  65. {
  66. //TGraph gr(filename, "%*lg %lg %lg");
  67. uint64_t i;
  68. uint32_t yMin = history->row.value, yMax = history->row.value;
  69. double deltaXMax = 0;
  70. double sum = 0;
  71. double x_old = history[0].row.sensorTS;
  72. //printf("filled == %li; %p %p\n", filled, gr[thread_id], f1[thread_id]);
  73. gr[thread_id]->Set(filled);
  74. i = 0;
  75. while (i < filled) {
  76. double x, y, deltaX;
  77. x = history[i].row.sensorTS;
  78. deltaX = x - x_old;
  79. x_old = x;
  80. if (deltaX > deltaXMax)
  81. deltaXMax = deltaX;
  82. y = history[i].row.value;
  83. //x[i] = history[i].unixTSNano;
  84. // x[i] = history[i].sensorTS;
  85. // y[i] = history[i].value;
  86. if (y < yMin)
  87. yMin = y;
  88. if (y > yMax)
  89. yMax = y;
  90. // printf("%li %li %i\n", i, history[i].unixTSNano, history[i].value);
  91. gr[thread_id]->SetPoint(i, x, y);
  92. sum += y;
  93. i++;
  94. }
  95. uint64_t x_start = history[0].row.sensorTS;
  96. uint64_t x_end = history[filled-1].row.sensorTS;
  97. f1[thread_id]->SetRange(x_start, x_end);
  98. uint64_t TSDiff = x_end - x_start;
  99. uint64_t unixTSDiff = history[filled-1].row.unixTSNano - history[0].row.unixTSNano;
  100. double lambda = (double)2*M_PI / TSDiff;
  101. //double avg = (yMax + yMin) / 2;
  102. static double avg_pre;
  103. avg_pre = sum / filled;
  104. if (deltaXMax/10 > ((double)TSDiff/(double)filled))
  105. return -1;
  106. volatile double amp_cur = amp;
  107. volatile double avg_cur = avg;
  108. volatile double phase_cur = phase;
  109. //TF1 f1[]("f1", fitfunc, x[0], x[filled-1], 4);
  110. double amp_pre = (yMax - yMin) / 2;
  111. // f1[thread_id]->SetErrors(amp*0.01, lambda*0.01, phase*0.01, avg*0.01);
  112. f1[thread_id]->SetParameters(amp_cur < 0 ? amp_pre : amp_cur, lambda, phase < 0 ? 0 : phase, avg_cur < 0 ? avg_pre : avg_cur);
  113. //f1[thread_id]->SetParameters(amp_pre, lambda, phase < 0 ? 0 : phase, avg);
  114. if (amp_cur < 0) {
  115. f1[thread_id]->SetParLimits(0, amp_pre*0.9, amp_pre*1.1);
  116. } else {
  117. f1[thread_id]->SetParLimits(0, amp_cur*0.9999, amp_cur*1.0001);
  118. }
  119. //f1[thread_id]->SetParLimits(1, lambda*0.9, lambda*1.1);
  120. f1[thread_id]->SetParLimits(1, lambda*0.9999, lambda*1.0001);
  121. if (phase_cur < 0) {
  122. f1[thread_id]->SetParLimits(2, 0, 2*M_PI);
  123. } else {
  124. f1[thread_id]->SetParLimits(2, phase_cur-(0.0001*2*M_PI), phase_cur+(0.0001*2*M_PI));
  125. }
  126. if (avg_cur < 0) {
  127. f1[thread_id]->SetParLimits(3, avg_pre*0.9999, avg_pre*1.0001);
  128. } else {
  129. f1[thread_id]->SetParLimits(3, avg_cur*0.9999, avg_cur*1.0001);
  130. }
  131. gr[thread_id]->Fit(f1[thread_id], "WROQ");
  132. /*
  133. printf("amp = %e (%lu)\n", amp, (yMax - yMin) / 2);
  134. printf("chi2/ndf = %lf\n", f1->GetChisquare() / f1->GetNDF());
  135. printf("probability = %lf\n", f1->GetProb());
  136. printf("lambda = %e\n", lambda);
  137. printf("avg = %e\n", avg);
  138. printf("par0 = %e\n", f1->GetParameter(0));
  139. printf("par1 = %e\n", f1->GetParameter(1));
  140. printf("par2 = %e\n", f1->GetParameter(2));
  141. printf("par3 = %e\n", f1->GetParameter(3));
  142. */
  143. if (par != NULL) {
  144. par[0] = f1[thread_id]->GetParameter(0);
  145. par[1] = f1[thread_id]->GetParameter(1);//*(double)TSDiff/(double)unixTSDiff;
  146. par[2] = f1[thread_id]->GetParameter(2);
  147. par[3] = f1[thread_id]->GetParameter(3);
  148. }
  149. if (thread_id == 0) {
  150. if (f1[thread_id]->GetChisquare() / f1[thread_id]->GetNDF() < 100000) {
  151. amp = f1[thread_id]->GetParameter(0);
  152. phase = f1[thread_id]->GetParameter(2);
  153. avg = f1[thread_id]->GetParameter(3);
  154. }
  155. }
  156. return f1[thread_id]->GetChisquare() / f1[thread_id]->GetNDF();
  157. }