Этот пример показывает, как сегментировать сигналы электрокардиограммы (ЭКГ) человека с помощью рецидивирующих нейронных сетей для глубокого обучения и частотно-временного анализа.
Электрическая активность в сердце человека может быть измерена как последовательность амплитуд от базового сигнала. Для одного нормального цикла сердцебиения сигнал ЭКГ может быть разделен на следующие морфологии пульса [1]:
P-волна - небольшой прогиб перед комплексом QRS, представляющий деполяризацию предсердий
Комплекс QRS - Наибольшая амплитуда фрагмента пульса
Т-волна - небольшой прогиб после комплекса QRS, представляющего реполяризацию желудочков
Сегментация этих областей форм волны ЭКГ может обеспечить базис для измерений, полезных для оценки общего состояния здоровья человеческого сердца и наличия аномалий [2]. Вручную аннотирование каждой области сигнала ЭКГ может быть утомительной и длительной задачей. Обработка сигналов и методы глубокого обучения потенциально могут помочь оптимизировать и автоматизировать аннотацию необходимой области.
Этот пример использует сигналы ЭКГ из общедоступной базы данных QT [3] [4]. Данные состоят примерно из 15 минут записей ЭКГ с частотой дискретизации 250 Гц, измеренной от общего числа 105 пациентов. Чтобы получить каждую запись, экзаменаторы поместили два электрода в других местах на груди пациента, получая двухканальный сигнал. База данных обеспечивает метки областей сигнала, сгенерированные автоматизированной экспертной системой [2]. Этот пример направлен на использование решения глубокого обучения, чтобы обеспечить метку для каждой выборки сигнала ЭКГ в соответствии с областью, где расположена выборка. Этот процесс маркировки необходимых областей через сигнал часто упоминается как сегментация формы волны.
Чтобы обучить глубокую нейронную сеть классифицировать области сигнала, можно использовать сеть Long Short-Term Memory (LSTM). Этот пример показывает, как методы предварительной обработки сигналов и частотно-временной анализ могут использоваться, чтобы улучшить эффективность сегментации LSTM. В частности, пример использует Synchrosqueezed преобразование Фурье, чтобы представлять нестационарное поведение сигнала ЭКГ.
Каждый канал 105 двухканальных сигналов ЭКГ был маркирован независимо автоматизированной экспертной системой и обрабатывается независимо, в общей сложности 210 сигналов ЭКГ, которые хранились вместе с метками области в 210 MAT-файлах. Файлы доступны в следующем расположении: https://www.mathworks.com/supportfiles/SPT/data/QTDatabaseECGData.zip.
Загрузите файлы данных в свою временную директорию, расположение которого задано tempdir
MATLAB ® команда. Если вы хотите поместить файлы данных в папку, отличную от
tempdir
измените имя директории в последующих инструкциях.
% Download the data dataURL = 'https://www.mathworks.com/supportfiles/SPT/data/QTDatabaseECGData1.zip'; datasetFolder = fullfile(tempdir,'QTDataset'); zipFile = fullfile(tempdir,'QTDatabaseECGData.zip'); if ~exist(datasetFolder,'dir') websave(zipFile,dataURL); unzip(zipFile,tempdir); end
The unzip
операция создает QTDatabaseECGData
папка во временной директории с 210 MAT-файлами в ней. Каждый файл содержит сигнал ЭКГ в переменной ecgSignal
и таблица меток областей в переменных signalRegionLabels
. Каждый файл также содержит частоту дискретизации сигнала в переменной Fs
. В этом примере все сигналы имеют частоту дискретизации 250 Гц.
Создайте сигнальный datastore для доступа к данным в файлах. Этот пример предполагает, что набор данных был сохранен в вашей временной директории под QTDatabaseECGData
папка. Если это не так, измените путь к данным в коде ниже. Укажите имена переменных, которые вы хотите считать из каждого файла, используя SignalVariableNames
параметр.
sds = signalDatastore(datasetFolder,'SignalVariableNames',["ecgSignal","signalRegionLabels"])
sds = signalDatastore with properties: Files:{ '/tmp/QTDataset/ecg1.mat'; '/tmp/QTDataset/ecg10.mat'; '/tmp/QTDataset/ecg100.mat' ... and 207 more } AlternateFileSystemRoots: [0×0 string] ReadSize: 1 SignalVariableNames: ["ecgSignal" "signalRegionLabels"]
datastore возвращает массив ячеек с двумя элементами с сигналом ECG и таблицей меток областей каждый раз, когда вы вызываете read
функция. Используйте preview
функция datastore, чтобы увидеть, что содержимое первого файла является сигналом ЭКГ длиной 225000 дискретизаций и таблицей, содержащей 3385 меток областей.
data = preview(sds)
data=2×1 cell array
{225000×1 double}
{ 3385×2 table }
Проверьте первые несколько строк таблицы меток областей и заметьте, что каждая строка содержит индексы пределов областей и значение класса областей (P, T или QRS).
head(data{2})
ans=8×2 table
ROILimits Value
__________ _____
83 117 P
130 153 QRS
201 246 T
285 319 P
332 357 QRS
412 457 T
477 507 P
524 547 QRS
Визуализируйте метки для первых 1000 выборок с помощью signalMask
объект.
M = signalMask(data{2}); plotsigroi(M,data{1}(1:1000))
Обычная процедура классификации машинного обучения является следующей:
Разделите базу данных на обучающие и тестовые наборы данных.
Обучите сеть с помощью обучающего набора данных.
Используйте обученную сеть, чтобы делать предсказания на тестовом наборе данных.
Сеть обучается с 70% данных и тестируется с оставшимися 30%.
Для воспроизводимых результатов сбросьте генератор случайных чисел. Используйте dividerand
функция для получения случайных индексов для тасования файлов и subset
функция signalDatastore
разделить данные на обучающие и тестовые хранилища данных.
rng default
[trainIdx,~,testIdx] = dividerand(numel(sds.Files),0.7,0,0.3);
trainDs = subset(sds,trainIdx);
testDs = subset(sds,testIdx);
В этой задаче сегментации вход в сеть LSTM является сигналом ECG, а выход является последовательностью или маской меток с той же длиной, что и входной сигнал. Сетевая задача состоит в том, чтобы пометить каждую выборку сигнала именем области, к которой она принадлежит. По этой причине необходимо преобразовать метки области на наборе данных в последовательности, содержащие по одной метке на выборку сигнала. Используйте преобразованные datastore и getmask
вспомогательная функция для преобразования меток областей. The getmask
функция добавляет категорию меток, "n/a"
, для маркировки выборок, которые не относятся ни к одной необходимой области.
type getmask.m
function outputCell = getmask(inputCell) %GETMASK Convert region labels to a mask of labels of size equal to the %size of the input ECG signal. % % inputCell is a two-element cell array containing an ECG signal vector % and a table of region labels. % % outputCell is a two-element cell array containing the ECG signal vector % and a categorical label vector mask of the same length as the signal. % Copyright 2020 The MathWorks, Inc. sig = inputCell{1}; roiTable = inputCell{2}; L = length(sig); M = signalMask(roiTable); % Get categorical mask and give priority to QRS regions when there is overlap mask = catmask(M,L,'OverlapAction','prioritizeByList','PriorityList',[2 1 3]); % Set missing values to "n/a" mask(ismissing(mask)) = "n/a"; outputCell = {sig,mask}; end
Предварительный просмотр преобразованного datastore, чтобы заметить, что он возвращает вектор сигнала и вектор метки равной длины. Постройте график первого элемента 1000 вектора категориальной маски.
trainDs = transform(trainDs, @getmask); testDs = transform(testDs, @getmask); transformedData = preview(trainDs)
transformedData=1×2 cell array
{224993×1 double} {224993×1 categorical}
plot(transformedData{2}(1:1000))
Передача очень длинных входных сигналов в сеть LSTM может привести к снижению эффективности оценки и чрезмерному использованию памяти. Чтобы избежать этих эффектов, нарушите сигналы ECG и их соответствующие маски меток с помощью преобразованных datastore и resizeData
вспомогательная функция. Функция helper создает как можно больше сегментов с 5000 образцами и отбрасывает оставшиеся выборки. Предварительный просмотр выхода преобразованного datastore показывает, что первый сигнал ECG и его маска метки разбиты на сегменты с 5000 образцами. Обратите внимание, что предварительный просмотр преобразованного datastore показывает только первые 8 элементов обратного floor(224993/5000)
= 44 массив ячеек элемента, который получился бы, если бы мы назвали datastore read
функция.
trainDs = transform(trainDs,@resizeData); testDs = transform(testDs,@resizeData); preview(trainDs)
ans=8×2 cell array
{1×5000 double} {1×5000 categorical}
{1×5000 double} {1×5000 categorical}
{1×5000 double} {1×5000 categorical}
{1×5000 double} {1×5000 categorical}
{1×5000 double} {1×5000 categorical}
{1×5000 double} {1×5000 categorical}
{1×5000 double} {1×5000 categorical}
{1×5000 double} {1×5000 categorical}
В следующих разделах этого примера сравниваются три различных подхода к обучению сетей LSTM. Из-за большого размера набора данных процесс обучения каждой сети может занять несколько минут. Если на вашей машине есть графический процессор и Parallel Computing Toolbox™, то MATLAB автоматически использует графический процессор для более быстрого обучения. В противном случае используется центральный процессор.
Можно пропустить шаги обучения и загрузить предварительно обученные сети с помощью селектора ниже. Если вы хотите обучить сети в качестве примера запусков, выберите 'Train Networks'. Если вы хотите пропустить шаги обучения, выберите 'Download Networks' и файл, содержащий все три предварительно обученные сети - rawNet
, filteredNet
, и fsstNet-
будет загружен во временную директорию, местоположение которого задано tempdir
MATLAB ® команда. Если вы хотите поместить загруженный файл в папку, отличную от
tempdir
измените имя директории в последующих инструкциях.
actionFlag = "Train networks"; if actionFlag = ="Download networks" % Download the pre-trained networks dataURL = 'https://ssd.mathworks.com/supportfiles/SPT/data/QTDatabaseECGSegmentationNetworks.zip'; %#ok<*UNRCH> modelsFolder = fullfile (tempdir,'QTDatabaseECGSegmentationNetworks'); modelsFile = fullfile (modelsFolder,'trainedNetworks.mat'); zipFile = fullfile (tempdir,'QTDatabaseECGSegmentationNetworks.zip'); if ~ существует (modelsFolder,'dir') веб-сайт (zipFile, dataURL); unzip (zipFile, fullfile (tempdir,'QTDatabaseECGSegmentationNetworks')); end load (modelsFile) end
Результаты между загруженными сетями и вновь обученными сетями могут незначительно варьироваться, поскольку сети обучаются с использованием случайных начальных весов.
Сначала обучите сеть LSTM, используя необработанные сигналы ECG от обучающего набора данных.
Определите сетевую архитектуру перед обучением. Задайте sequenceInputLayer
размера 1, чтобы принять одномерные временные ряды. Задайте слой LSTM с 'sequence'
выходной режим для обеспечения классификации для каждой выборки в сигнале. Используйте 200 скрытых узлов для оптимальной эффективности. Задайте fullyConnectedLayer
с размером выходом 4, по одному для каждого из классов формы волны. Добавление softmaxLayer
и a classificationLayer
для вывода предполагаемых меток.
layers = [ ... sequenceInputLayer(1) lstmLayer(200,'OutputMode','sequence') fullyConnectedLayer(4) softmaxLayer classificationLayer];
Выберите опции процесса обучения, которые гарантируют хорошую эффективность сети. Обратитесь к trainingOptions
документация для описания каждого параметра.
options = trainingOptions('adam', ... 'MaxEpochs',10, ... 'MiniBatchSize',50, ... 'InitialLearnRate',0.01, ... 'LearnRateDropPeriod',3, ... 'LearnRateSchedule','piecewise', ... 'GradientThreshold',1, ... 'Plots','training-progress',... 'shuffle','every-epoch',... 'Verbose',0,... 'DispatchInBackground',true);
Поскольку весь обучающий набор данных помещается в памяти, возможно использовать tall
функция datastore, чтобы преобразовать данные параллельно, если доступна Toolbox™ Parallel Computing, и затем собрать их в рабочую область. Обучение нейронной сети итеративно. При каждой итерации datastore считывает данные из файлов и преобразует данные перед обновлением сетевых коэффициентов. Если данные помещаются в память компьютера, импорт данных в рабочую область позволяет ускорить обучение, поскольку данные считываются и преобразуются только один раз. Обратите внимание, что если данные не помещаются в памяти, необходимо передать datastore в функцию обучения, и преобразования выполняются в каждую эпоху обучения.
Создайте длинные массивы как для обучающих, так и для тестовых наборов. В зависимости от системы, количество работников в параллельном пуле, который создает MATLAB, может отличаться.
tallTrainSet = tall(trainDs);
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 8).
tallTestSet = tall(testDs);
Теперь вызовите gather
функция длинных массивов для вычисления преобразований по набору данных в целом и получения массивов ячеек с помощью обучающих и тестовых сигналов и меток.
trainData = gather(tallTrainSet);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 11 sec Evaluation completed in 12 sec
trainData(1,:)
ans=1×2 cell array
{1×5000 double} {1×5000 categorical}
testData = gather(tallTestSet);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 2.9 sec Evaluation completed in 3.1 sec
Используйте trainNetwork
команда для обучения сети LSTM.
if actionFlag == "Train networks" rawNet = trainNetwork(trainData(:,1),trainData(:,2),layers,options); end
Подграфики точности и потерь обучения на рисунке отслеживают процесс обучения во всех итерациях. Используя данные необработанного сигнала, сеть правильно классифицирует около 77% выборок как принадлежащие к P-волне, комплексу QRS, T-волне или немеченой области "n/a"
.
Классификация тестовых данных с помощью обученной сети LSTM и classify
команда. Задайте мини-пакет размером 50, чтобы соответствовать опциям обучения.
predTest = classify(rawNet,testData(:,1),'MiniBatchSize',50);
Матрица неточностей предоставляет интуитивно понятное и информативное средство для визуализации классификационной эффективности. Используйте confusionchart
команда для вычисления общей точности классификации для предсказаний тестовых данных. Для каждого входа преобразуйте массив ячеек категориальных меток в вектор-строку. Задайте нормированное к столбцу отображение, чтобы просмотреть результаты как проценты выборок для каждого класса.
confusionchart([predTest{:}],[testData{:,2}],'Normalization','column-normalized');
Используя необработанный сигнал ЭКГ в качестве входных данных для сети, было правильным только около 60% выборок Т-волны, 40% выборок Р-волны и 60% выборок QRS-комплекса. Чтобы улучшить эффективность, примените некоторые знания о характеристиках сигнала ЭКГ перед входом в нейронную сеть для глубокого обучения для образца базовой линии блуждания, вызванной дыхательным движением пациента.
Три морфологии биений занимают различные полосы частот. Спектр комплекса QRS обычно имеет центральную частоту около 10-25 Гц, а его компоненты находятся ниже 40 Гц. Волны P и T происходят на ещё более низких частотах: компоненты P-волны находятся ниже 20 Гц, а компоненты T-волны - ниже 10 Гц [5].
Базовым блужданием является низкочастотное (< 0,5 Гц) колебание, вызванное дыхательным движением пациента. Это колебание не зависит от морфологий биения и не предоставляет содержательной информации [6].
Создайте полосно-пропускающий фильтр с областью значений частоты полосы пропускания [0,5, 40] Гц, чтобы удалить блуждание и любой шум высокой частоты. Удаление этих компонентов улучшает обучение LSTM, поскольку сеть не учит нерелевантные функции. Использование cellfun
на tall data массивов ячеек для параллельной фильтрации набора данных.
% Bandpass filter design hFilt = designfilt('bandpassiir', 'StopbandFrequency1',0.4215,'PassbandFrequency1', 0.5, ... 'PassbandFrequency2',40,'StopbandFrequency2',53.345,... 'StopbandAttenuation1',60,'PassbandRipple',0.1,'StopbandAttenuation2',60,... 'SampleRate',250,'DesignMethod','ellip'); % Create tall arrays from the transformed datastores and filter the signals tallTrainSet = tall(trainDs); tallTestSet = tall(testDs); filteredTrainSignals = gather(cellfun(@(x)filter(hFilt,x),tallTrainSet(:,1),'UniformOutput',false));
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: 0% complete Evaluation 0% complete
- Pass 1 of 1: Completed in 13 sec Evaluation completed in 14 sec
trainLabels = gather(tallTrainSet(:,2));
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 3.6 sec Evaluation completed in 4 sec
filteredTestSignals = gather(cellfun(@(x)filter(hFilt,x),tallTestSet(:,1),'UniformOutput',false));
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 2.4 sec Evaluation completed in 2.5 sec
testLabels = gather(tallTestSet(:,2));
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 1.9 sec Evaluation completed in 2 sec
Постройте график необработанных и отфильтрованных сигналов для типового случая.
trainData = gather(tallTrainSet);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 4 sec Evaluation completed in 4.2 sec
figure subplot(2,1,1) plot(trainData{95,1}(2001:3000)) title('Raw') grid subplot(2,1,2) plot(filteredTrainSignals{95}(2001:3000)) title('Filtered') grid
Несмотря на то, что базовая линия отфильтрованных сигналов может запутать врача, который используется для традиционных измерений ЭКГ на медицинских устройствах, сеть фактически выиграет от блуждающего удаления.
Обучите сеть LSTM по фильтрованным сигналам ECG с помощью той же сетевой архитектуры, что и ранее.
if actionFlag == "Train networks" filteredNet = trainNetwork(filteredTrainSignals,trainLabels,layers,options); end
Предварительная обработка сигналов повышает точность обучения до более 80%.
Классификация предварительно обработанных тестовых данных с обновленной сетью LSTM.
predFilteredTest = classify(filteredNet,filteredTestSignals,'MiniBatchSize',50);
Визуализируйте эффективность классификации как матрицу неточностей.
figure confusionchart([predFilteredTest{:}],[testLabels{:}],'Normalization','column-normalized');
Простая предварительная обработка улучшает классификацию Т-волн примерно на 15%, и классификацию QRS-комплекса и Р-волн примерно на 10%.
Общий подход для успешной классификации данного timeseries состоит в том, чтобы извлечь функции и передать их в сеть вместо исходных данных. Затем сеть изучает шаблоны между временем и частотой одновременно [7].
Synchrosqueezed преобразование Фурье (FSST) вычисляет частотный спектр для каждой выборки сигнала, поэтому он идеально подходит для рассматриваемой задачи сегментации, где нам нужно поддерживать то же временное разрешение, что и исходные сигналы. Используйте fsst
функция для проверки преобразования одного из обучающих сигналов. Задайте окно Кайзера длины 128, чтобы обеспечить адекватное разрешение частоты.
data = preview(trainDs);
figure
fsst(data{1,1},250,kaiser(128),'yaxis')
Вычислите FSST каждого сигнала в обучающем наборе данных в интересующей частотной области значений [0,5, 40] Гц. Относитесь к реальным и мнимым частям FSST как к отдельным функциям и подайте оба компонента в сеть. Кроме того, стандартизируйте функции путем вычитания среднего и деления на стандартное отклонение. Используйте преобразованный datastore, extractFSSTFeatures
вспомогательная функция и tall
функция для параллельной обработки данных.
fsstTrainDs = transform(trainDs,@(x)extractFSSTFeatures(x,250)); fsstTallTrainSet = tall(fsstTrainDs); fsstTrainData = gather(fsstTallTrainSet);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: 0% complete Evaluation 0% complete
- Pass 1 of 1: Completed in 2 min 35 sec Evaluation completed in 2 min 35 sec
Повторите эту процедуру для данных проверки.
fsstTTestDs = transform(testDs,@(x)extractFSSTFeatures(x,250)); fsstTallTestSet = tall(fsstTTestDs); fsstTestData = gather(fsstTallTestSet);
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 1 min 4 sec Evaluation completed in 1 min 4 sec
Измените архитектуру LSTM так, чтобы сеть приняла частотный спектр для каждой выборки вместо одного значения. Проверьте размер FSST, чтобы увидеть количество частот.
size(fsstTrainData{1,1})
ans = 1×2
40 5000
Задайте sequenceInputLayer
из 40 входных функций. Оставьте оставшиеся параметры сети неизменными.
layers = [ ... sequenceInputLayer(40) lstmLayer(200,'OutputMode','sequence') fullyConnectedLayer(4) softmaxLayer classificationLayer];
Обучите обновленную сеть LSTM с помощью преобразованного набора данных.
if actionFlag == "Train networks" fsstNet = trainNetwork(fsstTrainData(:,1),fsstTrainData(:,2),layers,options); end
Использование функций повышает точность обучения, которая теперь превышает 90%.
Используя обновленную сеть LSTM и извлеченные функции FSST, классифицируйте данные проверки.
predFsstTest = classify(fsstNet,fsstTestData(:,1),'MiniBatchSize',50);
Визуализируйте эффективность классификации как матрицу неточностей.
confusionchart([predFsstTest{:}],[fsstTestData{:,2}],'Normalization','column-normalized');
Использование представления частота-время улучшает классификацию Т-волн примерно на 25%, классификацию Р-волн примерно на 40% и классификацию QRS-комплекса на 30%, по сравнению с результатами необработанных данных.
Использование signalMask
объект для сравнения сетевого предсказания с метками основной истины для одного сигнала ECG. Игнорируйте "n/a"
метки при построении графика необходимых областей.
testData = gather(tall(testDs));
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: 0% complete Evaluation 0% complete
- Pass 1 of 1: Completed in 37 sec Evaluation completed in 37 sec
Mtest = signalMask(testData{1,2}(3000:4000)); Mtest.SpecifySelectedCategories = true; Mtest.SelectedCategories = find(Mtest.Categories ~= "n/a"); figure subplot(2,1,1) plotsigroi(Mtest,testData{1,1}(3000:4000)) title('Ground Truth') Mpred = signalMask(predFsstTest{1}(3000:4000)); Mpred.SpecifySelectedCategories = true; Mpred.SelectedCategories = find(Mpred.Categories ~= "n/a"); subplot(2,1,2) plotsigroi(Mpred,testData{1,1}(3000:4000)) title('Predicted')
Этот пример показал, как предварительная обработка сигнала и частотно-временной анализ могут улучшить эффективность сегментации формы сигнала LSTM. Фильтрация полосой пропускания и синхронизация на основе Фурье приводят к среднему улучшению по всем выходным классам с 55% до около 85%.
[1] McSharry, Patrick E., et al. Динамическая модель для генерации синтетических электрокардиограммных сигналов. Транзакции IEEE ® по биомедицинской инженерии. Том 50, № 3, 2003, стр. 289-294.
[2] Лагуна, Пабло, Раймон Жане и Пере Каминаль. «Автоматическое обнаружение контуров волны в многоуровневых сигналах ЭКГ: валидация с базой данных CSE». Компьютеры и биомедицинские исследования. Том 27, № 1, 1994, стр. 45-60.
[3] Голдбергер, Ари Л., Луис А. Н. Амарал, Леон Гласс, Джеффри М. Хаусдорф, Пламен Ч. Иванов, Роджер Г. Марк, Джозеф Е. Миетус, Джордж Б. Муди, Чунг-Канг Пенг PhysioBank, PhysioToolkit и PhysioNet: компоненты нового исследовательского ресурса комплексных физиологических сигналов. Циркуляция. Том 101, № 23, 2000, стр. e215-e220. [Тиражные электронные страницы; http://circ.ahajournals.org/content/101/23/e215.full].
[4] Лагуна, Пабло, Роджер Г. Марк, Ари Л. Голдбергер и Джордж Б. Муди. «База данных для оценки алгоритмов измерения интервалов QT и других сигналов в ЭКГ». Компьютеры в кардиологии. Vol.24, 1997, стр 673–676.
[5] Sörnmo, Leif, and Pablo Laguna. «Обработка сигнала электрокардиограммы (ЭКГ)». Wiley Encyclopedia of Biomedical Engineering, 2006.
[6] Kohler, B-U., Carsten Hennig, and Reinhold Orglmeister. «Принципы обнаружения QRS программного обеспечения». IEEE Engineering in Medicine and Biology Magazine. Том 21, № 1, 2002, стр. 42-57.
[7] Саламон, Джастин и Хуан Пабло Белло. Глубокие сверточные нейронные сети и увеличение данных для классификации звука окружающей среды. Буквы обработки сигналов IEEE. Том 24, № 3, 2017, с. 279-283.
confusionchart
| lstmLayer
| trainingOptions
| trainNetwork
| fsst
(Signal Processing Toolbox) | labeledSignalSet
(Набор Signal Processing Toolbox)