Main Content

データ内の信号の検出

この例では、関数 findsignal を使用して、データ内の時変信号を検出します。これには、距離計量を使用して完全に一致している信号およびほぼ一致している信号を検出する方法、ゆっくり変化するオフセットを補正する方法、および動的タイム ワーピングを使用してサンプリングのばらつきを許可する方法の例が含まれます。

完全一致の検索

信号の "数値的に厳密な" 一致を検索する場合は、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])
   5    15     0
  37    47     0
  69    79     0
  21    31     1.776357e-15
  53    63     1.776357e-15
  85    95     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')

findsignal を使用すると、データ内の最初の "p" を非常に簡単に見つけることができます。これは信号の値がデータの最初に非常に良く整列しているからです。

findsignal(data,signal)

ただし、2 番目の "p" には、findsignal による識別を困難にする 2 つの特性があります。これには重要ながらも最初の文字から一定のオフセットがあり、文字の部分はテンプレート信号とは異なる速度で描かれています。

文字の全体の形状に一致することだけに関心がある場合は、ウィンドウ処理された局所的な平均を信号とデータ要素の両方から除去できます。これにより、定数シフトの影響を軽減できます。

文字が描かれた際の速度の違いの影響を軽減するため、検索を実行する際に信号またはデータを共通の時間ベースに引き伸ばす動的タイム ワーピングを使用できます。

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" を 2 つの異なる方法で発音しています。話者はフレーズ内でこの単語をおよそ 0.5 秒かけて発音し、2 番目の音節 ("en-GIN-eer-ing") にアクセントを置いています。同じ話者が単語を個別に発音した場合には、0.75 秒かかっており、3 番目の音節 ("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);

これでフレーズと検索語のスペクトログラムが入手できたので、動的タイム ワーピングを使用して単語の長さにおける局所的なばらつきを説明することができます。同様に、パワー正規化を対称カルバック・ライブラー距離と併用して、パワー内のばらつきを説明することができます。

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

参考