이 페이지의 최신 내용은 아직 번역되지 않았습니다. 최신 내용은 영문으로 볼 수 있습니다.

데이터에서 신호 찾기

이 예제에서는 findsignal을 사용하여 데이터에서 시변 신호를 찾는 방법을 보여줍니다. 여기에는 거리 측정법을 사용하여 정확하게 일치하는 신호와 근사하게 일치하는 신호를 찾는 방법, 느리게 변하는 오프셋을 보정하는 방법, 동적 시간 굽힘(Dynamic Time Warping)을 사용하여 가변적인 샘플링을 허용하는 방법에 대한 예제가 포함됩니다.

정확히 일치하는 부분 찾기

신호에서 수치적으로 정확히 일치하는 부분을 찾으려면 strfind를 사용하여 일치 여부를 확인하면 됩니다.

예를 들어, 다음과 같은 데이터 벡터가 있고

data = [1 4 3 2 55 2 3 1 5 2 55 2 3 1 6 4 2 55 2 3 1 6 4 2];

다음 신호의 위치를 찾으려는 경우

signal = [55 2 3 1];

신호와 데이터가 수치적으로 정확한 경우에 한해 strfind를 사용하여 데이터에서 신호가 존재하는 위치를 나타내는 시작 인덱스를 찾을 수 있습니다.

iStart = strfind(data,signal)
iStart = 1×3

     5    11    18

가장 근접하게 일치하는 신호 찾기

strfind수치적으로 정확히 일치하는 항목을 찾는 데 적합합니다. 그러나, 이 접근 방식은 양자화 잡음 또는 기타 아티팩트로 인한 오차가 신호에 존재하는 경우 실패합니다.

예를 들어, 다음과 같은 사인파가 있고

data = sin(2*pi*(0:25)/16);

다음 신호의 위치를 찾으려는 경우

signal = cos(2*pi*(0:10)/16);

strfind는 5번째 샘플에서 시작하는 데이터에서 정현파를 찾을 수 없습니다.

iStart = strfind(data,signal)
iStart =

     []

strfind는 반올림 오차로 인해 일부 값이 수치적으로 같지 않기 때문에 데이터에서 신호를 찾을 수 없습니다. 이를 확인하기 위해 일치하는 영역의 신호에서 해당 데이터를 뺍니다.

data(5:15) - signal
ans = 1×11
10-15 ×

         0         0         0    0.0555    0.0612    0.0555         0    0.2220         0    0.2220         0

수치적으로 1e-15에 가까운 차이가 있습니다.

findsignal을 사용하여 이를 해결할 수 있습니다. 이 함수는 기본적으로 데이터에서 신호를 스윕하고 각 위치에서 국소적으로 데이터와 신호 간 차이의 제곱합을 계산하여 가장 낮은 합계를 찾습니다.

신호와 데이터에서 가장 잘 일치하는 부분을 강조 표시하여 플롯을 생성하려면 다음과 같이 findsignal을 호출하면 됩니다.

findsignal(data,signal)

임계값 미만의 가장 근접하게 일치하는 부분 찾기

기본적으로 findsignal은 항상 신호에서 데이터와 가장 근접하게 일치하는 부분을 반환합니다. 여러 개의 일치하는 부분을 반환하려면 차이의 최대 제곱합에 대한 한도를 지정하면 됩니다.

data = sin(2*pi*(0:100)/16);
signal = cos(2*pi*(0:10)/16);

findsignal(data,signal,'MaxDistance',1e-14)

findsignal은 일치하는 부분들을 근접성을 기준으로 정렬하여 반환합니다.

[iStart, iStop, distance] = findsignal(data,signal,'MaxDistance',1e-14);
fprintf('iStart iStop  total squared distance\n')
iStart iStop  total squared distance
fprintf('%4i %5i     %.7g\n',[iStart; iStop; distance])
  37    47     0
  69    79     0
  85    95     0
   5    15     1.776357e-15
  21    31     1.776357e-15
  53    63     1.776357e-15

변화하는 오프셋을 통해 복소 신호 궤적 검색하기

다음 예제에서는 findsignal을 사용하여 알려진 궤적을 추적하는 신호를 찾는 방법을 보여줍니다. "cursiveex.mat" 파일에는 종이에 펜으로 "phosphorescence"라는 단어를 썼을 때 펜 끝의 x 위치와 y 위치에 대한 기록이 포함되어 있습니다. x,y 데이터는 각각 복소 신호의 실수 성분과 허수 성분으로 인코딩됩니다.

load cursiveex
plot(data)
xlabel('real')
ylabel('imag')

