Main Content

이 페이지의 내용은 이전 릴리스에 관한 것입니다. 해당 영문 페이지는 최신 릴리스에서 제거되었습니다.

딥러닝을 사용한 파형 분할

이 예제에서는 순환 딥러닝 신경망과 시간-주파수 분석을 사용하여 사람의 심전도(ECG) 신호를 분할하는 방법을 다룹니다.

소개

사람 심장의 전기 활동은 기준 신호에서 벗어난 일련의 진폭으로 측정할 수 있습니다. 단일 정상 심박 주기의 경우 심전도 신호를 다음 심박 모폴로지로 나눌 수 있습니다 [1].

  • P파 — 심방 탈분극을 나타내는 QRS 복합파 이전의 작은 편향

  • QRS 복합파 — 심박의 최대 진폭 부분

  • T파 — 심실 재분극을 나타내는 QRS 복합파 이후의 작은 편향

심전도 파형의 이 영역을 분할하여 사람 심장의 전반적인 상태 및 이상 유무를 가늠하는 데 유용한 측정 기준을 마련할 수 있습니다 [2]. 심전도 신호의 각 영역에 수동으로 주석을 다는 것은 번거롭고 오랜 시간이 소요되는 작업일 수 있습니다. 신호 처리 및 딥러닝 방법은 관심 영역에 주석을 다는 작업을 간소화하고 자동화하는 데 도움이 될 수 있습니다.

이 예제에서는 공개적으로 사용 가능한 QT Database의 심전도 신호를 사용합니다 [3] [4]. 이 데이터는 총 105명의 환자로부터 측정한 샘플 레이트 250Hz의 약 15분 분량의 심전도 기록으로 구성되었습니다. 검사자가 각 기록을 얻기 위해 환자의 가슴에 서로 다른 위치에 두 전극을 설치했기 때문에 2채널 신호를 얻었습니다. 이 데이터베이스는 자동화된 전문가 시스템에서 생성한 신호 영역 레이블을 제공합니다 [2]. 이 예제는 딥러닝을 통해 샘플이 위치한 영역에 따라 개개의 심전도 신호 샘플에 레이블을 지정하는 것을 목적으로 합니다. 신호의 전 범위에서 관심 영역에 레이블을 지정하는 이 과정은 파형 분할이라고도 합니다.

신호 영역을 분류하도록 심층 신경망을 훈련시키기 위해 LSTM(장단기 기억) 신경망을 사용할 수 있습니다. 이 예제에서는 신호 전처리 기법 및 시간-주파수 분석을 활용하여 LSTM 분할 성능을 향상하는 방법을 보여줍니다. 특히 이 예제에서는 푸리에 싱크로스퀴즈 변환을 사용하여 심전도 신호의 비정상적 동작을 나타냅니다.

데이터 다운로드 및 준비

105개의 2채널 심전도 신호의 각 채널은 자동화된 전문가 시스템에 의해 개별적으로 레이블이 지정되었으며, 210 MAT 파일에 영역 레이블을 지정하여 함께 저장된 총 210개 심전도 신호에 대해 개별적으로 처리됩니다. 이 파일은 https://www.mathworks.com/supportfiles/SPT/data/QTDatabaseECGData.zip에서 받을 수 있습니다.

데이터 파일을 임시 디렉터리로 다운로드합니다. 임시 디렉터리의 위치는 MATLAB®의 tempdir 명령으로 지정됩니다. tempdir이 아닌 폴더에 데이터 파일을 저장하려는 경우 이후 지침에서 디렉터리 이름을 이에 맞게 변경하십시오.

% Download the data
dataURL = 'https://www.mathworks.com/supportfiles/SPT/data/QTDatabaseECGData.zip';
datasetFolder = fullfile(tempdir,'QTDataset');
zipFile = fullfile(tempdir,'QTDatabaseECGData.zip');
if ~exist(datasetFolder,'dir')
     websave(zipFile,dataURL);
end

% Unzip the data
unzip(zipFile,tempdir)

unzip 작업은 임시 디렉터리에 210개의 MAT 파일이 들어 있는 QTDatabaseECGData 폴더를 만듭니다. 각 파일은 변수 ecgSignal에 심전도 신호를 포함하고 변수 signalRegionLabels에 영역 레이블로 구성된 테이블을 포함합니다. 각 파일은 변수 Fs에 신호의 샘플 레이트도 포함합니다. 이 예제에서 모든 신호의 샘플 레이트는 250Hz입니다.

