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.

451 lines
16 KiB

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