You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

567 lines
18 KiB

1 year ago
  1. #include "opt_algo.hpp"
  2. #include "logger.hpp"
  3. using namespace opt_algo;
  4. using namespace std;
  5. #define TAG "OptAlgo"
  6. #define BASE_LINE_SLOPE_SAMPLE_POS 240
  7. #define VERSION 1
  8. static void algo_assert(bool condition, const char* msg) {
  9. if (!condition) {
  10. ZLOGE(TAG, "algo_assert:%s", msg);
  11. throw std::runtime_error(msg);
  12. }
  13. }
  14. int OptAlgo::getAlgoVersion() { return VERSION; }
  15. int OptAlgo::calculate_peak_num(vector<float>& ogigin_val) {
  16. float avg = 0;
  17. int peakNum = 0;
  18. for (size_t i = 0; i < ogigin_val.size(); i++) {
  19. avg += ogigin_val[i];
  20. }
  21. avg = avg / ogigin_val.size();
  22. bool findPeak = false;
  23. for (size_t i = 0; i < ogigin_val.size(); i++) {
  24. if (!findPeak && ogigin_val[i] > avg) {
  25. findPeak = true;
  26. peakNum++;
  27. }
  28. if (findPeak && ogigin_val[i] < avg) {
  29. findPeak = false;
  30. }
  31. }
  32. return peakNum;
  33. }
  34. shared_ptr<AlgoResult> OptAlgo::calculate(vector<float> ogigin_val, int peaknum) {
  35. shared_ptr<AlgoResult> algoResult = make_shared<AlgoResult>();
  36. algoResult->ogigin_val = ogigin_val;
  37. algoResult->supper_val = super_sampling(ogigin_val, ogigin_val.size(), 5); // pointNum:1200*5=6000
  38. algoResult->supper_median_val = median_filtering(algoResult->supper_val, 25); // pointNum:6000
  39. algoResult->supper_smooth_sub_val = sub_sampling(algoResult->supper_median_val, 6); // pointNum:6000/6=1000
  40. algoResult->lineContext->raw = sub_sampling(algoResult->supper_median_val, 6);
  41. algoResult->lineContext->avg = smooth_windows(algoResult->supper_smooth_sub_val, 13);
  42. vector<float> diffpreprocess = least_square_method_differentiate(algoResult->supper_smooth_sub_val, 13);
  43. algoResult->lineContext->diff = smooth_windows(diffpreprocess, 13);
  44. algoResult->lineContext->agvline = find_avg_line(algoResult->supper_smooth_sub_val);
  45. algoResult->lineContext->raw250 = sub_sampling(algoResult->lineContext->raw, 4);
  46. algoResult->lineContext->avg250 = sub_sampling(algoResult->lineContext->avg, 4);
  47. algoResult->lineContext->diff250 = sub_sampling(algoResult->lineContext->diff, 4);
  48. /**
  49. * @brief
  50. *
  51. * 5
  52. *
  53. * 2:
  54. * 80,120
  55. * 3:
  56. * 40,80,120
  57. * 4:
  58. * 40,80,120,160
  59. * 5:
  60. * 40,80,120,160,200
  61. *
  62. */
  63. /**
  64. * @brief
  65. * 线40(10*4)40250
  66. * 10线线
  67. */
  68. // int baseline_sample_pos = 0;
  69. vector<int> slop_smaple_xstart;
  70. if (peaknum == 2) {
  71. slop_smaple_xstart.push_back(10 * 4);
  72. slop_smaple_xstart.push_back(20 * 4);
  73. slop_smaple_xstart.push_back(200 * 4);
  74. } else if (peaknum == 3) {
  75. slop_smaple_xstart.push_back(10 * 4);
  76. slop_smaple_xstart.push_back(200 * 4);
  77. slop_smaple_xstart.push_back(235 * 4);
  78. } else if (peaknum == 4) {
  79. slop_smaple_xstart.push_back(10 * 4);
  80. slop_smaple_xstart.push_back(200 * 4);
  81. slop_smaple_xstart.push_back(235 * 4);
  82. } else if (peaknum == 5) {
  83. slop_smaple_xstart.push_back(10 * 4);
  84. slop_smaple_xstart.push_back(235 * 4);
  85. }
  86. linear_least_squares_muti_windos(&algoResult->lineContext->avg[0], (int)algoResult->lineContext->avg.size(), slop_smaple_xstart,
  87. 5 * 4, //
  88. algoResult->lineContext->baseline_slope, //
  89. algoResult->lineContext->baseline_intercept);
  90. for (size_t i = 0; i < peaknum; i++) {
  91. Error_t ret = k_ecode_ok;
  92. if (i == 0) {
  93. if (peaknum == 2) {
  94. ret = findpeak(algoResult->lineContext, 80 * 4, 80 * 4, algoResult->peakInfo[0]);
  95. } else if (peaknum == 3) {
  96. ret = findpeak(algoResult->lineContext, 40 * 4, 80 * 4, algoResult->peakInfo[0]);
  97. } else if (peaknum == 4) {
  98. ret = findpeak(algoResult->lineContext, 40 * 4, 80 * 4, algoResult->peakInfo[0]);
  99. } else if (peaknum == 5) {
  100. ret = findpeak(algoResult->lineContext, 40 * 4, 80 * 4, algoResult->peakInfo[0]);
  101. }
  102. } else {
  103. ret = findpeak(algoResult->lineContext, algoResult->peakInfo[i - 1]->peak_end_pos, 80 * 4, algoResult->peakInfo[i]);
  104. }
  105. if (ret != k_ecode_ok) {
  106. algoResult->error_code = ret;
  107. break;
  108. }
  109. }
  110. algoResult->peakNum = peaknum;
  111. return algoResult;
  112. }
  113. vector<float> OptAlgo::differentiate(vector<float>& inputRaw) {
  114. /**
  115. * @brief
  116. *
  117. */
  118. for (int i = 0; i <= inputRaw.size() - 8; i += 8) {
  119. inputRaw[i + 1] = inputRaw[i + 1] + 0.001f;
  120. inputRaw[i + 2] = inputRaw[i + 2] + 0.002f;
  121. inputRaw[i + 3] = inputRaw[i + 3] + 0.003f;
  122. inputRaw[i + 4] = inputRaw[i + 4] + 0.004f;
  123. inputRaw[i + 5] = inputRaw[i + 5] + 0.005f;
  124. inputRaw[i + 6] = inputRaw[i + 6] + 0.004f;
  125. inputRaw[i + 7] = inputRaw[i + 7] + 0.003f;
  126. inputRaw[i + 8] = inputRaw[i + 8] + 0.002f;
  127. }
  128. /**
  129. * @brief
  130. * @Warning:
  131. *
  132. *
  133. */
  134. vector<float> differentiateRaw(inputRaw.size(), 0);
  135. for (size_t i = 1; i < differentiateRaw.size(); i++) {
  136. differentiateRaw[i] = inputRaw[i] - inputRaw[i - 1];
  137. }
  138. differentiateRaw[0] = differentiateRaw[1];
  139. return differentiateRaw;
  140. }
  141. vector<float> OptAlgo::least_square_method_differentiate(vector<float>& inputRaw, int windows_size) {
  142. algo_assert(windows_size > 0, "windows_size <= 0");
  143. algo_assert(windows_size % 2 == 1, "windows_size is not odd");
  144. vector<float> differentiateRaw(inputRaw.size(), 0);
  145. vector<float> windowsRaw(windows_size, 0);
  146. int windows_size_half = (windows_size - 1) / 2;
  147. for (int index = windows_size_half; index < inputRaw.size() - windows_size_half; index++) {
  148. windowsRaw = getwindowspoint(inputRaw, index, windows_size);
  149. float intercept = 0;
  150. linear_least_squares(windowsRaw.data(), windows_size, differentiateRaw[index], intercept);
  151. }
  152. for (size_t i = 0; i < windows_size_half; i++) {
  153. differentiateRaw[i] = differentiateRaw[windows_size_half];
  154. }
  155. for (size_t i = inputRaw.size() - windows_size_half; i < inputRaw.size(); i++) {
  156. differentiateRaw[i] = differentiateRaw[inputRaw.size() - windows_size_half - 1];
  157. }
  158. return differentiateRaw;
  159. }
  160. /**
  161. * @brief 线
  162. *
  163. * @param val Y轴数据
  164. * @param size Y轴数据长度
  165. * @return float
  166. */
  167. void OptAlgo::linear_least_squares(vector<float>& x, vector<float>& y, float& slope, float& intercept) {
  168. size_t n = x.size();
  169. double sumX = 0.0, sumY = 0.0, sumXY = 0.0, sumXX = 0.0;
  170. for (size_t i = 0; i < n; ++i) {
  171. sumX += x[i];
  172. sumY += y[i];
  173. sumXY += x[i] * y[i];
  174. sumXX += x[i] * x[i];
  175. }
  176. double xMean = sumX / n;
  177. double yMean = sumY / n;
  178. algo_assert(!feq((sumXX - n * xMean * xMean), 0, 0.0001), "sumXX - n * xMean * xMean == 0");
  179. slope = (sumXY - n * xMean * yMean) / (sumXX - n * xMean * xMean);
  180. intercept = yMean - slope * xMean;
  181. return;
  182. }
  183. void OptAlgo::linear_least_squares(float* y, int size, float& slope, float& intercept) {
  184. vector<float> xpoint(size, 0);
  185. vector<float> ypoint(size, 0);
  186. for (size_t i = 0; i < size; i++) {
  187. xpoint[i] = i;
  188. ypoint[i] = y[i];
  189. }
  190. return linear_least_squares(xpoint, ypoint, slope, intercept);
  191. }
  192. void OptAlgo::linear_least_squares_muti_windos(float* y, int size, vector<int> startx, int windowssize, float& slope, float& intercept) {
  193. vector<float> xpoint;
  194. vector<float> ypoint;
  195. // ZLOGI(TAG, "xxxxx%d", startx.size());
  196. for (size_t i = 0; i < startx.size(); i++) {
  197. int xstart = startx[i];
  198. for (size_t xindex = xstart; xindex < (xstart + windowssize); xindex++) {
  199. // ZLOGI(TAG, "xindex:%d y:%f", xindex, y[xindex]);
  200. xpoint.push_back(xindex);
  201. ypoint.push_back(y[xindex]);
  202. }
  203. }
  204. return linear_least_squares(xpoint, ypoint, slope, intercept);
  205. }
  206. vector<float> OptAlgo::super_sampling(vector<float>& inputRaw, int32_t nInputLength, int32_t nUpSampleRate) {
  207. /**
  208. * @brief
  209. *
  210. */
  211. int nOutputLength = nInputLength * nUpSampleRate;
  212. vector<float> upSamplingRaw(nOutputLength, 0);
  213. for (int si = 0, di = 0; si < nInputLength - 1; di++) {
  214. float a = upSamplingRaw[di * nUpSampleRate] = (float)inputRaw[si];
  215. float b = upSamplingRaw[(di + 1) * nUpSampleRate] = (float)inputRaw[++si];
  216. float nSlope = (b - a) / nUpSampleRate;
  217. for (int i = 0; i < nUpSampleRate - 1; i++) {
  218. int baseIndex = (di * nUpSampleRate) + i;
  219. upSamplingRaw[baseIndex + 1] = upSamplingRaw[baseIndex] + nSlope;
  220. }
  221. }
  222. return upSamplingRaw;
  223. }
  224. vector<float> OptAlgo::sub_sampling(vector<float>& inputRaw, int nSubSampleRate) {
  225. int nSum = 0;
  226. float fAvg = 0;
  227. int subIndex = 0;
  228. int nOutputLength = inputRaw.size() / nSubSampleRate;
  229. vector<float> subSampledRaw(nOutputLength, 0);
  230. for (int index = 0; index < inputRaw.size(); index++) {
  231. if (index % nSubSampleRate == 0 && index > 0) {
  232. fAvg = nSum / nSubSampleRate;
  233. if (subIndex < subSampledRaw.size()) {
  234. subSampledRaw[subIndex++] = fAvg;
  235. } else {
  236. int empty = 0;
  237. }
  238. nSum = 0;
  239. }
  240. nSum += inputRaw[index];
  241. }
  242. subSampledRaw[subSampledRaw.size() - 1] = subSampledRaw[subSampledRaw.size() - 2];
  243. return subSampledRaw;
  244. }
  245. vector<float> OptAlgo::smooth_windows(vector<float>& inputRaw, int windows_size) {
  246. vector<float> smoothRaw(inputRaw.size(), 0);
  247. int windows_size_half = (windows_size - 1) / 2;
  248. for (int index = windows_size_half; index < inputRaw.size() - windows_size_half; index++) {
  249. float sum = 0;
  250. for (int i = index - windows_size_half; i <= index + windows_size_half; i++) {
  251. sum += inputRaw[i];
  252. }
  253. smoothRaw[index] = sum / windows_size;
  254. }
  255. for (size_t i = 0; i < windows_size_half; i++) {
  256. smoothRaw[i] = smoothRaw[windows_size_half];
  257. }
  258. for (size_t i = inputRaw.size() - windows_size_half; i < inputRaw.size(); i++) {
  259. smoothRaw[i] = smoothRaw[inputRaw.size() - windows_size_half - 1];
  260. }
  261. return smoothRaw;
  262. }
  263. vector<float> OptAlgo::median_filtering(vector<float>& inputRaw, int windows_size) {
  264. vector<float> medianRaw(inputRaw.size(), 0);
  265. vector<float> windows(windows_size, 0);
  266. int windows_size_half = (windows_size - 1) / 2;
  267. for (int index = windows_size_half; index < inputRaw.size() - windows_size_half; index++) {
  268. for (int i = 0; i < windows_size; i++) {
  269. windows[i] = inputRaw[index + i - windows_size_half];
  270. }
  271. sort_vector(windows); // 从小到大顺序排序
  272. medianRaw[index] = windows[windows_size_half + 1];
  273. }
  274. for (size_t i = 0; i < windows_size_half; i++) {
  275. medianRaw[i] = medianRaw[windows_size_half];
  276. }
  277. for (size_t i = inputRaw.size() - windows_size_half; i < inputRaw.size(); i++) {
  278. medianRaw[i] = medianRaw[inputRaw.size() - windows_size_half - 1];
  279. }
  280. return medianRaw;
  281. }
  282. /**
  283. * @brief
  284. *
  285. * @param inputRaw
  286. * @return float
  287. */
  288. float OptAlgo::find_avg_line(vector<float>& inputRaw) {
  289. float base_min = 500;
  290. float fsum = 0;
  291. int cnt = 0;
  292. int range = inputRaw.size();
  293. do {
  294. fsum = cnt = 0;
  295. for (int i = 1; i < range; i++) {
  296. if (inputRaw[i] < base_min) {
  297. fsum += inputRaw[i];
  298. cnt++;
  299. }
  300. }
  301. base_min = base_min + 50;
  302. } while (cnt < range - 15 * inputRaw.size() / 250);
  303. float fbase = fsum / cnt;
  304. return fbase;
  305. }
  306. bool OptAlgo::feq(float a, float b, float epsilon) {
  307. float dv = a - b;
  308. if (dv < 0) dv = -dv;
  309. return dv <= epsilon;
  310. }
  311. Error_t OptAlgo::findpeak(shared_ptr<LineContext> lineContext, int32_t search_start, int32_t peakwindth,
  312. shared_ptr<PeakInfo> retpeak) { //
  313. /**
  314. * @brief
  315. *
  316. * :
  317. *
  318. *
  319. *
  320. */
  321. ZLOGI(TAG, "findpeak start:%d windth:%d", search_start, peakwindth);
  322. // judge_win_size
  323. int judge_win_size = 2 * (lineContext->avg.size() / 250) + 1;
  324. int peakoff = //
  325. sub_find_peak(lineContext, search_start, peakwindth, judge_win_size);
  326. if (peakoff < 0) return k_ecode_can_not_find_peak;
  327. retpeak->peak_pos = peakoff;
  328. /**
  329. * @brief
  330. *
  331. * :
  332. *
  333. * 线
  334. *
  335. */
  336. int peak_start_pos = find_peak_endpoint(lineContext, retpeak->peak_pos, -1, peakwindth / 2);
  337. int peak_end_pos = find_peak_endpoint(lineContext, retpeak->peak_pos, 1, peakwindth / 2);
  338. if (peak_start_pos < 0) return k_ecode_can_not_find_peak_start;
  339. if (peak_end_pos < 0) return k_ecode_can_not_find_peak_end;
  340. retpeak->peak_start_pos = peak_start_pos;
  341. retpeak->peak_end_pos = peak_end_pos;
  342. /**
  343. * @brief
  344. *
  345. */
  346. float peak_full_area = 0;
  347. for (int i = peak_start_pos; i <= peak_end_pos; i++) {
  348. peak_full_area += lineContext->raw[i];
  349. }
  350. float peak_base_line_area = 0;
  351. #if 1
  352. peak_base_line_area = //
  353. (lineContext->raw[peak_start_pos] + lineContext->raw[peak_end_pos]) * 0.5 * (peak_end_pos - peak_start_pos + 1);
  354. #else
  355. for (int i = peak_start_pos; i <= peak_end_pos; i++) {
  356. peak_base_line_area += i * lineContext->baseline_slope + lineContext->baseline_intercept;
  357. }
  358. #endif
  359. retpeak->peak_full_area = peak_full_area;
  360. retpeak->peak_base_line_area = peak_base_line_area;
  361. retpeak->area = peak_full_area - peak_base_line_area;
  362. if (retpeak->area <= 0) retpeak->area = 0;
  363. retpeak->find_peak = true;
  364. return k_ecode_ok;
  365. }
  366. int OptAlgo::find_peak_endpoint(shared_ptr<LineContext> lineContext,
  367. int peakpos, //
  368. int search_direction, //
  369. int search_windows) {
  370. /**
  371. * @brief
  372. *
  373. *
  374. * :
  375. * 1.
  376. * 2. 线
  377. *
  378. */
  379. int off = -1;
  380. ZLOGI(TAG, "find peakend top_pos:%d direction:%d windows:%d", peakpos, search_direction, search_windows);
  381. //
  382. algo_assert(search_windows > 0, "search_windows <= 0");
  383. algo_assert(search_direction == 1 || search_direction == -1, "search_direction != 1 && search_direction != -1");
  384. //
  385. int index_dval = search_direction >= 0 ? 1 : -1;
  386. int search_start = peakpos;
  387. int search_end = peakpos + search_direction * search_windows;
  388. algo_assert(search_end >= 0, "search_end < 0");
  389. algo_assert(lineContext->avg.size() > search_end, "lineContext->avg.size() <= search_start");
  390. for (int i = search_start; i != search_end; i += index_dval) {
  391. float now = lineContext->avg[i];
  392. if (now >= lineContext->agvline) continue;
  393. if (search_direction == 1) {
  394. if (feq(lineContext->diff[i], lineContext->baseline_slope, 0.3) || lineContext->diff[i] >= lineContext->baseline_slope) {
  395. off = i;
  396. break;
  397. }
  398. } else {
  399. if (feq(lineContext->diff[i], lineContext->baseline_slope, 0.3) || lineContext->diff[i] <= lineContext->baseline_slope) {
  400. off = i;
  401. break;
  402. }
  403. }
  404. }
  405. return off;
  406. }
  407. int OptAlgo::sub_find_peak(shared_ptr<LineContext> lineContext, int start_off, int windos_size, int judge_win_size) { //
  408. ZLOGI(TAG, "sub_find_peak %d %d %d", start_off, windos_size, judge_win_size);
  409. float maxv = 0;
  410. int peakoff = -1;
  411. bool findmax = false;
  412. for (size_t index = 0; index < windos_size; index++) {
  413. int off = index + start_off;
  414. // 从窗口的一半大小开始判断
  415. if (findmax && lineContext->avg[off] <= lineContext->agvline) break;
  416. if (off < judge_win_size / 2) continue;
  417. // 查找的点要大于基线
  418. if (lineContext->avg[off] <= lineContext->agvline) continue;
  419. // 判断的
  420. if ((off + judge_win_size / 2) > (lineContext->avg.size() - 1)) break;
  421. // 找到最大的峰值,这里判断用于去除一个波峰中的某个临时的小波峰
  422. if (maxv > lineContext->avg[off]) continue;
  423. /**
  424. * @brief
  425. */
  426. if (is_maxval_in_windows(&(lineContext->avg[off]), judge_win_size)) {
  427. findmax = true;
  428. maxv = lineContext->avg[off];
  429. peakoff = off;
  430. }
  431. }
  432. return peakoff;
  433. }
  434. bool OptAlgo::is_maxval_in_windows(float* val, int windows_size) {
  435. algo_assert(windows_size > 0, "windows_size <= 0");
  436. algo_assert(windows_size % 2 == 1, "windows_size is not odd");
  437. bool ret = true;
  438. float* valstartpos = val - windows_size / 2;
  439. for (size_t i = 0; i < windows_size; i++) {
  440. if (&valstartpos[i] == val) continue;
  441. if (valstartpos[i] > *val) {
  442. ret = false;
  443. break;
  444. }
  445. }
  446. return ret;
  447. }
  448. float OptAlgo::get_avg_in_windows(vector<float>& src, int off, int windows) {
  449. float sum = 0;
  450. algo_assert(windows % 2 == 1, "windows is not odd");
  451. for (int i = off - windows / 2; i <= off + windows / 2; i++) {
  452. sum += src[i];
  453. }
  454. return sum / windows;
  455. }
  456. void OptAlgo::sort_vector(vector<float>& src) {
  457. // 实现冒泡排序
  458. for (int i = 0; i < src.size(); i++) {
  459. for (int j = 0; j < src.size() - i - 1; j++) {
  460. if (src[j] > src[j + 1]) {
  461. float temp = src[j];
  462. src[j] = src[j + 1];
  463. src[j + 1] = temp;
  464. }
  465. }
  466. }
  467. }
  468. vector<float> OptAlgo::getwindowspoint(vector<float>& src, int off, int windows) {
  469. vector<float> ret(windows, 0);
  470. int retindex = 0;
  471. for (int i = off - windows / 2; i <= off + windows / 2; i++) {
  472. ret[retindex] = src[i];
  473. retindex++;
  474. }
  475. return ret;
  476. }