파일의 데이터에 액세스할 수 있도록 신호 데이터저장소를 만듭니다. 이 예제에서는 데이터셋이 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"]

read 함수를 호출할 때마다 데이터저장소는 심전도 신호와 영역 레이블로 구성된 테이블을 포함하는, 요소를 2개 가진 셀형 배열을 반환합니다. 데이터저장소의 preview 함수를 사용하여 첫 번째 파일의 내용은 225,000개 샘플로 이루어진 심전도 신호와 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 

displayWaveformLabels 헬퍼 함수를 사용하여 첫 1,000개 샘플에 대한 레이블을 시각화합니다.

displayWaveformLabels(data,true,1000)

일반적인 머신러닝 분류 절차는 다음과 같습니다.

  1. 데이터베이스를 훈련 데이터셋 및 테스트 데이터셋으로 나눕니다.

  2. 훈련 데이터셋을 사용하여 신경망을 훈련시킵니다.

  3. 훈련된 신경망을 사용하여 테스트 데이터셋에 대해 예측을 수행합니다.

데이터의 70%로 신경망을 훈련시키고 나머지 30%로 테스트합니다.

재현 가능한 결과를 얻기 위해 난수 생성기를 재설정합니다. dividerand 함수를 사용하여 임의의 인덱스를 얻어 파일을 섞고, signalDatastoresubset 함수를 사용하여 데이터를 훈련 데이터저장소와 테스트 데이터저장소로 나눕니다.

rng default
[trainIdx,~,testIdx] = dividerand(numel(sds.Files),0.7,0,0.3);
trainDs = subset(sds,trainIdx);
testDs = subset(sds,testIdx);

이 분할 문제에서 LSTM 신경망에 대한 입력값은 심전도 신호이고 출력값은 입력 신호와 길이가 같은 시퀀스 또는 레이블로 구성된 마스크입니다. 신경망의 임무는 각 신호 샘플에 해당 샘플이 속하는 영역의 이름을 레이블로 지정하는 것입니다. 따라서 데이터셋의 영역 레이블을 신호 샘플당 하나의 레이블을 포함하는 시퀀스로 변환해야 합니다. 변환된 데이터저장소와 roi2mask 헬퍼 함수를 사용하여 레이블을 변환합니다. 변환된 데이터저장소를 미리 보고 데이터저장소가 동일한 길이의 신호 벡터와 레이블 벡터를 반환함을 확인합니다. categorical형 마스크 벡터의 처음 1000개 요소를 플로팅합니다. roi2mask 함수는 레이블 범주 n/a를 추가하여 관심 영역에 속하지 않는 샘플에 레이블을 지정합니다.

trainDs = transform(trainDs, @roi2mask);
testDs = transform(testDs, @roi2mask);

transformedData = preview(trainDs)
transformedData=1×2 cell array
    {224993×1 double}    {224993×1 categorical}

plot(transformedData{2}(1:1000))

LSTM 신경망에 매우 긴 입력 신호를 전달하면 추정 성능이 저하되고 메모리가 과도하게 사용될 수 있습니다. 이러한 효과를 방지하려면 변환된 데이터저장소와 resizeData 헬퍼 함수를 사용하여 심전도 신호 및 그에 대응되는 레이블 마스크를 분할하십시오. 헬퍼 함수는 5000개 샘플로 구성된 세그먼트를 가능한 한 많이 만들고 나머지 샘플은 무시합니다. 변환된 데이터저장소의 출력값을 미리 보면 첫 번째 심전도 신호와 그 레이블 마스크가 5000개 단위의 샘플 세그먼트들로 분할된 것을 볼 수 있습니다. 변환된 데이터저장소의 미리보기는 데이터저장소 read 함수를 호출했다면 결과로 생성되었을 floor(224993/5000) = 44개 요소를 가진 셀형 배열의 처음 8개 요소만 보여줍니다.

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 신경망에 직접 원시 심전도 신호 입력하기

우선, 훈련 데이터셋의 원시 심전도 신호를 사용하여 LSTM 신경망을 훈련시킵니다.

