00001
00002
00003
00004 #include "guess.h"
00005
00006 #include <algorithm>
00007 #include <ctype.h>
00008
00009 #include "common.h"
00010 #include "data.h"
00011 #include "model.h"
00012 #include "logic.h"
00013 #include "ui.h"
00014 #include "func.h"
00015 #include "settings.h"
00016
00017 using namespace std;
00018 using boost::array;
00019
00020 const array<string, 3> Guess::linear_traits =
00021 {{ "slope", "intercept", "avgy" }};
00022 const array<string, 4> Guess::peak_traits =
00023 {{ "center", "height", "hwhm", "area" }};
00024
00025 Guess::Guess(Settings const *settings) : settings_(settings)
00026 {
00027 }
00028
00029 void Guess::initialize(const DataAndModel* dm, int lb, int rb, int ignore_idx)
00030 {
00031 int len = rb - lb;
00032 assert(len >= 0);
00033 if (len == 0)
00034 throw ExecuteError("guess: empty range");
00035 xx_.resize(len);
00036 for (int j = 0; j != len; ++j)
00037 xx_[j] = dm->data()->get_x(lb+j);
00038 if (settings_->guess_uses_weights) {
00039 sigma_.resize(len);
00040 for (int j = 0; j != len; ++j)
00041 sigma_[j] = dm->data()->get_sigma(lb+j);
00042 }
00043 yy_.clear();
00044 yy_.resize(len, 0.);
00045 dm->model()->compute_model(xx_, yy_, ignore_idx);
00046 for (int j = 0; j != len; ++j)
00047 yy_[j] = dm->data()->get_y(lb+j) - yy_[j];
00048 }
00049
00050
00051 double Guess::find_hwhm(int pos, double* area)
00052 {
00053 const double hm = 0.5 * yy_[pos];
00054 const int n = 3;
00055 int left_pos = 0;
00056 int right_pos = yy_.size() - 1;
00057
00058
00059 int counter = 0;
00060 for (int i = pos; i > 0; --i) {
00061 if (yy_[i] > hm) {
00062 if (counter > 0)
00063 --counter;
00064 }
00065 else {
00066 ++counter;
00067
00068
00069 if (counter == n) {
00070 left_pos = i + counter;
00071 break;
00072 }
00073 }
00074 }
00075
00076
00077 counter = 0;
00078 for (int i = pos; i < right_pos; i++) {
00079 if (yy_[i] > hm) {
00080 if (counter > 0)
00081 counter--;
00082 }
00083 else {
00084 counter++;
00085 if (counter == n) {
00086
00087 right_pos = i - counter + 1;
00088 break;
00089 }
00090 }
00091 }
00092
00093 if (area) {
00094 *area = 0;
00095 for (int i = left_pos; i < right_pos; ++i)
00096 *area += (xx_[i+1] - xx_[i]) * (yy_[i] + yy_[i+1]) / 2;
00097 }
00098
00099 double hwhm = (xx_[right_pos] - xx_[left_pos]) / 2.;
00100 return max(hwhm, epsilon);
00101 }
00102
00103
00104
00105 array<double,4> Guess::estimate_peak_parameters()
00106 {
00107
00108
00109 int pos = -1;
00110 if (!sigma_.empty()) {
00111 for (int i = 1; i < (int) yy_.size() - 1; ++i) {
00112 int t = pos == -1 ? i-1 : pos;
00113 if (sigma_[i+1] * yy_[i] > sigma_[i] * yy_[i+1] &&
00114 sigma_[t] * yy_[i] > sigma_[i] * yy_[t])
00115 pos = i;
00116 }
00117 }
00118 else {
00119 for (int i = 1; i < (int) yy_.size() - 1; ++i)
00120 if (yy_[i] > yy_[i+1] && yy_[i] > (pos == -1 ? yy_[i-1] : yy_[pos]))
00121 pos = i;
00122 }
00123 if (pos == -1)
00124 throw ExecuteError("Peak outside of the range.");
00125
00126 double height = yy_[pos] * settings_->height_correction;
00127 double center = xx_[pos];
00128 double area;
00129 double hwhm = find_hwhm(pos, &area) * settings_->width_correction;
00130 array<double,4> r = {{ center, height, hwhm, area }};
00131 return r;
00132 }
00133
00134 array<double,3> Guess::estimate_linear_parameters()
00135 {
00136 double sx = 0, sy = 0, sxx = 0, sxy = 0;
00137 int n = yy_.size();
00138 for (int i = 0; i != n; ++i) {
00139 double x = xx_[i];
00140 double y = yy_[i];
00141 sx += x;
00142 sy += y;
00143 sxx += x*x;
00144
00145 sxy += x*y;
00146 }
00147 double slope = (n * sxy - sx * sy) / (n * sxx - sx * sx);
00148 double intercept = (sy - slope * sx) / n;
00149 double avgy = sy / n;
00150 array<double,3> r = {{ slope, intercept, avgy }};
00151 return r;
00152 }
00153
00154