엣지 임펄스와 아두이노 나노 33 BLE 센스로 만드는 정밀 ECG 분석기
부품 및 소모품
| 아두이노 나노 33 BLE 센스 | 1개 |
| SparkFun 싱글 리드 심박 모니터 - AD8232 | 1개 |
| ElectroPeak 0.96" OLED 64x128 디스플레이 모듈 | 1개 |
필요한 도구 및 기계
- 납땜 인두 (일반)
- 납 와이어, 무연
- 10개 점퍼 와이어 키트, 5cm 길이
앱 및 온라인 서비스
- Edge Impulse Studio
- MATLAB
- 아두이노 IDE
- Microsoft Visual Studio 2017
프로젝트 소개
급성 심장마비 및 사망률 증가 - 커지는 우려
지난 10년간 급성 심장마비 사망자가 엄청나게 증가했습니다.
특히 인도 같은 개발도상국에서는 유전적 요인과 생활 습관 외에도 농촌 지역의 의료 자원 부족이 심장마비 치사율의 주요 원인입니다.

기술로 이 글로벌 문제 해결에 기여
Edge Impulse로 구동되는 TinyML 애플리케이션을 개발하여 주머니에 들어가는 미니 진단 ECG 분석기 장치를 만들었습니다. 이 장치는 클라우드 연결 없이 독립적으로 심장 질환을 진단할 수 있습니다.
시장 현황의 ECG 분석기 및 특징
- 기존 IoT 의료 기기는 대량의 ECG 데이터를 모바일/서버로 전송하고 분석은 고성능 프로세서/모바일 앱에서 수행
- ECG 장치에서 신호를 받아 컴퓨터 기반 애플리케이션에서 ECG 패턴 분석
- 모든 ECG 분석 장치는 인터넷이나 고성능 컴퓨터/모바일 애플리케이션에 의존
이를 요약하면 다음과 같습니다:

핵심 솔루션
- Edge Impulse 기반 ECG 분석기는 인터넷 의존성 없이 ECG 데이터 분석
- IoT 기기 대비 최저 지연 시간
- 15KB ROM의 ECG 분석 TinyML 모델이 모든 TinyML 지원 마이크로컨트롤러에서 실행 가능
- 장치가 ECG 패턴을 분석해 정상, 심방 세동, 1도 방실 차동으로 분류
아키텍처
ECG 분석기는 다음을 포함합니다:
1. AD8232를 이용한 ECG 판독
2. 다양한 심장 질환 ECG 패턴 시뮬레이션
3. 양질의 데이터셋 생성을 위한 새로운 접근법
4. 모델 훈련
5. 모델 테스트 정확도 및 배포된 라이브러리와 애플리케이션 코드 통합

ECG 그래프 이해
기술 작업에 앞서 ECG 그래프 기초를 살펴보겠습니다.
ECG 그래프는 P, Q, R, S, T 5개 파동으로 나뉩니다.

심방 세동 (Atrial Fibrillation)

1도 방실 차동 (First-Degree Heart Block)

ECG 분석기 제작 시작
1. AD8232를 이용한 ECG 판독
아래 연결도대로 ECG 센서 AD8232를 아두이노 나노 33 BLE 센스에 연결하세요.
아래 코드를 플래싱한 후 'Ctrl+Shift+L'을 눌러 그래픽 스트리밍 데이터를 시각화하세요.
void setup() {
// 시리얼 통신 초기화:
Serial.begin(115200);
pinMode(2, INPUT); // 리드 오프 감지 LO+ 설정
pinMode(3, INPUT); // 리드 오프 감지 LO- 설정
}
void loop() {
if((digitalRead(2) == 1) || (digitalRead(3) == 1)){
Serial.println('!');
} else {
// 아날로그 입력 0의 값 전송:
Serial.println(analogRead(A0));
}
// 시리얼 데이터 포화 방지를 위해 잠시 대기
delay(5);
}
1.1 ECG 전극 배치
ECG 전극은 위 다이어그램의 RA, LA, LL 위치에 부착하고 잭을 ECG 분석기의 AD8232 센서에 연결하세요.