훈련에 앞서 신경망 아키텍처를 정의합니다. 1차원 시계열을 받을 수 있도록 sequenceInputLayer의 크기를 1로 지정하십시오. 신호의 각 샘플에 대해 분류하기 위해 'sequence' 출력 모드를 사용해 LSTM 계층을 지정합니다. 최적의 성능을 위해 200개의 숨겨진 노드를 사용합니다. 각각의 파형 클래스에 하나씩 할당할 수 있도록 fullyConnectedLayer의 출력 크기를 4로 지정합니다. softmaxLayerclassificationLayer를 추가하여 추정된 레이블을 출력합니다.

layers = [ ...
    sequenceInputLayer(1)
    lstmLayer(200,'OutputMode','sequence')
    fullyConnectedLayer(4)
    softmaxLayer
    classificationLayer];

우수한 신경망 성능을 보장할 수 있도록 훈련 과정에 대한 옵션을 선택합니다. 각 파라미터에 대한 설명은 trainingOptions (Deep Learning Toolbox) 문서를 참조하십시오.

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);

전체 훈련 데이터셋이 다 메모리에 담기므로 Parallel Computing Toolbox™가 있다면 데이터저장소의 tall 함수를 사용하여 데이터를 병렬로 변환한 다음 이를 작업 공간으로 불러모을 수 있습니다. 신경망 훈련은 반복적인 작업입니다. 매회 반복에서 데이터저장소가 파일에서 데이터를 읽어 들이고 데이터를 변환한 후에 신경망 계수를 업데이트합니다. 데이터가 컴퓨터의 메모리에 다 담긴다면 데이터를 작업 공간으로 가져오는 편이 데이터를 한 번만 읽고 변환하게 되므로 훈련 속도가 더 빠릅니다. 데이터가 메모리에 담기지 않는다면 데이터저장소를 훈련 함수에 전달해야 하며, 변환은 매 훈련 Epoch마다 수행됩니다.

훈련 세트와 테스트 세트를 위한 tall형 배열을 만듭니다. MATLAB이 만드는 병렬 풀의 워커 개수는 시스템에 따라 달라질 수 있습니다.

tallTrainSet = tall(trainDs);
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 8).
tallTestSet = tall(testDs);

이제 tall형 배열의 gather 함수를 호출하여 전체 데이터셋에 대해 변환을 계산하고 훈련 및 테스트 신호와 레이블이 지정된 셀형 배열을 얻습니다.

 trainData = gather(tallTrainSet);
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: 0% complete
Evaluation 0% complete
- Pass 1 of 1: Completed in 28 sec
Evaluation completed in 28 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 9.8 sec
Evaluation completed in 10 sec

신경망 훈련시키기

trainNetwork 명령을 사용하여 LSTM 신경망을 훈련시킵니다. 데이터셋이 크기 때문에 이 과정은 시간이 꽤 걸릴 수 있습니다. 시스템에 GPU와 Parallel Computing Toolbox™가 있는 경우 MATLAB은 자동으로 훈련에 GPU를 사용합니다. GPU가 없으면 CPU를 사용합니다.

아래 Figure의 훈련 정확도 및 손실 서브플롯은 모든 반복 과정에 걸쳐 훈련 진행 상황을 추적합니다. 신경망은 원시 신호 데이터를 사용하여 약 77%의 샘플에 대해 P파, QRS 복합파, T파 또는 N/A인지 여부를 올바르게 분류합니다.

net = trainNetwork(trainData(:,1),trainData(:,2),layers,options);

테스트 데이터 분류하기

훈련된 LSTM 신경망 및 classify 명령을 사용하여 테스트 데이터를 분류합니다. 훈련 옵션과 일치하도록 미니 배치 크기를 50으로 지정합니다.

predTest = classify(net,testData(:,1),'MiniBatchSize',50);

정오분류표는 분류 성능을 시각화하는 직관적이며 유용한 수단입니다. confusionchart 명령을 사용하여 테스트 데이터 예측값에 대한 전체적인 분류 정확도를 계산합니다. 각 입력값에 대해, categorical형 레이블로 구성된 셀형 배열을 행 벡터로 변환합니다. 각 클래스에 대해 샘플의 백분율로 결과를 표시하기 위해 열 정규화된 디스플레이를 지정합니다.

