Health/심전도(ECG) 분석

6. Heart Rate Variability (HRV)

꼰대코더 2024. 1. 7. 23:24

심박 변이도(HRV)의 이해와 중요성

HRV란 무엇인가?

심박 변이도(Heart Rate Variability, HRV)는 심박 간격의 미세한 변화를 의미합니다. 이는 연속된 심장 박동 사이의 시간이 약간씩 늘어나거나 줄어드는 현상을 말합니다.

  • HRV는 특수 장비 없이는 인지하기 어려우나, 건강한 사람들에게도 존재합니다.
  • 심장 상태, 불안, 우울증 등 신체 및 정신 건강 상태를 반영할 수 있습니다.
  • HRV 자체는 일반적인 현상으로, 부정맥을 의미하지 않습니다.

정상적인 심박 리듬

  • 일반적인 심박은 "Sinus Rhythm"이라고 합니다.
  • 심박 간격이 0.12초보다 길 경우 "Sinus Arrhythmia"이라고 합니다.
  • 부정맥은 주로 호흡에 의해 발생하며, 정상적인 심혈관계 반응의 일부입니다.
  • 호흡과 무관한 경우, 다른 심장 문제의 징후일 수 있습니다.

HRV의 특성

  1. 심박수는 상황에 따라 변화합니다:
    • 낮은 심박수: 휴식 또는 편안한 상태
    • 빠른 심박수: 활동, 스트레스, 위험 상황
  2. 나이에 따른 변화:
    • HRV는 나이가 들수록 감소하는 경향이 있습니다.
  3. 적응성:
    • 심장은 생활 환경의 변화에 반응해야 합니다.
    • 이를 위해 다른 신체 시스템에 의존합니다.

신경계와 HRV의 관계

  1. 자율신경계(Autonomic Nervous System):
    • 뇌와 심장을 연결하는 직접적인 통로
    • 무의식적으로 작동
  2. 자율신경계의 구성:
    • 교감신경계: 응급 상황에서 심박수와 혈압 증가 관리
    • 부교감신경계: 균형 유지 및 휴식 반응 조절

HRV의 중요성

  • HRV는 신체의 적응 능력을 나타내는 지표입니다.
  • 높은 HRV: 환경 변화에 대한 적응력이 좋음, 스트레스 저항력 높음
  • 낮은 HRV: 현재 또는 미래의 건강 문제 가능성 시사

HRV에 영향을 미치는 요인

  • 평소 심박수가 높은 경우 HRV가 낮아질 수 있습니다.
  • 비만, 고혈압, 부정맥, 간질환, 분노, 우울증 등과 관련이 있습니다.

HRV 개선 방법

  1. 건강한 식습관 유지
  2. 규칙적인 운동
  3. 스트레스 관리 및 마인드 컨트롤
  4. 충분한 수면 (부교감신경 활성화)
  5. 호흡 조절 연습

주의: HRV의 해석은 복잡하며, 개인차가 있을 수 있습니다. 정확한 평가를 위해서는 전문가의 조언을 구하는 것이 좋습니다.

Time-domain analysis

hr = 60000/rr_ecg

 # HRV metrics
print(f" Mean RR (ms)                                     = { np.mean( rr_ecg ) }")
print(f" STD RR/SDNN (ms)                            =  { np.std( rr_ecg ) }")
print(f" Mean HR (Kubios\' style) (beats/min)  =  {  60000/np.mean( rr_ecg ) }")
print(f" 'Mean HR (beats/min)                          =  {  np.mean(hr) }")
print(f" STD HR (beats/min)                            =  {  np.std(hr) }")
print(f" Min HR (beats/min)                             =  {  np.min(hr) }")
print(f" Max HR (beats/min)                            =  {  np.max(hr) }")
print(f" RMSSD (ms)                                       =  {  np.sqrt(np.mean(np.square(np.diff( rr_ecg )))) }")
print(f" NN50                                                   =  {  np.sum(np.abs(np.diff( rr_ecg )) > 50)*1 }")
print(f" pNN50 (%)                                          =  {  100 * np.sum((np.abs(np.diff( rr_ecg )) > 50)*1) / len( rr_ecg ) }")

 

결과

