Спектральный анализ аритмий сердца
Спектральный анализ аритмий сердца
В данном примере демонстрируется применение спектрального анализа к электрокардиографическим сигналам с различными типами сердечного ритма. Рассматриваются записи ЭКГ с нормальным синусовым ритмом, экстрасистолией и фибрилляцией предсердий, полученные из открытых баз данных PhysioNet. Для частотного анализа используются функции библиотеки EngeeDSP.
Функция engee.clear() выполняет очистку рабочего пространств:
engee.clear()
Для визуализации результатов доступны два режима отрисовки графиков:
-
Для статической, быстрой отрисовки - используйте
gr(). -
Для интерактивной, динамической визуализации с возможностью масштабирования и просмотра значений - используйте
plotlyjs().
Выберите одну из команд, закомментировав вторую. Оба бэкенда являются взаимоисключающими, и активирован будет последний вызванный.
#gr()
plotlyjs()
Подключим с помощью функции include файл "read.jl" для чтения файлов:
include("$(@__DIR__)/read.jl")
Спектральный анализ ЭКГ в норме
В качестве исходных данных для анализа используется электрокардиографический сигнал, соответствующий нормальному синусовому ритму сердца. Данная запись получена из базы данных MIT-BIH Normal Sinus Rhythm Database (NSRDB) и отражает работу сердца здорового человека без выраженных нарушений ритма.
Укажем путь к файлу с выбранной записью ЭКГ:
data = ("$(@__DIR__)/mit-bih-normal-sinus-rhythm/16272")
После задания пути к файлу выполняется чтение заголовка записи ЭКГ. Из заголовка извлекается служебная информация, описывающая параметры сигнала: имя записи, частота дискретизации, количество каналов и общее число отсчётов. Также выводятся сведения о формате данных, коэффициенте усиления и текстовом описании записи.
hdr = read_header(data)
println("Наименование записи: ", hdr.record)
println("Частота дискретизации: ", hdr.fs, " Гц")
println("Количество сигналов: ", hdr.nsig)
println("Количество отсчётов: ", hdr.nsamp)
println("Формат данных: ", hdr.fmt)
println("Усиление: ", hdr.gain)
println("Описание: ", hdr.desc)
Для демонстрации временного представления ЭКГ выберем 10-секундный фрагмент записи.
t_start = 0.0
t_dur = 10.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_212(data; sampfrom=sampl_start, sampto=sampl_end)
y1 = phys === nothing ? float.(raw[:,1])/200 : phys[:,1]
t1 = (0:length(y1)-1)./ hdr.fs.+ t_start
plot(t1, y1,
xlabel="Время, с",
ylabel="Амплитуда",
title="Запись $(hdr.record) NSRDB",
legend=false)
Также продемонстрируем минутный фрагмент ЭКГ-записи. Для этого увеличим длительность анализируемого интервала до 60 секунд, считаем соответствующий участок сигнала и построим его временное представление.
t_start = 0.0
t_dur = 60.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_212(data; sampfrom=sampl_start, sampto=sampl_end)
y1 = phys === nothing ? float.(raw[:,1])/200 : phys[:,1]
t1 = (0:length(y1)-1) ./ hdr.fs .+ t_start
plot(t1, y1,
xlabel="Время, с",
ylabel="Амплитуда",
title="Запись $(hdr.record) NSRDB",
legend=false)
Для перехода к частотному представлению сигнала используем функции библиотеки EngeeDSP. Функция EngeeDSP.Functions.fft выполняет быстрое преобразование Фурье временного сигнала, преобразуя его во множество комплексных частотных коэффициентов. Далее применяется EngeeDSP.Functions.fftshift для центрирование спектра.
nsampl = length(y1)
fs = hdr.fs
df = hdr.fs / nsampl
freq_vec1 = -fs/2 : df : fs/2 - df
fft_y1 = EngeeDSP.Functions.fft(y1) # БПФ
fft_Y1 = EngeeDSP.Functions.fftshift(fft_y1) # Центрированный спектр
Рассчитаем амплитудный спектр анализируемого сигнала и построим его в диапазоне частот от 0 до 10 Гц.
Amp1 = (2*abs.(fft_Y1))/nsampl
plot(
freq_vec1, Amp1,
xlabel="Частота, Гц",
ylabel="Амплитуда",
title="Амплитудный спектр сигнала $(hdr.record) NSRDB",
grid=true,
legend=false,
xlim=(0, 10),
)
Полученный амплитудный спектр ЭКГ-сигнала с нормальным синусовым ритмом имеет упорядоченную структуру. В спектре отчётливо выражена основная частотная компонента в области около 1 Гц, соответствующая частоте сердечных сокращений, а также наблюдаются гармоники на кратных частотах. Энергия сигнала сосредоточена преимущественно в низкочастотной области до 10 Гц.
Отдельно можно отметить наличие компоненты в области около 0,1 Гц, которая не связана напрямую с сердечной деятельностью и обусловлена низкочастотными помехами, возникающими при записи сигнала.
Спектральный анализ ЭКГ при желудочковой экстрасистолии
Желудочковая экстрасистолия - это разновидность нарушения сердечного ритма, при которой внеочередные сокращения возникают не из синусового узла, а из дополнительных очагов возбуждения в желудочках сердца. Такие преждевременные сокращения проявляются на ЭКГ как отдельные, более ранние, деформированные комплексы QRS по сравнению с нормальными сердечными циклам.
Экстрасистолы могут быть одиночными или повторяющимися, а в зависимости от частоты и характера появлений выявляются как частые или редкие. Часто желудочковые экстрасистолы не сопровождаются выраженными симптомами у пациента, но могут ощущаться как перебои или «пропущенные» удары сердца.
Используем запись ЭКГ с желудочковой экстрасистолией из базы данных CU Ventricular Tachyarrhythmia Database (CU VTADB).
data = ("$(@__DIR__)/cu-ventricular-tachyarrhythmia/cu05")
Выведем основные параметры анализируемой записи ЭКГ.
hdr = read_header(data)
println("Наименование записи: ", hdr.record)
println("Частота дискретизации: ", hdr.fs, " Гц")
println("Количество сигналов: ", hdr.nsig)
println("Количество отсчётов: ", hdr.nsamp)
println("Формат данных: ", hdr.fmt)
println("Усиление: ", hdr.gain)
println("Описание: ", hdr.desc)
Продемонстрируем желудочковую экстрасистолу. Для этого выделим на записи двухсекундный фрагмент в интервале 126 -128 с и отметим участок, соответствующий экстрасистолическому комплексу, цветной областью на графике.
t_start = 126.0
t_dur = 2.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_212(data; sampfrom=sampl_start, sampto=sampl_end)
y2 = phys === nothing ? float.(raw[:,1]) : phys[:,1]
t2 = (0:length(y2)-1) ./ hdr.fs .+ t_start
p =plot(t2, y2,
xlabel="Время, с",
ylabel="Амлитуда",
title="Запись $(hdr.record) CU VTADB ",
legend=false
)
vline!(p, [127.1, 127.3], color=:red, alpha=0.3)
display(p)
Продемонстрируем минутный фрагмент ЭКГ при желудочковой экстрасистолии, выбрав участок записи без выраженных артефактов.
t_start = 115.0
t_dur = 60.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_212(data; sampfrom=sampl_start, sampto=sampl_end)
y2 = phys === nothing ? float.(raw[:,1]) : phys[:,1]
t2 = (0:length(y2)-1) ./ hdr.fs .+ t_start
plot(t2, y2,
xlabel="Время, с",
ylabel="Амплитуда",
title="Запись $(hdr.record) CU VTADB ",
legend=false)
Аналогично, для частотного анализа используем функции библиотеки EngeeDSP.
nsampl = length(y2)
fs = hdr.fs
df = hdr.fs / nsampl
freq_vec2 = -fs/2 : df : fs/2 - df
fft_y2 = EngeeDSP.Functions.fft(y2) # БПФ
fft_Y2 = EngeeDSP.Functions.fftshift(fft_y2) # Центрированный спектр
Построим амплитудный спектр минутного фрагмента ЭКГ с желудочковой экстрасистолией в диапазоне частот до 10 Гц.
Amp2 = (2*abs.(fft_Y2))/nsampl
plot(
freq_vec2, Amp2,
xlabel="Частота, Гц",
ylabel="Амплитуда",
title="Амплитудный спектр сигнала $(hdr.record) CU VTADB",
grid=true,
legend=false,
xlim=(0, 10),
)
Полученный амплитудный спектр ЭКГ при желудочковой экстрасистолии имеет менее упорядоченную структуру по сравнению с нормальным синусовым ритмом. Характер распределения спектральной энергии указывает на нарушение периодичности сердечных сокращений, обусловленное наличием экстрасистолических комплексов, что согласуется с особенностями ЭКГ при желудочковой экстрасистолии.
Спектральный анализ ЭКГ при предсердной экстрасистолии
Используем запись ЭКГ из базы данных MIT-BIH Arrhythmia Database, содержащую нарушения сердечного ритма. Запись 101 в целом характеризуется преимущественно нормальным синусовым ритмом, на фоне которого периодически присутствуют единичные и повторяющиеся предсердные экстрасистолы.
Единичные и повторяющиеся предсердные экстрасистолы представляют собой преждевременные сердечные сокращения, возникающие в предсердиях вне нормального синусового ритма. При единичных экстрасистолах такие сокращения появляются эпизодически и не оказывают существенного влияния на общий ритм сердца. Повторяющиеся предсердные экстрасистолы характеризуются более частым возникновением преждевременных импульсов, что приводит к периодическому нарушению регулярности сердечных циклов.
data = ("$(@__DIR__)/mit-bih-arrhythmia/101")
Выведем основную информацию о выбранной записи ЭКГ, включая параметры дискретизации, структуру сигнала и описание записи.
hdr = read_header(data)
println("Наименование записи: ", hdr.record)
println("Частота дискретизации: ", hdr.fs, " Гц")
println("Количество сигналов: ", hdr.nsig)
println("Количество отсчётов: ", hdr.nsamp)
println("Формат данных: ", hdr.fmt)
println("Усиление: ", hdr.gain)
println("Описание: ", hdr.desc)
Продемонстрируем единичную предсердную экстрасистолу. Для этого выделим на записи шестисекундный фрагмент в интервале 373 - 379 с и отметим на графике участок, соответствующий экстрасистолическому комплексу, цветными вертикальными линиями.
t_start = 373.0
t_dur = 6.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_212(data; sampfrom=sampl_start, sampto=sampl_end)
y3 = phys === nothing ? float.(raw[:,1]) : phys[:,1]
t3 = (0:length(y3)-1) ./ hdr.fs .+ t_start
plot(t3, y3,
xlabel="Время, с",
ylabel="Амлитуда",
title="Запись $(hdr.record) MIT-BIH Arrhythmia Database ",
legend=false)
vline!([375.6, 376.2], color=:red, alpha=0.3)
Продемонстрируем минутный фрагмент ЭКГ записи, содержащий эпизоды нарушений сердечного ритма.
t_start = 370.0
t_dur = 60.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_212(data; sampfrom=sampl_start, sampto=sampl_end)
y3 = phys === nothing ? float.(raw[:,1]) : phys[:,1]
t3 = (0:length(y3)-1) ./ hdr.fs .+ t_start
plot(t3, y3,
xlabel="Время, с",
ylabel="Амлитуда",
title="Запись $(hdr.record) MIT-BIH Arrhythmia Database ",
legend=false)
Аналогично предыдущим шагам, для минутного фрагмента ЭКГ выполним частотный анализ с использованием функций библиотеки EngeeDSP, получив центрированное спектральное представление сигнала.
nsampl = length(y3)
fs = hdr.fs
df = hdr.fs / nsampl
freq_vec3 = -fs/2 : df : fs/2 - df
fft_y3 = EngeeDSP.Functions.fft(y3) # БПФ
fft_Y3 = EngeeDSP.Functions.fftshift(fft_y3) # Центрированный спектр
Построим амплитудный спектр минутного фрагмента ЭКГ в диапазоне частот до 10 Гц.
Amp3 = (2*abs.(fft_Y3))/nsampl
plot(
freq_vec3, Amp3,
xlabel="Частота, Гц",
ylabel="Амплитуда",
title="Амплитудный спектр сигнала $(hdr.record) MIT-BIH Arrhythmia Database",
grid=true,
legend=false,
xlim=(0, 10),
ylim=(0 ,0.08)
)
Полученный амплитудный спектр минутного фрагмента ЭКГ из базы MIT-BIH Arrhythmia Database характеризуется выраженной разупорядоченностью по сравнению с нормальным синусовым ритмом. В спектре присутствует основная низкочастотная компонента, однако спектральные пики имеют заметное уширение, а энергия сигнала распределена по более широкому диапазону частот.
Спектральный анализ ЭКГ при фибрилляции предсердия
Фибрилляция предсердий - это форма нарушения сердечного ритма, при которой электрическая активность предсердий становится хаотичной и несогласованной. Вместо регулярных импульсов синусового узла в предсердиях возникают множественные очаги возбуждения, что приводит к их неэффективным сокращениям.
На электрокардиограмме фибрилляция предсердий характеризуется отсутствием нормальных зубцов P и появлением мелких нерегулярных колебаний базовой линии, а также нерегулярными интервалами между комплексами QRS
Выбираем запись s02, соответствующую фибрилляции предсердий, из базы данных Atrial Fibrillation Termination Challenge Database (AFDB).
data = ("$(@__DIR__)/af-termination-challenge/s02")
hdr = read_header(data)
println("Наименование записи: ", hdr.record)
println("Частота дискретизации: ", hdr.fs, " Гц")
println("Количество сигналов: ", hdr.nsig)
println("Количество отсчётов: ", hdr.nsamp)
println("Формат данных: ", hdr.fmt)
println("Усиление: ", hdr.gain)
println("Описание: ", hdr.desc)
Продемонстрируем 10-секундный фрагмент записи ЭКГ, на котором заметна нерегулярность ритма, характерная для фибрилляции предсердий.
t_start = 0.0
t_dur = 10.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_16(data; sampfrom=sampl_start, sampto=sampl_end)
y4 = phys === nothing ? float.(raw[:,1]) : phys[:,1]
t4 = (0:length(y4)-1) ./ hdr.fs .+ t_start
plot(t4, y4,
xlabel="Время, с",
ylabel="Амлитуда",
title="Запись $(hdr.record) AFDB",
legend=false)
Продемонстрируем минутный фрагмент записи ЭКГ при фибрилляции предсердий, отражающий выраженную нерегулярность сердечного ритма.
t_start = 0.0
t_dur = 60.0
sampl_start = Int(round(t_start * hdr.fs))
sampl_end = sampl_start + Int(round(t_dur * hdr.fs))
_, raw, phys = read_dat_16(data; sampfrom=sampl_start, sampto=sampl_end)
y4 = phys === nothing ? float.(raw[:,1]) : phys[:,1]
t4 = (0:length(y4)-1) ./ hdr.fs .+ t_start
plot(t4, y4,
xlabel="Время, с",
ylabel="Амплитуда",
title="Запись $(hdr.record) AFDB",
legend=false)
Аналогично предыдущим шагам, выполним частотный анализ минутного фрагмента ЭКГ при фибрилляции предсердий с использованием функций библиотеки EngeeDSP и получим центрированный спектр сигнала.
nsampl = length(y4)
fs = hdr.fs
df = hdr.fs / nsampl
freq_vec4 = -fs/2 : df : fs/2 - df
fft_y4 = EngeeDSP.Functions.fft(y4) # БПФ
fft_Y4 = EngeeDSP.Functions.fftshift(fft_y4) # Центрированный спектр
Построим амплитудный спектр минутного фрагмента ЭКГ при фибрилляции предсердий в диапазоне частот до 10 Гц.
Amp4 = (2*abs.(fft_Y4))/nsampl
plot(
freq_vec4, Amp4,
xlabel="Частота, Гц",
ylabel="Амплитуда",
title="Амплитудный спектр сигнала $(hdr.record) AFDB",
grid=true,
legend=false,
xlim=(0, 10),
)
Амплитудный спектр ЭКГ при фибрилляции предсердий характеризуется выраженной разупорядоченностью и отсутствием чётко выраженной основной частотной компоненты. Энергия сигнала распределена по широкому диапазону частот, при этом наблюдается повышенный фоновый уровень спектра и большое количество нерегулярных спектральных составляющих.
Используемые материалы
В работе использовались реальные электрокардиографические записи из открытого ресурса PhysioNet.
- MIT-BIH Normal Sinus Rhythm Database (NSRDB) - записи ЭКГ с нормальным синусовым ритмом - https://physionet.org/content/nsrdb/1.0.0/
- CU Ventricular Tachyarrhythmia Database (CUDB) - записи ЭКГ с желудочковыми нарушениями ритма - https://physionet.org/content/cudb/1.0.0/
- MIT-BIH Arrhythmia Database - записи ЭКГ с различными видами аритмий - https://physionet.org/content/mitdb/1.0.0/
- Atrial Fibrillation Database (AFDB) - записи ЭКГ с фибрилляцией предсердий - https://physionet.org/content/afdb/1.0.0/
Заключение
В ходе примера был представлен спектральный анализ различных аритмий сердца. В работе использовались реальные электрокардиографические сигналы, полученные из открытых медицинских баз данных. Для частотного анализа сигналов применялись функции библиотеки EngeeDSP, в частности функции EngeeDSP.Functions.fft для вычисления быстрого преобразования Фурье и EngeeDSP.Functions.fftshift для формирования центрированного спектрального представления. Использование данных инструментов позволило наглядно продемонстрировать особенности спектров ЭКГ при различных типах нарушений сердечного ритма.