2. MATLAB 시그널 빌더로 다양한 ECG 패턴 시뮬레이션
Step 2.1: 정상 ECG 데이터를 엑셀에 저장
시리얼 모니터 데이터를 아래 템플릿처럼 엑셀 파일에 복사 저장하세요. ECG 값은 'Y' 아래 두 번째 열에 있어야 합니다. 첫 번째 열은 시간 시리즈로 0.005(5ms)씩 증가해야 합니다.

Step 2.2: MATLAB 시그널 빌더
MATLAB에서 새로운 Simulink 모델을 생성하세요.

작업 공간에 'signal builder'를 입력하고 선택하세요. 'scope'도 삽입해 시그널 빌더와 연결하세요. 아래 스크린샷 참조.


저장된 엑셀 데이터를 로드하려면 시그널 빌더를 열고 '파일에서 가져오기' 옵션을 선택하세요.

언급된 옵션을 선택해 데이터를 가져오세요.

모델 저장 없이 확인하고 가져오세요. 아직 더 할 단계가 있습니다.
2.3: 시그널 빌더에서 ECG 데이터 시각화
A 60초 ECG 데이터는 시그널 빌더에서 이렇게 보입니다. 수동 편집을 위해 5초 데이터로 확대하고 '드래그'로 ECG 파동을 편집하세요.


확대 후 마우스 포인터를 ECG 파동 가까이 대면 ECG의 임의 포인트를 선택해 드래그하여 애플리케이션 요구사항에 맞게 편집할 수 있습니다.

2.4: 시그널 빌더에서 P-R 간격 데이터 편집으로 AV 블록 1 케이스 생성
I는 P 파동을 수동으로 끌어내리고 R 파동보다 훨씬 앞에 위치시켜 P-R 간격이 200ms를 초과하도록 했습니다.
시그널 빌더 데이터의 다른 타임라인에서도 이 단계를 반복하세요.

편집 후 데이터를 .mat 파일로 내보내세요. 시그널 빌더에서 이 옵션을 찾을 수 있습니다. .mat 파일이 저장되면 아래 단계를 따르세요.

따라할 단계: .mat 파일을 더블클릭 → 1x1 Dataset 더블클릭 → Data:1에서 수정된 데이터 확인.
데이터를 복사해 새 엑셀 파일에 붙여넣으세요.
Step 2.5: 엑셀 데이터를 배열로 내보내기
I는 엑셀 데이터를 배열로 변환하는 .m 스크립트를 작성했습니다.
MATLAB에서 이 스크립트를 실행하세요. 실행 전 ExcelFilename을 로컬 저장 파일명으로, ExcelSheetName을 해당 시트명으로 바꾸세요.
data=xlsread('ExcelFilename.xlsx','ExcelSheetName');
ECGExtract=(data(1:end,1)); %%Column A data
fid=fopen('test.txt','wt');%opening with the t flag auto-converts \n to \r\n on Windows
fprintf(fid,'{');
FormatSpec=[repmat('%i ',1,size(ECGExtract,2)) ','];
fprintf(fid,FormatSpec, ECGExtract);
fprintf(fid,'}')
fclose(fid);
텍스트 파일이 현재 디렉토리에 생성됩니다.

배열 내용을 복사해 심방 세동과 1도 방실 차동 시뮬레이션용 ECGAnalyzer.c 코드에 붙여넣으세요.

3. 양질의 데이터셋 생성을 위한 새로운 접근법
ECG 데이터를 보면 짧은 시간 윈도우(예: 3초)에서는 정상 ECG와 다른 심장 질환 ECG를 구분하기 정말 어렵습니다.

필터링된 ECG 데이터만으로 심방 세동, 정상, 1도 방실 차동을 학습시켰을 때 정확도가 23% 미만이었습니다. 짧은 윈도우에서 모델이 차이를 구분 못 하기 때문입니다.
윈도우 시간을 늘리면 처리 시간과 피크 RAM 사용량이 크게 늘어나고, 그래도 정확도가 안 나왔습니다.
새로운 접근법의 배경:
의사나 훈련된 사람이 ECG 그래프를 분석할 때, R-R 파동 사이, P-R 간격의 작은 박스 수를 세서 그래프에 적거나 기억해 계산합니다.

