emg_util.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <string.h>
  5. #include <float.h>
  6. #include "emg_util.h"
  7. #include <assert.h>
  8. /**
  9. * 閲嶇疆闄锋尝婊ゆ尝鍣ㄧ姸鎬�
  10. * 鍔熻兘锛氬皢婊ゆ尝鍣ㄧ殑杈撳叆杈撳嚭鍘嗗彶鍊兼竻闆讹紝纭繚鏂扮殑婊ゆ尝杩囩▼涓嶅彈涔嬪墠鐘舵�佸奖鍝�
  11. * 鍙傛暟锛歠ilter - 鎸囧悜闄锋尝婊ゆ尝鍣ㄧ粨鏋勪綋鐨勬寚閽�
  12. */
  13. void notchFilterReset(NotchFilter *filter) {
  14. // 閲嶇疆杈撳叆鍘嗗彶鍊硷紙x1涓哄墠涓�鏃跺埢杈撳叆锛寈2涓哄墠涓ゆ椂鍒昏緭鍏ワ級
  15. filter->x1 = filter->x2 = 0.0;
  16. // 閲嶇疆杈撳嚭鍘嗗彶鍊硷紙y1涓哄墠涓�鏃跺埢杈撳嚭锛寉2涓哄墠涓ゆ椂鍒昏緭鍑猴級
  17. filter->y1 = filter->y2 = 0.0;
  18. }
  19. /**
  20. * 闄锋尝婊ゆ尝鍣ㄥ鐞嗗崟涓牱鏈�
  21. * 鍔熻兘锛氬鍗曚釜杈撳叆鏁版嵁杩涜婊ゆ尝澶勭悊锛屽熀浜嶪IR婊ゆ尝鍣ㄥ樊鍒嗘柟绋�
  22. * 鍙傛暟锛�
  23. * filter - 鎸囧悜闄锋尝婊ゆ尝鍣ㄧ粨鏋勪綋鐨勬寚閽堬紙鍖呭惈绯绘暟鍜屽巻鍙茬姸鎬侊級
  24. * input - 褰撳墠杈撳叆鐨勯噰鏍锋暟鎹�
  25. * 杩斿洖鍊硷細婊ゆ尝鍚庣殑杈撳嚭鏁版嵁
  26. */
  27. double notchFilterProcess(NotchFilter *filter, double input) {
  28. // 鏍规嵁IIR婊ゆ尝鍣ㄥ樊鍒嗘柟绋嬭绠楀綋鍓嶈緭鍑�
  29. // 鍏紡锛歽[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
  30. double output =
  31. filter->b[0] * input + // 褰撳墠杈撳叆椤�
  32. filter->b[1] * filter->x1 + // 鍓嶄竴鏃跺埢杈撳叆椤�
  33. filter->b[2] * filter->x2 - // 鍓嶄袱鏃跺埢杈撳叆椤�
  34. filter->a[1] * filter->y1 - // 鍓嶄竴鏃跺埢杈撳嚭鍙嶉椤�
  35. filter->a[2] * filter->y2; // 鍓嶄袱鏃跺埢杈撳嚭鍙嶉椤�
  36. // 鏇存柊杈撳叆鍘嗗彶鐘舵�侊紙绉讳綅鎿嶄綔锛屼繚瀛樻渶鏂扮殑涓や釜杈撳叆鍊硷級
  37. filter->x2 = filter->x1; // 鍓嶄袱鏃跺埢 = 鍓嶄竴鏃跺埢
  38. filter->x1 = input; // 鍓嶄竴鏃跺埢 = 褰撳墠杈撳叆
  39. // 鏇存柊杈撳嚭鍘嗗彶鐘舵�侊紙绉讳綅鎿嶄綔锛屼繚瀛樻渶鏂扮殑涓や釜杈撳嚭鍊硷級
  40. filter->y2 = filter->y1; // 鍓嶄袱鏃跺埢 = 鍓嶄竴鏃跺埢
  41. filter->y1 = output; // 鍓嶄竴鏃跺埢 = 褰撳墠杈撳嚭
  42. return output;
  43. }
  44. /**
  45. * 闄锋尝婊ゆ尝鍣ㄥ鐞嗘暟缁勬暟鎹�
  46. * 鍔熻兘锛氬涓�鏁存杈撳叆鏁版嵁杩涜杩炵画婊ゆ尝锛岄�愪釜鏍锋湰璋冪敤鍗曟牱鏈鐞嗗嚱鏁�
  47. * 鍙傛暟锛�
  48. * filter - 鎸囧悜闄锋尝婊ゆ尝鍣ㄧ粨鏋勪綋鐨勬寚閽�
  49. * input - 鎸囧悜杈撳叆鏁版嵁鏁扮粍鐨勬寚閽�
  50. * output - 鎸囧悜杈撳嚭鏁版嵁鏁扮粍鐨勬寚閽堬紙闇�鎻愬墠鍒嗛厤鍐呭瓨锛�
  51. * length - 杈撳叆/杈撳嚭鏁版嵁鐨勯暱搴︼紙鏍锋湰鏁帮級
  52. */
  53. void notchFilterProcessArray(NotchFilter *filter, const double *input, double *output, int length) {
  54. // 閬嶅巻杈撳叆鏁扮粍锛岄�愪釜鏍锋湰杩涜婊ゆ尝
  55. int i = 0;
  56. for (i = 0; i < length; i++) {
  57. output[i] = notchFilterProcess(filter, input[i]);
  58. }
  59. }
  60. // 搴旂敤涓�涓弻浜岄樁鑺�
  61. double biquad_filter(double input, const double *sos_row, BiquadState *state) {
  62. double b0 = sos_row[0];
  63. double b1 = sos_row[1];
  64. double b2 = sos_row[2];
  65. double a1 = sos_row[4]; // 娉ㄦ剰绱㈠紩锛氱5涓槸 a1
  66. double a2 = sos_row[5]; // 绗�6涓槸 a2
  67. double output = b0 * input + b1 * state->x1 + b2 * state->x2
  68. - a1 * state->y1 - a2 * state->y2;
  69. state->x2 = state->x1;
  70. state->x1 = input;
  71. state->y2 = state->y1;
  72. state->y1 = output;
  73. return output;
  74. }
  75. // 鍙嶈浆鏁扮粍
  76. void reverse_array(double *data, int n) {
  77. int i = 0;
  78. for (i = 0; i < n / 2; i++) {
  79. double temp = data[i];
  80. data[i] = data[n - 1 - i];
  81. data[n - 1 - i] = temp;
  82. }
  83. }
  84. /**
  85. * @brief 闆剁浉浣嶅甫閫氭护娉� (绫讳技 MATLAB filtfilt)
  86. * @param indata: 杈撳叆淇″彿鏁扮粍
  87. * @param outdata: 杈撳嚭淇″彿鏁扮粍锛堟护娉㈠悗缁撴灉锛�
  88. * @param len: 淇″彿闀垮害
  89. * @param sos: 2x6 鐨勪簩闃惰妭绯绘暟鐭╅樀
  90. * @param num_stages: 鑺傛暟锛堣繖閲屾槸 2锛�
  91. */
  92. void filtfilt_sos(const double *indata, double *outdata, int len, const double sos[2][6], int num_stages) {
  93. // === 鎵�鏈夊彉閲忓0鏄庣Щ鍒伴《閮� ===
  94. double *temp;
  95. BiquadState *states;
  96. int i, j;
  97. double sample;
  98. temp = (double *)malloc(len * sizeof(double));
  99. states = (BiquadState *)calloc(num_stages, sizeof(BiquadState));
  100. // === 鍓嶅悜婊ゆ尝 ===
  101. for (i = 0; i < len; i++) {
  102. sample = indata[i];
  103. for (j = 0; j < num_stages; j++) {
  104. sample = biquad_filter(sample, sos[j], &states[j]);
  105. }
  106. temp[i] = sample;
  107. }
  108. memset(states, 0, num_stages * sizeof(BiquadState));
  109. reverse_array(temp, len);
  110. for (i = 0; i < len; i++) {
  111. sample = temp[i];
  112. for (j = 0; j < num_stages; j++) {
  113. sample = biquad_filter(sample, sos[j], &states[j]);
  114. }
  115. temp[i] = sample;
  116. }
  117. reverse_array(temp, len);
  118. memcpy(outdata, temp, len * sizeof(double));
  119. free(temp);
  120. free(states);
  121. }
  122. // 蹇�熸帓搴忥紙鍗囧簭锛�
  123. void quicksort(double *arr, int n) {
  124. // 鎵�鏈夊彉閲忕Щ鍒伴《閮�
  125. double pivot, temp;
  126. int i, j;
  127. if (n <= 1) return;
  128. pivot = arr[n / 2];
  129. i = 0;
  130. j = n - 1;
  131. while (i <= j) {
  132. while (arr[i] < pivot) i++;
  133. while (arr[j] > pivot) j--;
  134. if (i <= j) {
  135. temp = arr[i]; arr[i] = arr[j]; arr[j] = temp;
  136. i++; j--;
  137. }
  138. }
  139. quicksort(arr, j + 1);
  140. if (i < n) quicksort(arr + i, n - i);
  141. }
  142. // 璁$畻涓綅鏁�
  143. double median(double *arr, int n) {
  144. // 鎵�鏈夊彉閲忕Щ鍒伴《閮�
  145. double *copy;
  146. double med;
  147. int i;
  148. copy = (double*)malloc(n * sizeof(double));
  149. if (!copy) return 0.0; // 鍐呭瓨鍒嗛厤澶辫触
  150. for (i = 0; i < n; i++) {
  151. copy[i] = arr[i];
  152. }
  153. quicksort(copy, n);
  154. if (n % 2 == 1) {
  155. med = copy[n/2];
  156. } else {
  157. med = (copy[n/2-1] + copy[n/2]) * 0.5;
  158. }
  159. free(copy);
  160. return med;
  161. }
  162. /**
  163. * 瀵圭О绱㈠紩鏄犲皠鍑芥暟锛岀敤浜庢ā鎷烳ATLAB涓殑'sym'妯″紡杈圭晫寤舵嫇銆�
  164. *
  165. * @param i 褰撳墠璁$畻鐨勭储寮曚綅缃��
  166. * @param N 淇″彿闀垮害銆�
  167. * @return 鏄犲皠鍚庣殑绱㈠紩浣嶇疆銆�
  168. */
  169. int symmetric_index(int i, int N) {
  170. while (i < 0) { // 濡傛灉绱㈠紩灏忎簬0锛屽垯缈昏浆鍒版鍖洪棿
  171. i = -i - 1;
  172. }
  173. while (i >= N) { // 濡傛灉绱㈠紩瓒呭嚭淇″彿闀垮害锛屽垯闀滃儚鍥炰俊鍙峰唴
  174. i = 2 * N - i - 1;
  175. }
  176. return i;
  177. }
  178. // 鍗风Н + 涓嬮噰鏍凤紙瀵圭О杈圭晫锛�
  179. void dwt_conv_down(const double *input, int len_in, const double *filt, int len_filt, double *output) {
  180. // 鎵�鏈夊彉閲忕Щ鍒伴《閮�
  181. int out_len;
  182. int i, j, center, n, idx;
  183. double sum;
  184. out_len = (len_in + 1) / 2; // 淇闀垮害
  185. for (i = 0; i < out_len; i++) {
  186. center = 2 * i;
  187. sum = 0.0;
  188. for (j = 0; j < len_filt; j++) {
  189. n = center - (len_filt - 1)/2 + j;
  190. idx = symmetric_index(n, len_in);
  191. sum += input[idx] * filt[len_filt - 1 - j];
  192. }
  193. output[i] = sum;
  194. }
  195. }
  196. // 涓婇噰鏍� + 鍗风Н锛堥噸鏋勶級
  197. void idwt_up_conv(const double *input, int len_in, const double *filt, int len_filt, double *output, int len_out) {
  198. // 鎵�鏈夊彉閲忕Щ鍒伴《閮�
  199. int i, j, pos_in, pos_out;
  200. int radius;
  201. memset(output, 0, len_out * sizeof(double));
  202. radius = (len_filt - 1) / 2; // 3 for sym4
  203. for (i = 0; i < len_in; i++) {
  204. pos_in = 2 * i;
  205. for (j = 0; j < len_filt; j++) {
  206. pos_out = pos_in + j - radius;
  207. if (pos_out >= 0 && pos_out < len_out) {
  208. output[pos_out] += input[i] * filt[len_filt - 1 - j];
  209. }
  210. }
  211. }
  212. }
  213. // 杞槇鍊煎嚱鏁�
  214. void soft_threshold(double *vec, int n, double thr) {
  215. int i;
  216. for (i = 0; i < n; i++) {
  217. if (vec[i] > thr)
  218. vec[i] -= thr;
  219. else if (vec[i] < -thr)
  220. vec[i] += thr;
  221. else
  222. vec[i] = 0.0;
  223. }
  224. }
  225. void denoise_emg_wavelab(double *data, int N, double fs, double *denoised) {
  226. // === 鎵�鏈夊彉閲忓0鏄庣Щ鍒伴《閮� ===
  227. const int levels = 6;
  228. double *work, *tmp_low, *tmp_high;
  229. double *details[6];
  230. int det_len[6];
  231. int current_len;
  232. int lev, out_len;
  233. double *abs_d6;
  234. double med_abs, sigma, thr;
  235. int i;
  236. // 鍒嗛厤鍐呭瓨
  237. work = (double*)malloc(N * sizeof(double));
  238. tmp_low = (double*)malloc(N * sizeof(double));
  239. tmp_high = (double*)malloc(N * sizeof(double));
  240. if (!work || !tmp_low || !tmp_high) {
  241. // 閿欒澶勭悊
  242. if (work) free(work);
  243. if (tmp_low) free(tmp_low);
  244. if (tmp_high) free(tmp_high);
  245. return;
  246. }
  247. memcpy(work, data, N * sizeof(double));
  248. current_len = N;
  249. // === 1. 澶氱骇灏忔尝鍒嗚В ===
  250. for (lev = 0; lev < levels; lev++) {
  251. out_len = (current_len + 1) / 2;
  252. dwt_conv_down(work, current_len, sym4_h, 8, tmp_low);
  253. dwt_conv_down(work, current_len, sym4_g, 8, tmp_high);
  254. details[lev] = (double*)malloc(out_len * sizeof(double));
  255. det_len[lev] = out_len;
  256. memcpy(details[lev], tmp_high, out_len * sizeof(double));
  257. memcpy(work, tmp_low, out_len * sizeof(double));
  258. current_len = out_len;
  259. }
  260. // === 2. 鍣0浼拌 ===
  261. abs_d6 = (double*)malloc(det_len[5] * sizeof(double));
  262. for (i = 0; i < det_len[5]; i++) {
  263. abs_d6[i] = fabs(details[5][i]);
  264. }
  265. med_abs = median(abs_d6, det_len[5]);
  266. sigma = med_abs / 0.6745;
  267. // thr = sigma * sqrt(2.0 * log((double)N));
  268. thr = sigma * sqrt(2.0 * log((double)N));
  269. printf("Threshold: %.15f sigma:%.15f\n", thr,sigma);
  270. free(abs_d6);
  271. // === 3. 杞槇鍊� ===
  272. for (lev = 0; lev < levels; lev++) {
  273. soft_threshold(details[lev], det_len[lev], thr);
  274. }
  275. // === 4. 閲嶆瀯 ===
  276. memcpy(tmp_low, work, current_len * sizeof(double));
  277. for (lev = levels - 1; lev >= 0; lev--) {
  278. out_len = (lev == 5) ? N : det_len[lev] * 2;
  279. idwt_up_conv(tmp_low, current_len, sym4_h, 8, work, out_len);
  280. idwt_up_conv(details[lev], det_len[lev], sym4_g, 8, tmp_high, out_len);
  281. for (i = 0; i < out_len; i++) {
  282. work[i] += tmp_high[i];
  283. }
  284. memcpy(tmp_low, work, out_len * sizeof(double));
  285. current_len = out_len;
  286. }
  287. memcpy(denoised, work, N * sizeof(double));
  288. free(work);
  289. free(tmp_low);
  290. free(tmp_high);
  291. for (i = 0; i < levels; i++) {
  292. if (details[i]) free(details[i]);
  293. }
  294. }
  295. void remove_dc_offset(const double* src, double* dest, int n) {
  296. double sum, mean;
  297. int i;
  298. if (n <= 0) return;
  299. sum = 0.0;
  300. for (i = 0; i < n; i++) {
  301. sum += src[i];
  302. }
  303. mean = sum / n;
  304. for (i = 0; i < n; i++) {
  305. dest[i] = src[i] - mean;
  306. }
  307. }
  308. // ================= 涓诲鐞嗗嚱鏁� =================
  309. void emg_denoised(double *emg_raw, int length, int fs, double *emg_denoised) {
  310. // === 鎵�鏈夊彉閲忓0鏄庣Щ鍒伴《閮� ===
  311. double *temp1;
  312. double *temp2;
  313. NotchFilter filter;
  314. int i;
  315. // 楠岃瘉杈撳叆鏈夋晥鎬�
  316. if (!emg_raw || length <= 0 || !emg_denoised) {
  317. fprintf(stderr, "閿欒锛氭棤鏁堣緭鍏ュ弬鏁癨n");
  318. return;
  319. }
  320. // 鍒嗛厤涓存椂鍐呭瓨
  321. temp1 = (double *)malloc(length * sizeof(double));
  322. temp2 = (double *)malloc(length * sizeof(double));
  323. if (!temp1 || !temp2) {
  324. fprintf(stderr, "閿欒锛氬唴瀛樺垎閰嶅け璐n");
  325. if (temp1) free(temp1);
  326. if (temp2) free(temp2);
  327. return;
  328. }
  329. // 鍒濆鍖栧唴瀛�
  330. memset(temp1, 0, length * sizeof(double));
  331. memset(temp2, 0, length * sizeof(double));
  332. // 鍒濆鍖栭櫡娉㈡护娉㈠櫒锛堜娇鐢ㄩ瀹氫箟绯绘暟锛�
  333. for (i = 0; i < 3; i++) {
  334. filter.b[i] = NOTCH_B[i];
  335. filter.a[i] = NOTCH_A[i];
  336. }
  337. // 閲嶇疆婊ゆ尝鍣ㄧ姸鎬�
  338. notchFilterReset(&filter);
  339. // 鍘婚櫎鐩存祦鍋忕疆
  340. remove_dc_offset(emg_raw, temp2, length);
  341. // 闄锋尝婊ゆ尝锛�50Hz 鎴� 60Hz锛�
  342. notchFilterProcessArray(&filter, temp2, temp1, length);
  343. // 鍙屽悜浜岄樁鑺傛护娉紙闆剁浉浣嶆护娉級
  344. filtfilt_sos(temp1, emg_denoised, length, sos, 2);
  345. // 灏忔尝鍘诲櫔锛堜娇鐢� sym4锛�
  346. denoise_emg_wavelab(emg_denoised, length, fs, temp2);
  347. // 灏嗘渶缁堢粨鏋滃鍒跺埌杈撳嚭
  348. for (i = 0; i < length; i++) {
  349. emg_denoised[i] = temp2[i];
  350. }
  351. // 娓呯悊鎵�鏈変复鏃跺唴瀛�
  352. free(temp1);
  353. free(temp2);
  354. }
  355. /*
  356. #define DATA_SIZE 2000 // 瀹氫箟鏁版嵁閲忓ぇ灏�
  357. int main1() {
  358. // 1. 鎵撳紑杈撳叆鏂囦欢
  359. const char* input_filename = "E:/workspace/C++c/emg/emg_row2000.txt";
  360. const char* output_filename = "E:/workspace/C++c/emg/emg_denoised_row2000.txt";
  361. system("chcp 65001 > nul");
  362. setlocale(LC_ALL, ".UTF8");
  363. FILE *input_file = fopen(input_filename, "r");
  364. if (input_file == NULL) {
  365. perror("鎵撳紑杈撳叆鏂囦欢澶辫触");
  366. return EXIT_FAILURE;
  367. }
  368. // 2. 鍔ㄦ�佸垎閰嶅唴瀛樺瓨鍌ㄦ暟鎹�
  369. // double *data = (double*)malloc(DATA_SIZE * sizeof(double));
  370. double inputdata[2000]={0};
  371. double outputdata[2000]={0};
  372. if (inputdata == NULL) {
  373. perror("鍐呭瓨鍒嗛厤澶辫触");
  374. fclose(input_file);
  375. return EXIT_FAILURE;
  376. }
  377. // 3. 璇诲彇鏁版嵁骞堕獙璇佸畬鏁存��
  378. int valid_count = 0;
  379. for (int i = 0; i < DATA_SIZE; i++) {
  380. if (fscanf(input_file, "%lf", &inputdata[i]) != 1) {
  381. fprintf(stderr, "绗� %d 涓暟鎹В鏋愬け璐ワ紙鍙兘鏍煎紡閿欒锛塡n", i + 1);
  382. break;
  383. }
  384. valid_count++;
  385. }
  386. fclose(input_file); // 鍏抽棴杈撳叆鏂囦欢
  387. // 4. 鎵撳嵃鏁版嵁锛堝彲閫夛細闄愬埗鎵撳嵃鍓�10涓級
  388. emg_denoised(inputdata,2000,1000,outputdata);
  389. // printf("馃搳 鏁版嵁棰勮锛堝墠10涓級:\n");
  390. // for (int i = 1000; i < 1100 && i < valid_count; i++) {
  391. // printf("Data[%d] = %f\n", i, outputdata[i]);
  392. // }
  393. // 5. 淇濆瓨鏁版嵁鍒拌緭鍑烘枃浠�
  394. FILE *output_file = fopen(output_filename, "w");
  395. if (output_file == NULL) {
  396. perror("鍒涘缓杈撳嚭鏂囦欢澶辫触");
  397. // free(data);
  398. return EXIT_FAILURE;
  399. }
  400. for (int i = 0; i < valid_count; i++) {
  401. fprintf(output_file, "%.15g\n", outputdata[i]); // 楂樼簿搴︿繚瀛�
  402. }
  403. fclose(output_file);
  404. printf("datasave output.txt锛堝叡 %d 涓湁鏁堝�硷級\n", valid_count);
  405. // 6. 閲婃斁鍐呭瓨
  406. // free(data);
  407. return EXIT_SUCCESS;
  408. }
  409. */