같은 사람이 템플릿 신호로 문자 "p"를 썼습니다.

plot(signal)
title('signal')
xlabel('real')
ylabel('imag')

데이터에서 첫 번째 "p"는 findsignal을 사용하여 쉽게 찾을 수 있습니다. 이는 신호 값이 데이터 시작 부분에서는 상당히 잘 정렬되기 때문입니다.

findsignal(data,signal)

그러나, 두 번째로 나오는 "p"에는 findsignal이 식별하기 어렵게 만드는 두 가지 특성이 있습니다. 즉, 첫 번째 문자로부터 일정한 크기의 상당히 큰 오프셋이 있으며, 문자의 일부분이 템플릿 신호와 다른 속도로 그려졌습니다.

문자의 전체적인 모양만 일치시키려는 경우에는 신호 요소와 데이터 요소 모두에서 윈도우가 적용된 국소 평균을 뺄 수 있습니다. 그러면 일정한 크기의 이동에 따른 영향을 완화할 수 있습니다.

검색을 수행할 때 신호 또는 데이터를 공통 시간 베이스로 늘이는 동적 시간 굽힘(Dynamic Time Warping)을 사용하면 문자가 그려지는 속도의 변화로 인한 영향을 완화할 수 있습니다.

findsignal(data,signal,'TimeAlignment','dtw', ...
               'Normalization','center', ...
               'NormalizationLength',600, ...
               'MaxNumSegments',2)

시간을 늘인 전력 신호 찾기

다음 예제에서는 findsignal을 사용하여 문구에서 음성 단어의 위치를 찾는 방법을 보여줍니다.

다음 파일에는 같은 사람의 음성으로 "Accelerating the pace of engineering and science"라는 문구를 녹음한 오디오와 "engineering" 문구를 녹음한 별도의 오디오가 들어 있습니다.

load slogan
soundsc(phrase,fs)
soundsc(hotword,fs)

일반적으로, 같은 사람이 한 문장이나 문구를 말할 때 개별 단어를 달리 발음합니다. 이 예제에서는 다음 두 가지 다른 방법으로 "engineering"을 발음했습니다. 문구 내에서 이 단어를 발음할 때 데 약 0.5초가 걸렸으며 두 번째 음절에 강세를 두었습니다("en-GIN-eer-ing"). 같은 사람이 단어만 따로 발음할 때는 0.75초가 걸렸으며, 세 번째 음절에 강세를 두었습니다("en-gin-EER-ing").

시간과 음량 모두에서 이러한 국소적 변동을 보정하려면, 스펙트럼 전력 분포가 시간에 따라 달라지므로 스펙트로그램을 사용하여 스펙트럼 전력 분포를 보고해야 합니다.

처음에는 상당히 성긴 주파수 분해능으로 스펙트로그램을 사용하십시오. 이는 구강 및 비강의 더 넓은 대역 공명을 방해받지 않게 둔 채, 성도의 협대역 성문 펄스를 의도적으로 흐릿하게 설정하기 위한 것입니다. 그러면 음성 단어에서 모음을 추적할 수 있습니다. 자음(특히 파열음 및 마찰음)은 스펙트로그램을 사용하여 식별하기가 훨씬 어렵습니다. 아래 코드에서는 스펙트로그램을 계산합니다.

Nwindow = 64;
Nstride = 8;
Beta = 64;

Noverlap = Nwindow - Nstride;
[~,~,~,PxxPhrase] = spectrogram(phrase, kaiser(Nwindow,Beta), Noverlap);
[~,~,~,PxxHotWord] = spectrogram(hotword, kaiser(Nwindow,Beta), Noverlap);

문구와 검색어에 대한 스펙트로그램이 계산되었으므로 동적 시간 굽힘(Dynamic Time Warping)을 사용하여 단어 길이의 국소적 변동을 파악할 수 있습니다. 이와 유사하게, 대칭적 쿨백-라이블러 거리(Kullback-Leibler Distance)와 함께 전력 정규화를 사용하여 전력 변동을 파악할 수 있습니다.

[istart,istop] = findsignal(PxxPhrase, PxxHotWord, ...
    'Normalization','power','TimeAlignment','dtw','Metric','symmkl')
istart = 1144
istop = 1575

식별된 단어를 플로팅하고 재생합니다.

findsignal(PxxPhrase, PxxHotWord, 'Normalization','power', ...
    'TimeAlignment','dtw','Metric','symmkl')

soundsc(phrase(Nstride*istart-Nwindow/2 : Nstride*istop+Nwindow/2),fs)