confusionchart([predTest{:}],[testData{:,2}],'Normalization','column-normalized');

원시 심전도 신호를 신경망에 대한 입력값으로 사용한 경우 T파 샘플의 약 60%, P파 샘플의 40%, QRS 복합파 샘플의 60%만 올바르게 분류했습니다. 성능을 높이려면 입력 전에 심전도 신호 특성에 관한 지식(예를 들어 환자의 호흡 동작에 의한 기준선 변동)을 딥러닝 신경망에 적용합니다.

기준선 변동 및 고주파 잡음을 제거하기 위해 필터링 방법 적용하기

세 심박 모폴로지는 서로 다른 주파수 대역에 있습니다. QRS 복합파의 스펙트럼은 대개 중앙 주파수가 약 10~25Hz이며, 그 성분은 40Hz 아래에 있습니다. P파와 T파는 훨씬 더 낮은 주파수에서 발생합니다. P파 성분이 20Hz 미만, T파 성분이 10Hz 미만입니다[5].

기준선 변동은 환자의 호흡 동작으로 인해 발생하는 저주파(< 0.5Hz) 진동입니다. 이 진동은 심박 모폴로지와 상관없으며 유의미한 정보를 제공하지 않습니다[6].

기준선 변동 및 모든 고주파 잡음을 제거하려면 [0.5, 40]Hz의 통과대역 주파수 범위로 대역통과 필터를 설계하십시오. 이 성분을 제거하면 신경망이 불필요한 특징을 학습하지 않으므로 LSTM 훈련이 향상됩니다. tall형 데이터 셀형 배열에 대해 cellfun을 사용하여 데이터셋을 병렬로 필터링합니다.

% 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 19 sec
Evaluation completed in 19 sec
trainLabels = gather(tallTrainSet(:,2));
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: Completed in 19 sec
Evaluation completed in 19 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 8.5 sec
Evaluation completed in 8.6 sec
testLabels = gather(tallTestSet(:,2));
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: Completed in 8.3 sec
Evaluation completed in 8.5 sec

일반적인 경우의 원시 및 필터링된 신호를 플로팅합니다.

trainData = gather(tallTrainSet);
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: Completed in 19 sec
Evaluation completed in 19 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 신경망을 훈련시킵니다.

filteredNet = trainNetwork(filteredTrainSignals,trainLabels,layers,options);

신호를 전처리하면 훈련 정확도가 향상되어 80%를 넘어섭니다.

필터링된 심전도 신호 분류하기

업데이트된 LSTM 신경망을 사용하여 전처리된 테스트 데이터를 분류합니다.

predFilteredTest = classify(filteredNet,filteredTestSignals,'MiniBatchSize',50);

분류 성능을 정오분류표로 시각화합니다.

figure
confusionchart([predFilteredTest{:}],[testLabels{:}],'Normalization','column-normalized');

단순 전처리를 수행하면 T파 분류가 약 15%, QRS 복합파 분류가 10% 향상됩니다. P파 분류 정확도는 변경되지 않았습니다.

심전도 신호의 시간-주파수 표현

시계열 데이터를 성공적으로 분류하기 위해 흔히 사용하는 접근법 중 하나는 시간-주파수 특징을 추출하여 이를 원본 데이터 대신 신경망에 제공하는 것입니다. 그러면 신경망은 시간 및 주파수에 걸쳐 패턴을 동시에 학습합니다[7].

푸리에 싱크로스퀴즈 변환(FSST)은 각각의 신호 샘플에 대한 주파수 스펙트럼을 계산하므로 원본 신호와 동일한 시간 분해능을 유지해야 하는 이 분할 문제에 이상적입니다. fsst 함수를 사용하여 훈련 신호 중 하나에 대한 변환을 살펴봅니다. 적합한 주파수 분해능을 제공하기 위해 길이가 128인 카이저 윈도우를 지정합니다.

data =  preview(trainDs);
figure
fsst(data{1,1},250,kaiser(128),'yaxis')

