用该传感器判断是食指还是中指还是其他指头。& w5 x: \- k& ]
+ e5 f% j8 ?# {对于我们的三个指头(5个也好)本质上是一种多分类网络问题,我们将输入信号划分成不同的分类。5 M$ u! I. p$ c) D, J
小拇指
8 O }: o% G& [9 ^大拇指
. k9 ], @/ I, t6 o; l中指(后来用了食指方便)
- n; t' ?0 @6 b3 r3 G2 _没有指头(空置)- a& s t! |; {5 F# h) D
3 ]1 R6 a7 {/ }% G( b
因此我们利用多分类神经网络来实现判断功能。
# g9 k. ]: L; `7 @* m9 B9 U5 o' e x! P8 z6 H( l! \& u$ A$ p, t
- 7 `0 x! Z8 {1 a# V$ I! o
- int i = 0;
6 b" |; K5 B0 ~: ` - void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)9 p& l @/ g, l7 H1 ~
- {
/ K& `1 }6 I4 `- N - maxim_max30102_read_fifo(&red,&ir);5 J) }( I- I8 ?! a' W, f
- printf("%ld ",ir);
, G. D; y, k2 {3 \, w8 u1 f - i++;8 [ A# }( \+ }! J' T/ x2 a* q: h
- if(i==128)
* d; U8 ?5 S e - {+ S* q+ N V7 [5 K, w }; c% Z( n
- i=0;
" u3 o4 Z- t2 R3 J0 q - printf("\n");8 M- k9 ~2 I, V# {2 Z0 m. p# e
- }
1 P2 C- b1 ~0 {! k! l - }
复制代码
& X% z2 T/ C7 U, \$ I3 D信号的输入部分则和上期一样,100HZ的采样率,128的采样长度。% S a9 v8 k6 F5 A. B
* Y% S7 Z; }- d( \
1 Y7 }- {4 u w1 E1 P, G$ s2 a3 i% W4 _& H
创建一个n-Class n分类神经网络。
2 e: [( d" H% T- `4 M9 Q
; F6 S( Z8 n, i: k3 T5 U' V7 I) o" Y
- y2 U# o+ @3 j/ Y7 {6 s
2 v. _3 y3 k! c( Y" _其他设置都和上期的保持一样,使用通用一轴传感器。
5 M8 `4 M9 d c: z8 d5 l
+ h1 }+ M; C% m$ p- ]! i8 W
2 b1 C9 k; t# e5 Q5 u
/ O1 j x3 p$ O
但是信号输入的地方,我们利用串口导入各个类别的数据(这里是不同的指头)8 c+ m% ^# i) N, @% D- x- G+ v
2 k$ w( g- J; O+ _+ \5 c
& c" v3 L' M5 x( B
O9 U0 o! u w; a( M* i需要注意的是,这里的标签即代表着我们的分类,不像之前那样子可以一个类别下面可以使用多组数据。# `0 K1 u! O8 o2 y
3 P: @- s. `7 c: [
6 @; I8 U3 V$ g
+ q* B& B5 ]% W* s: X训练我们的模型,这里可以选择我们的分类(其实这里我觉得要是把某组数据能添加到某个分类就好了,这里让我研究一下)。
0 ^2 P; w8 q, v1 k. l; I* F4 p9 Z) b3 F( ^) B2 J/ x
/ q+ N7 @2 |$ s6 C2 c7 F. F
2 h$ x U6 y# R+ t& K u
训练好我们的模型,这里可以关注各指标。! K6 Y) _. E2 k5 Y
$ U6 W& y! @) f接着就是验证我们的模型,验证的过程可以参考文章开头的视频。
- _2 ~* n* g2 V7 N8 U5 Y) V+ e# L; n3 v$ U$ X
! O% d% |5 w2 c/ Q
8 S' A+ V* d' ]& ]0 g0 ~! [% u% p部署完我们的模型之后,查看生成的.ZIP文件,其中相比于异常识别多了一个knowledge的头文件。
" [) q$ y6 P3 k8 N" u/ Z& s
* _+ Y! m; J" L [4 E7 Z$ \. ~
/ Q- B' d" `! j, Y) B# v1 p
& p% s; Z# x: ^4 r! P; B这里我们需要libneai.a以及两个.h文件
, |* F; q; k* `
! N a+ [& _; {STM32中用机器学习实现正确率99.95%的心率异常检测!) G8 t% K) x* L- \1 F3 H
* a- d$ f+ w$ z) f- Y怎么导入文件请查看这篇文章。& _& N' r! n$ o+ k0 {
. X- C' p. v) v
$ _3 [5 l3 m$ y5 q1 H, a& m3 g
初始化函数中,我们需要导入一个数组,这个数组就定义在knowledge.h这个文件中。
; {, `* Y: A# Q: m5 X
/ M: w: {) a& M7 _; ?
" ~' Y |# [$ i( B
+ E0 ]+ `' ?( f$ c. ~ c: n4 u- neai_classification_init(knowledge);
复制代码 . R0 ~$ M1 I5 O' ~! S% Z l( l+ `
初始化的时候,需要以这个数组为参数。
' c3 z5 t, T! o6 h- p% p2 ]
; t3 r) n, h: i! Q& K& S, e之后我们在定时器中,采集到128个数据之后进行预测。
% E6 J! j3 |2 q" r/ B* K% u
" P. F* s- q* x, M" Q; \& \$ X- float IRD[128];. A5 m w4 o. X- c* a/ p5 ~! p0 E
- int i = 0;
" T/ T: {1 B# m: b2 n0 L6 [* }/ ] - int LeranTime= 0;1 u/ d1 h/ R+ D$ F3 z
- const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name1 w; a' e& j" O6 G+ D- r
- "unknown",
# [0 l( U( Q* R' M8 N - "zhongzhi",8 M U, w0 {7 l4 k5 }
- "Error",5 v0 |$ B5 y! {6 ~! N
- "xiaomuzhi2",
8 Y9 { z4 Q1 F/ V! ~/ P% ~ - "damuzhi",
8 N( X; b' D0 W4 m" b' |/ A - };' A& j( w2 C* K0 F2 n4 e
- float Output[4];
8 i1 e$ Y. h1 ~+ c6 \ - void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
( ]" O( s! B7 A2 k% n2 h - {& e2 t S. B' f3 @3 ~9 Q
- uint16_t yuce;
/ H- ]$ ]* D) l# Q2 N) E - maxim_max30102_read_fifo(&red,&ir);
: m9 r. L( T+ ?" r" M: c, B* `. o - IRD = ir;
! m* @3 |4 Y% T - i++;6 Q3 s- f# ]" }( M1 c0 P9 p
- //printf("%d ",ir);! h0 P% g4 Z* E$ P) t0 p V. b- L: N* H. p
- if(i==128)7 }6 H' G, D2 L8 Q' p
- {. S; K+ t8 p0 z2 E" N' f4 w8 ? N
" c2 c2 ?' h3 O0 G
8 i2 d7 w: L3 p j0 P1 V2 Q- neai_classification(IRD,Output,&yuce);
& j' Y) o7 l* m# A k( H - 5 Y2 r! n7 B# M$ z9 o5 h
- 1 b& `% B' C, k" E
- printf("\n\n\n");
* x3 Q8 D% j* y/ ]# W: H - printf("zhongzhi:%.2f\r\n",Output[0]);+ I( T W* i. e y5 T# @
- printf("Error:%.2f\r\n",Output[1]);4 O" y: z$ ?1 l# m2 g$ D
- printf("xiaomuzhi:%.2f\r\n",Output[2]);) Y, ?: u$ |# X0 ~) u- Q5 c
- printf("damuzhi:%.2f\r\n",Output[3]);. M$ |2 O! |. T- e$ m; ^. k4 W6 }
- LeranTime++;
9 R# E2 o$ f# g4 e( T1 }4 h - i = 0;$ L/ f7 E a# t; [
- }- v: t+ r1 u0 `% h0 q
- }
复制代码
8 T) j2 ~ w) Z" o5 }4 t/ `5 j- p这里的 预测函数有三个参数,第一个参数是输入数组,第二参数是输出数组,输出数组中包含着对于各个分类的参数预测值,第三个参数输入一个指针,这个指针会指向预测最大值的索引。! ~2 E7 L# h. ]& C+ i+ C
1 S9 G( Z! w+ v8 ~- N
" |$ t. e( z1 `) o, s; i0 C7 L* u
5 I7 p1 F& I, z* G烧入我们的代码,可以看到,空置的时候,Error的预测值是最大的。
. m2 N) V4 F7 ]+ a1 }" F' Q6 C" f" C3 z+ \# w
/ P& v! o/ g# t- ^) j1 r
. b* C: P, n+ a9 f" c' i1 Z当我们放上中指的时候,检测到中指的概率是最大的。( e4 W/ }, ]. f0 X. j: c3 w
5 Y9 c; g! ~# Z" }4 ~& f' S" U
: M/ `! Z9 I/ X3 O8 T7 S- b1 m6 s n: t$ s5 O, G e! B" V
小拇指也是可以正常的检测。
5 m" {* J4 F. H% Y2 C; |
3 a7 z3 t4 _* Y! n6 F- v% ~( J6 U! g# G6 T. N) `2 W% a/ P
/ G9 b; K+ ~ y- S7 P转载自:电路小白
4 ?* Q. n1 f7 N1 }& I如有侵权请联系删除6 y, f# F P. |7 E5 e( |+ M! ]
2 d3 }' R* x9 `" I9 t2 u
: _5 i- T S1 E( f- C
: }- ?# ^/ l/ p
/ C% L% G( [. N8 Z$ r4 o |