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.

405 lines
13 KiB

1 year ago
  1. #include "a8k_opt_algo.hpp"
  2. namespace a8k_opt_algo {
  3. using namespace std;
  4. typedef enum {
  5. ktopt,
  6. kfopt,
  7. } opt_type_t;
  8. class PorcessContext {
  9. public:
  10. vector<float> raw; //
  11. vector<float> avg; //
  12. vector<float> diff; // 一阶斜率
  13. vector<float> diffX2; // 二阶斜率
  14. float agvline; //
  15. };
  16. static void algo_assert(bool condition, const char* msg) {
  17. if (!condition) {
  18. printf("algo_assert:%s\n", msg);
  19. throw std::runtime_error(msg);
  20. }
  21. }
  22. bool feq(float a, float b, float epsilon) {
  23. float dv = a - b;
  24. if (dv < 0) dv = -dv;
  25. return dv <= epsilon;
  26. }
  27. opt_type_t m_opttype;
  28. PorcessContext m_cxt;
  29. static vector<float> sub_sampling(vector<float>& inputRaw, int nSubSampleRate);
  30. vector<float> super_sampling(vector<float>& inputRaw, int32_t nInputLength, int32_t nUpSampleRate);
  31. static vector<float> sub_sampling(vector<float>& inputRaw, int nSubSampleRate) {
  32. int nSum = 0;
  33. float fAvg = 0;
  34. int subIndex = 0;
  35. int nOutputLength = inputRaw.size() / nSubSampleRate;
  36. vector<float> subSampledRaw(nOutputLength, 0);
  37. for (int index = 0; index < inputRaw.size(); index++) {
  38. if (index % nSubSampleRate == 0 && index > 0) {
  39. fAvg = nSum / nSubSampleRate;
  40. if (subIndex < subSampledRaw.size()) {
  41. subSampledRaw[subIndex++] = fAvg;
  42. } else {
  43. int empty = 0;
  44. }
  45. nSum = 0;
  46. }
  47. nSum += inputRaw[index];
  48. }
  49. subSampledRaw[subSampledRaw.size() - 1] = subSampledRaw[subSampledRaw.size() - 2];
  50. return subSampledRaw;
  51. }
  52. vector<float> super_sampling(vector<float>& inputRaw, int32_t nInputLength, int32_t nUpSampleRate) {
  53. /**
  54. * @brief
  55. *
  56. */
  57. int nOutputLength = nInputLength * nUpSampleRate;
  58. vector<float> upSamplingRaw(nOutputLength, 0);
  59. for (int si = 0, di = 0; si < nInputLength - 1; di++) {
  60. float a = upSamplingRaw[di * nUpSampleRate] = (float)inputRaw[si];
  61. float b = upSamplingRaw[(di + 1) * nUpSampleRate] = (float)inputRaw[++si];
  62. float nSlope = (b - a) / nUpSampleRate;
  63. for (int i = 0; i < nUpSampleRate - 1; i++) {
  64. int baseIndex = (di * nUpSampleRate) + i;
  65. upSamplingRaw[baseIndex + 1] = upSamplingRaw[baseIndex] + nSlope;
  66. }
  67. }
  68. return upSamplingRaw;
  69. }
  70. vector<float> getwindowspoint(vector<float>& src, int off, int windows) {
  71. vector<float> ret(windows, 0);
  72. int retindex = 0;
  73. for (int i = off - windows / 2; i <= off + windows / 2; i++) {
  74. ret[retindex] = src[i];
  75. retindex++;
  76. }
  77. return ret;
  78. }
  79. /**
  80. * @brief 线
  81. *
  82. * @param val Y轴数据
  83. * @param size Y轴数据长度
  84. * @return float
  85. */
  86. void linear_least_squares(vector<float>& x, vector<float>& y, float& slope, float& intercept) {
  87. size_t n = x.size();
  88. double sumX = 0.0, sumY = 0.0, sumXY = 0.0, sumXX = 0.0;
  89. for (size_t i = 0; i < n; ++i) {
  90. sumX += x[i];
  91. sumY += y[i];
  92. sumXY += x[i] * y[i];
  93. sumXX += x[i] * x[i];
  94. }
  95. double xMean = sumX / n;
  96. double yMean = sumY / n;
  97. algo_assert(!feq((sumXX - n * xMean * xMean), 0, 0.0001), "sumXX - n * xMean * xMean == 0");
  98. slope = (sumXY - n * xMean * yMean) / (sumXX - n * xMean * xMean);
  99. intercept = yMean - slope * xMean;
  100. return;
  101. }
  102. void linear_least_squares(float* y, int size, float& slope, float& intercept) {
  103. vector<float> xpoint(size, 0);
  104. vector<float> ypoint(size, 0);
  105. for (size_t i = 0; i < size; i++) {
  106. xpoint[i] = i;
  107. ypoint[i] = y[i];
  108. }
  109. return linear_least_squares(xpoint, ypoint, slope, intercept);
  110. }
  111. void linear_least_squares_muti_windos(float* y, int size, vector<int> startx, int windowssize, float& slope, float& intercept) {
  112. vector<float> xpoint;
  113. vector<float> ypoint;
  114. // ZLOGI(TAG, "xxxxx%d", startx.size());
  115. for (size_t i = 0; i < startx.size(); i++) {
  116. int xstart = startx[i];
  117. for (size_t xindex = xstart; xindex < (xstart + windowssize); xindex++) {
  118. // ZLOGI(TAG, "xindex:%d y:%f", xindex, y[xindex]);
  119. xpoint.push_back(xindex);
  120. ypoint.push_back(y[xindex]);
  121. }
  122. }
  123. return linear_least_squares(xpoint, ypoint, slope, intercept);
  124. }
  125. vector<float> least_square_method_differentiate(vector<float>& inputRaw, int windows_size) {
  126. algo_assert(windows_size > 0, "windows_size <= 0");
  127. algo_assert(windows_size % 2 == 1, "windows_size is not odd");
  128. vector<float> differentiateRaw(inputRaw.size(), 0);
  129. vector<float> windowsRaw(windows_size, 0);
  130. int windows_size_half = (windows_size - 1) / 2;
  131. for (int index = windows_size_half; index < inputRaw.size() - windows_size_half; index++) {
  132. windowsRaw = getwindowspoint(inputRaw, index, windows_size);
  133. float intercept = 0;
  134. linear_least_squares(windowsRaw.data(), windows_size, differentiateRaw[index], intercept);
  135. }
  136. for (size_t i = 0; i < windows_size_half; i++) {
  137. differentiateRaw[i] = differentiateRaw[windows_size_half];
  138. }
  139. for (size_t i = inputRaw.size() - windows_size_half; i < inputRaw.size(); i++) {
  140. differentiateRaw[i] = differentiateRaw[inputRaw.size() - windows_size_half - 1];
  141. }
  142. return differentiateRaw;
  143. }
  144. vector<float> smooth_windows(vector<float>& inputRaw, int windows_size) {
  145. vector<float> smoothRaw(inputRaw.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. float sum = 0;
  149. for (int i = index - windows_size_half; i <= index + windows_size_half; i++) {
  150. sum += inputRaw[i];
  151. }
  152. smoothRaw[index] = sum / windows_size;
  153. }
  154. for (size_t i = 0; i < windows_size_half; i++) {
  155. smoothRaw[i] = smoothRaw[windows_size_half];
  156. }
  157. for (size_t i = inputRaw.size() - windows_size_half; i < inputRaw.size(); i++) {
  158. smoothRaw[i] = smoothRaw[inputRaw.size() - windows_size_half - 1];
  159. }
  160. return smoothRaw;
  161. }
  162. float find_avg_line(vector<float>& inputRaw) {
  163. float base_min = 500;
  164. float fsum = 0;
  165. int cnt = 0;
  166. int range = inputRaw.size();
  167. do {
  168. fsum = cnt = 0;
  169. for (int i = 1; i < range; i++) {
  170. if (inputRaw[i] < base_min) {
  171. fsum += inputRaw[i];
  172. cnt++;
  173. }
  174. }
  175. base_min = base_min + 50;
  176. } while (cnt < range - 15 * inputRaw.size() / 250);
  177. float fbase = fsum / cnt;
  178. return fbase;
  179. }
  180. /***********************************************************************************************************************
  181. * ALGO_IMPL *
  182. ***********************************************************************************************************************/
  183. int32_t findPeakTurnPoint(vector<float>& data, int32_t search_start, int32_t suggest_search_end) {
  184. int32_t search_end = 0;
  185. for (int32_t i = search_start; i < suggest_search_end; i++) {
  186. if (data[i] > m_cxt.agvline) {
  187. search_end = i;
  188. }
  189. }
  190. int32_t peakTurnPos = 0;
  191. float maxdiff2 = 0;
  192. for (int32_t i = search_start; i < search_end; i++) {
  193. if (m_cxt.diffX2[i] > maxdiff2) {
  194. maxdiff2 = m_cxt.diffX2[i];
  195. peakTurnPos = i;
  196. }
  197. }
  198. return peakTurnPos;
  199. }
  200. float computePeakArea(vector<float>& data, int32_t start, int32_t end) {
  201. float area = 0;
  202. for (int i = start; i < end; i++) {
  203. area += data[i];
  204. }
  205. float baselinearea = 0;
  206. baselinearea = (data[start] + data[end]) * abs(end - start) / 2;
  207. return abs(area - baselinearea);
  208. }
  209. void findpeak(vector<float>& data, int32_t search_start, int32_t search_end, PeakInfo& retpeak) {
  210. // find peak
  211. float max = 0;
  212. int peakpos = 0;
  213. float midpos = (search_end - search_start) / 2;
  214. for (int i = search_start; i < search_end; i++) {
  215. if (data[i] > max) {
  216. max = data[i];
  217. peakpos = i;
  218. }
  219. }
  220. if (max < m_cxt.agvline) {
  221. retpeak.find_peak = false;
  222. return;
  223. } else if (peakpos > midpos + 10) {
  224. retpeak.find_peak = false;
  225. return;
  226. } else if (peakpos < midpos - 10) {
  227. retpeak.find_peak = false;
  228. return;
  229. }
  230. // find_peak_start
  231. // 从pos向前找20个点,从低于均值线的坐标开始找,找到diff2的最大值
  232. retpeak.peak_pos = peakpos;
  233. retpeak.peak_start_pos = findPeakTurnPoint(data, peakpos - 20, peakpos);
  234. retpeak.peak_end_pos = findPeakTurnPoint(data, peakpos, peakpos + 20);
  235. retpeak.area = computePeakArea(data, retpeak.peak_start_pos, retpeak.peak_end_pos);
  236. // find_peak_end
  237. // 从pos向后找20个点,找到diff2的最大值
  238. }
  239. void a8k_opt_algo_process(vector<float>& ogigin_val, OptAlgoResult& result) {
  240. //
  241. vector<float> super = super_sampling(ogigin_val, ogigin_val.size(), 5);
  242. vector<float> subsample = sub_sampling(ogigin_val, 24);
  243. m_cxt.raw = subsample;
  244. m_cxt.avg = smooth_windows(subsample, 4);
  245. m_cxt.diff = least_square_method_differentiate(m_cxt.avg, 4); // 最小二乘法求曲线斜率集合
  246. m_cxt.diffX2 = least_square_method_differentiate(m_cxt.diff, 4); // 最小二乘法求曲线二次斜率集合
  247. m_cxt.agvline = find_avg_line(subsample);
  248. // findPeak
  249. for (size_t i = 0; i < 5; i++) {
  250. findpeak(m_cxt.avg, 20, 60, result.pin040);
  251. findpeak(m_cxt.avg, 60, 100, result.pin080);
  252. findpeak(m_cxt.avg, 100, 140, result.pin120);
  253. findpeak(m_cxt.avg, 140, 180, result.pin160);
  254. findpeak(m_cxt.avg, 180, 220, result.pin200);
  255. }
  256. }
  257. void A8kOptAlgoProcess(vector<float> ogigin_val, OptAlgoResult& result) { //
  258. a8k_opt_algo_process(ogigin_val, result);
  259. }
  260. /***********************************************************************************************************************
  261. * T_A8kOptAlgoPreProcess *
  262. ***********************************************************************************************************************/
  263. int32_t t_detector_gain_to_raw_gain(float scan_gain) {
  264. // opamp_gain = (((100.0 * (float) scan_gain_raw) / 255) + 2.4) / 4.7;
  265. int32_t scan_gain_raw = 0;
  266. scan_gain_raw = (scan_gain * 4.7 - 2.4) * 256. / 100. + 0.5;
  267. if (scan_gain_raw < 1) scan_gain_raw = 1;
  268. if (scan_gain_raw > 255) scan_gain_raw = 255;
  269. return scan_gain_raw;
  270. }
  271. float t_detector_raw_gain_to_gain(int32_t gain) {
  272. float scan_gain = 0;
  273. scan_gain = (((100.0 * (float)gain) / 256) + 2.4) / 4.7;
  274. return scan_gain;
  275. }
  276. void T_A8kOptAlgoPreProcess(vector<float> ogigin_val, int32_t now_scan_gain, int32_t expectResultRangeStart, int32_t expectResultRangeEnd, OptAlgoPreProcessResult& result) {
  277. int32_t adcgoal = expectResultRangeEnd;
  278. int32_t maxadc = ogigin_val[0];
  279. result.scanAgain = false;
  280. result.suggestScanGain = now_scan_gain;
  281. for (int32_t i = 1; i < ogigin_val.size(); i++) {
  282. if (maxadc < ogigin_val[i]) {
  283. maxadc = ogigin_val[i];
  284. }
  285. }
  286. if (maxadc > expectResultRangeStart) {
  287. result.scanAgain = false;
  288. return;
  289. }
  290. float nowgain = t_detector_raw_gain_to_gain(now_scan_gain);
  291. float gain_adjust = 0;
  292. if (maxadc != 0) {
  293. gain_adjust = nowgain * ((float)adcgoal / (float)maxadc);
  294. } else {
  295. gain_adjust = nowgain;
  296. }
  297. result.suggestScanGain = t_detector_gain_to_raw_gain(gain_adjust);
  298. result.scanAgain = true;
  299. }
  300. /***********************************************************************************************************************
  301. * F_A8kOptAlgoPreProcess *
  302. ***********************************************************************************************************************/
  303. float f_detector_raw_gain_to_gain(int32_t gain) {
  304. float scan_gain = 0;
  305. scan_gain = (((100. / 256.) * (float)gain) + 0.125) / 2.15 + 1.;
  306. return scan_gain;
  307. }
  308. int32_t f_detector_gain_to_raw_gain(float scan_gain) {
  309. // int32_t scan_gain = (((100. / 256.) * (float)scan_gain_raw) + 0.125) / 2.15 + 1.;
  310. int32_t scan_gain_raw = 0;
  311. scan_gain_raw = ((scan_gain - 1.0) * 2.15 - 0.125) * 255. / 100. + 0.5;
  312. if (scan_gain_raw < 1) scan_gain_raw = 1;
  313. if (scan_gain_raw > 255) scan_gain_raw = 255;
  314. return scan_gain_raw;
  315. }
  316. void F_A8kOptAlgoPreProcess(vector<float> ogigin_val, int32_t now_scan_gain, int32_t expectResultRangeStart, int32_t expectResultRangeEnd, OptAlgoPreProcessResult& result) {
  317. int32_t adcgoal = expectResultRangeEnd;
  318. int32_t maxadc = ogigin_val[0];
  319. result.scanAgain = false;
  320. result.suggestScanGain = now_scan_gain;
  321. for (int32_t i = 1; i < ogigin_val.size(); i++) {
  322. if (maxadc < ogigin_val[i]) {
  323. maxadc = ogigin_val[i];
  324. }
  325. }
  326. if (maxadc > expectResultRangeStart) {
  327. result.scanAgain = false;
  328. return;
  329. }
  330. float nowgain = f_detector_raw_gain_to_gain(now_scan_gain);
  331. float gain_adjust = 0;
  332. if (maxadc != 0) {
  333. gain_adjust = nowgain * ((float)adcgoal / (float)maxadc);
  334. } else {
  335. gain_adjust = nowgain;
  336. }
  337. result.suggestScanGain = f_detector_gain_to_raw_gain(gain_adjust);
  338. result.scanAgain = true;
  339. }
  340. } // namespace a8k_opt_algo