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.

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