관심 주파수 범위 [0.5, 40]Hz에 대해 훈련 데이터셋에 있는 각 신호의 FSST를 계산합니다. FSST의 실수부와 허수부를 서로 다른 특징으로 간주하고 두 성분을 모두 신경망에 입력합니다. 또한, 평균을 빼고 표준편차로 나누어 훈련 특징을 표준화합니다. 변환된 데이터저장소, 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 23 sec
Evaluation completed in 1 min 23 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];

심전도 신호의 FSST를 사용하여 신경망 훈련시키기

변환된 데이터셋을 사용하여 업데이트된 LSTM 신경망을 훈련시킵니다.

fsstNet = trainNetwork(fsstTrainData(:,1),fsstTrainData(:,2),layers,options);

시간-주파수 특징을 사용하면 훈련 정확도가 향상되어 이제는 90%가 넘습니다.

FSST를 사용하여 테스트 데이터 분류하기

업데이트된 LSTM 신경망 및 추출된 FSST 특징을 사용하여 테스트 데이터를 분류합니다.

predFsstTest = classify(fsstNet,fsstTestData(:,1),'MiniBatchSize',50);

분류 성능을 정오분류표로 시각화합니다.

confusionchart([predFsstTest{:}],[fsstTestData{:,2}],'Normalization','column-normalized');

시간-주파수 표현을 사용하면 원시 데이터 결과에 비해 T파 분류가 약 20%, P파 분류가 약 40%, QRS 복합파 분류가 30% 향상됩니다.

displayWaveformLabels 헬퍼 함수를 사용하여 단일 심전도 신호에 대한 실측 레이블과 신경망 예측을 비교합니다.

testData = gather(tall(testDs));
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: Completed in 8.3 sec
Evaluation completed in 8.5 sec
figure
subplot(2,1,1)
displayWaveformLabels({testData{1,1}(3000:4000),testData{1,2}(3000:4000)},false)
title('Ground Truth')

subplot(2,1,2)
displayWaveformLabels({testData{1,1}(3000:4000),predFsstTest{1}(3000:4000)},false)
title('Predicted')

결론

이 예제에서는 신호 전처리 및 시간-주파수 분석으로 LSTM 파형 분할 성능을 높일 수 있는 방법을 다뤘습니다. 대역통과 필터 및 푸리에 기반 싱크로스퀴징 때문에 모든 출력 클래스에 걸쳐 평균적으로 55%에서 약 85%로 성능이 향상되었습니다.

참고 문헌

[1] McSharry, Patrick E., et al. "A dynamical model for generating synthetic electrocardiogram signals." IEEE® Transactions on Biomedical Engineering. Vol. 50, No. 3, 2003, pp. 289–294.

[2] Laguna, Pablo, Raimon Jané, Pere Caminal. "Automatic detection of wave boundaries in multilead ECG signals: Validation with the CSE database." Computers and Biomedical Research. Vol. 27, No. 1, 1994, pp. 45–60.

[3] Goldberger, Ary L., Luis A. N. Amaral, Leon Glass, Jeffery M. Hausdorff, Plamen Ch. Ivanov, Roger G. Mark, Joseph E. Mietus, George B. Moody, Chung-Kang Peng, H. Eugene Stanley. "PhysioBank, PhysioToolkit, and PhysioNet: Components of a New Research Resource for Complex Physiologic Signals." Circulation. Vol. 101, No. 23, 2000, pp. e215–e220. [Circulation Electronic Pages, http://circ.ahajournals.org/content/101/23/e215.full].

[4] Laguna, Pablo, Roger G. Mark, Ary L. Goldberger, George B. Moody. "A Database for Evaluation of Algorithms for Measurement of QT and Other Waveform Intervals in the ECG." Computers in Cardiology. Vol.24, 1997, pp. 673–676.

[5] Sörnmo, Leif, Pablo Laguna. "Electrocardiogram (ECG) signal processing." Wiley Encyclopedia of Biomedical Engineering, 2006.

[6] Kohler, B-U., Carsten Hennig, Reinhold Orglmeister. "The principles of software QRS detection." IEEE Engineering in Medicine and Biology Magazine. Vol. 21, No. 1, 2002, pp. 42–57.

[7] Salamon, Justin, Juan Pablo Bello. "Deep convolutional neural networks and data augmentation for environmental sound classification." IEEE Signal Processing Letters. Vol. 24, No. 3, 2017, pp. 279–283.

참고 항목

함수

관련 항목