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.

434 lines
14 KiB

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