필터링된 ECG 데이터에서 별도 파형을 생성했습니다.
새 파형:


정상 ECG 데이터용 생성 데이터셋:

해독된 R-R 간격과 PR 간격 데이터는 정상 ECG 데이터에서 항상 100과 50입니다.
심방 세동 ECG 데이터용 생성 데이터셋:

이전 R-R 간격과 현재 R-R 간격 사이에 편차가 있을 때마다 R-R 간격 데이터가 한 사이클 동안 -100으로 떨어집니다.
1도 방실 차동 ECG 데이터용 생성 데이터셋:

P-R 간격이 200ms를 초과할 때마다 PR 간격 데이터가 한 사이클 동안 -50으로 떨어집니다.
이 접근법으로 모델 정확도를 90% 이상으로 향상시켰습니다.
4. Edge Impulse에서 모델 훈련
Edge Impulse ML 훈련에 들어가기 전에 시뮬레이션과 실시간 ECG 센서 판독을 위해 라이브러리 파일에서 몇 가지 파라미터를 설정해야 합니다.
Step 4.1: 실시간 ECG 센서 판독으로 데이터 수집 시 SIMULATION을 0으로 설정,
또는
MATLAB 세션을 따른 시뮬레이션 ECG 데이터(심방 세동, 1도 방실 차동) 수집 시 SIMULATION을 1로 설정.

Step 4.2: 시뮬레이션용 필수 데이터 버퍼 주석 처리/해제

Step 4.3: 데이터 수집
정상, 심방 세동, 1도 방실 차동 3개 라벨로 ECG 데이터 수집:

https://docs.edgeimpulse.com/docs/arduino-nano-33-ble-sense

주파수를 202로 선택:
$ edge-impulse-daemon --frequency 202
Step 4.4: 임펄스 생성
임펄스 생성 섹션에서 윈도우 크기 3000ms, 윈도우 증가 2999ms, K-means 이상 탐지 선택:

Step 4.5: 스펙트럴 특징
스펙트럴 특징에서 필터 타입을 None으로 선택:

Step 4.6: NN 분류기:
I는 훈련 사이클 40회, 학습률 0.005로 설정했고 92.9% 정확도를 얻었습니다.

이상 탐지에는 PR 간격 RMS와 RR 간격 RMS를 선택했습니다.
5. 모델 테스트 정확도 및 통합
모델 테스트 정확도는 약 97%였습니다.

5.1 배포:
배포에서 아두이노 선택:

다운로드한 EI 배포 파일을 아두이노 라이브러리에 추가하세요.

참고: GitHub 링크의 ECG_Analyzer 라이브러리도 아두이노 라이브러리에 추가하세요. 이는 제 ECG 디코딩 알고리즘 코드를 EI 생성 모델과 통합하는 데 도움이 됩니다.
5.2 애플리케이션 코드를 핵심 EI 생성 코드와 통합
I는 애플리케이션 코드를 EI 배포된 "nano_ble33_sense_accelerometer_continuous"에 병합해 ECGAnalyzer.ino로 저장했습니다.
GitHub 링크의 첨부 파일로 제공됩니다. 장치에서 ECG_Analyzer.c의 SIMULATION을 0으로 설정하고 코드를 플래싱하세요.

하드웨어
프리칭 다이어그램대로 연결하세요:


조립:


최종 제품
최종 제품과 테스트 데이터 정확도입니다!


크레딧
ECG: https://geekymedics.com/how-to-read-an-ecg/
코드
GitHub 저장소
https://github.com/Manivannan-maker/ECGAnalyzer
ECGAnalyzer.zip 압축 해제 후 플래시할 코드: EI_Deployed_Library\examples\ECGAnalyzer\ECGAnalyzer.ino
시뮬레이션 편집용 라이브러리: ECGAnalyzer_lib\ecg_analyzer.c
MATLAB 스크립트 및 시그널 빌더 모델: Matlab_Simulation\Excel2Arrayconverter.m, Matlab_Simulation\signalbuilder.slx
회로도
다이어그램대로 연결하세요 ecgdefault_SjMMcgW8jY.fzz
