본문 바로가기
Health/심전도(ECG) 분석

6. Heart Rate Variability (HRV)

by 꼰대코더 2024. 1. 7.

심박 변이도(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