Mean RR (ms)                                     = 692.9509514875368
STD RR/SDNN (ms)                            =   40.971424374471724
Mean HR (Kubios' style) (beats/min)     86.5862148990485
Mean HR (beats/min)                          =  86.90379938215764
STD HR (beats/min)                             =  5.387913337905105
Min HR (beats/min)                              =  76.47058823529393
Max HR (beats/min)                             =  104.00000000000242
RMSSD (ms)                                        =  13.477858392926546
NN50                                                    =   1
pNN50 (%)                                           =   0.34843205574912894

 

Frequency-domain analysis

# x = 5. R-R Intervals 에서 구한 4Hz 인터폴레이션 numpy , fs 주파수 (=4Hz)
fxx, pxx = signal.welch(x=self.product._rri_interplated, fs=4, nperseg=256)

 

그래프

powerspectrum_f = interp1d(fxx, pxx, kind='cubic', fill_value= 'extrapolate')
plt.figure(figsize=(15,6))
plt.title("FFT Spectrum (Welch's periodogram)")

# setup frequency bands for plotting
x_VLF = np.linspace(0, 0.04, 100)
x_LF = np.linspace(0.04, 0.15, 100)
x_HF = np.linspace(0.15, 0.4, 100)

plt.gca().fill_between(x_VLF, powerspectrum_f(x_VLF), alpha=0.5, color="#F5866F", label="VLF")
plt.gca().fill_between(x_LF, powerspectrum_f(x_LF), alpha=0.5, color="#51A6D8", label="LF")
plt.gca().fill_between(x_HF, powerspectrum_f(x_HF), alpha=0.5, color="#ABF31F", label="HF")

plt.gca().set_xlim(0, 0.5)
plt.gca().set_ylim(0)
plt.xlabel("Frequency (Hz)")
plt.ylabel("Density")
plt.legend()
plt.show()

 

LF(Low Frequency)   :  주파수 0.04 ~ 0.15 구간

HF(High Frequency) :   주파수 0.15 ~ 0.4   구간

#주파수 밴드: very low frequency (VLF), low frequency (LF), high frequency (HF) 
cond_VLF = (fxx >= 0) & (fxx < 0.04)
cond_LF   = (fxx >= 0.04) & (fxx < 0.15)
cond_HF  = (fxx >= 0.15) & (fxx < 0.4)

# 밴드별 파워계산
vlf   = np.trapz(pxx[cond_VLF], fxx[cond_VLF])
lf    = np.trapz(pxx[cond_LF], fxx[cond_LF])
hf   = np.trapz(pxx[cond_HF], fxx[cond_HF])

# 전체 파워
total_power = vlf + lf + hf

#peaks (Hz) in each band
peak_VLF = fxx[cond_VLF][np.argmax(pxx[cond_VLF])]
peak_LF = fxx[cond_LF][np.argmax(pxx[cond_LF])]
peak_HF = fxx[cond_HF][np.argmax(pxx[cond_HF])]

#fractions
LF_nu = 100 * lf / (lf + hf)
HF_nu = 100 * hf / (lf + hf)

print(f"  Power VLF (ms2)     = {  VLF  }")
print(f"  Power LF (ms2)       = {  LF  }")
print(f"  Power HF (ms2)      = {  HF    }")
print(f"  Power Total (ms2)   = {  total_power  }")

print(f"  LF/HF                      = {  (LF/HF)  }")
print(f"  Peak VLF (Hz)         = {  peak_VLF  }")
print(f"  Peak LF (Hz)           = {  peak_LF  }")
print(f"  Peak HF (Hz)          = {  peak_HF  }")

print(f"  Fraction LF (nu)      = {  LF_nu  }")
print(f"  Fraction HF (nu)      = {  HF_nu  }")

 

결과

Power VLF (ms2)          =  416.70741870124107
Power LF (ms2)            =   396.5167820676011
Power HF (ms2)           =   52.09260382637196
Power Total (ms2)        =   865.3168045952141
LF/HF                           =   7.61176737083862
Peak VLF (Hz)             =   0.015625
Peak LF (Hz)                =   0.078125
Peak HF (Hz)               =   0.15625
Fraction LF (nu)           =   88.38798173547715
Fraction HF (nu)          =   11.612018264522852

 

다음 마지막 칼럼에서 위의 결과를 분석하고자 한다.

'Health > 심전도(ECG) 분석' 카테고리의 다른 글

7. 결과분석  (0) 2024.01.08
5. R-R Intervals  (1) 2024.01.07
4. Peak(R) detection (Revised)  (0) 2023.12.13
3. 시그널 전처리 (Revised)  (1) 2023.12.09
2. ECG 데이터 클린징 (Revised)  (1) 2023.12.07