時系列データをトリガ検出してから切り出すと、毎回決まった位置でデータ収集できるため後処理が容易になります。Pythonでは標準でトリガ検出機能は存在しないため、ここでは独自に考案したトリガ検出アルゴリズムを解説します。
こんにちは。wat(@watlablog)です。
信号処理には時間波形の切り出し方法としてトリガ検出を使う場合があります。ここではトリガ検出機能を作ってみた結果を紹介します。
トリガ検出について
トリガ検出とは?
トリガ(Trigger)とは、元々銃等の「引き金」のことを意味しますが、現在は「〇〇をトリガとして△△を開始する」といったように、何かの合図としての意味を持たせて使っています。
信号処理の分野ではトリガ信号と呼ばれる位置検出用の信号を用いて、測定データを毎回決まった位置から収集するといったことをよくしています。例えば、オシロスコープでサイン波を観察する時に、サイン波自体、または位相が同期したトリガ信号を使うことで、波形の形の変化が視認しやすくなります。
以下はトリガ信号のイメージ図です。時系列データは通常任意のフレームサイズ毎にデータを収集します。ここで、トリガレベルを設定すると、その値になる波形の位置を検出します。これをトリガ位置と呼び、一連の計算をトリガ検出と呼びます。
自作するトリガ検出アルゴリズム
このページではトリガ検出のアルゴリズムを解説しますが、筆者の完全思い付きであることに注意して下さい。
自作した理由はPythonでは標準のライブラリやインポートパッケージに、中々それらしい関数が存在しなかったためです(探せばあるかも知れませんが、僕は探せませんでした…)。
アルゴリズムの図解イメージを以下に示します。上の図でトリガレベルを設定した値が実際に探したい値ですが、単純にその値になるかどうかを値として比較する場合は、if文を多用したり、エッジの上下検出で場合分けが複雑になりそうであったため、まずトリガレベルで波形のオフセットをさせて符号の変化に着目する方法を採用しました。
この図の右に拡大記載してあるように、実際のデータは連続では無く離散の点列データです。
そのため、無作為に測定したデータ内には、完全に厳密なゼロクロス点に対応する点はおそらくありませんが、今回は実際に存在する点の位置を求めたいため、厳密さは求めません。
トリガレベルでオフセットさせた波形のゼロクロス点はそのままトリガ位置になります。この点をコンピュータ上で判別するために、符号が負値から正値に変化する位置を計算していきます。
Pythonでトリガ検出プログラムを作る
関数ファイル
トリガ検出プログラムはNumPyを使ってコーディングしています。
以下はトリガ検出部分の関数ファイル(trigger_function.py)です。def文を使った関数表現は「Pythonの関数 def文の使い方!引数や別ファイル式も解説」に記載していますので、ご参照下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import numpy as np def trigger(data, Tlevel): data = data - Tlevel #波形全体をトリガレベルでオフセット #位置情報 i と判定値 jを初期化 i = 0 j = True #ゼロクロス点探査Whileループ #ループ停止条件=トリガを検出した場合と検出されなかった場合のどちらか while j == True: #最初のループはiを増分させるだけ if i == 0: i = i + 1 #波形を全て探査した場合はjを強制的に判定値jをFalseにしてiに-1(未検出の意味)を代入 elif i + 1 == len(data): j = False i = -1 #前の値(i-1)と今の値(i)で符号を比較し判定値jに渡す。iを増分させる。 else: j = np.sign(data[i-1]) == np.sign(data[i]) i = i + 1 return i |
whileループを使っている理由は、ゼロクロス点が見つかった瞬間にループを終えたかったからです。
ループ内部に存在するif文は、「初期」「探査終了時」「それ以外」で場合分けするために使っています。
関数自体は波形とトリガレベルを引数として、位置情報(波形の点の何番目が検出されたか)を戻り値にしています。
メインファイル
以下にメインファイル(main_trigger.py)を示します。
と言っても、ほとんどがトリガ信号を作る部分で、トリガ検出部は上記関数を実行する最後の方の行しかありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import trigger_function import numpy as np from matplotlib import pyplot as plt #トリガ信号を作成(検証用波形) samplerate = 25600 #サンプリングレート Fs = 4096 #フレームサイズ x = np.arange(0, Fs)/samplerate #波形の横軸を作成 data = [] #空配列を作成 for i in range(Fs): #フレームサイズ分の点列データをループで作成 if i < 1000: data.append(1) elif 1000 <= i < 1100: data.append(1+((i+1)-1000)/10) else: data.append(11) data = np.array(data) #NumPy配列に変換 #トリガ検出関数を実行 i = (trigger_function.trigger(data, 10)) * (1 / samplerate) print(i) |
生成したトリガ信号は以下の図です。0~1000サンプル目までは1[V]、その後は11[V]一定になるという波形です。
上記コードはトリガレベルを10[V]に設定しています。プログラムを実行すると以下の数値が得られます。この数値は10[V]部分の時間情報ですので、トリガ検出はしっかりと機能したと言えます。
1 |
>>0.042578125 |
まとめ
本ページでは、時系列データの信号をトリガ検出する方法について、簡単な符号調査で行う手法をPythonで作成しました。
後はこの時間情報、もしくはサンプル位置情報を使って自由に時間波形を切り出すことで、データ解析の幅が拡がります。
今回作成した関数はノイズに対する対策がどれほど必要かまでは言及していませんが、おそらく既に記事にしているフィルタ処理等と組み合わせて使うことでより良い信号処理が可能になると思います。
以下の「信号処理」ページにまとめていきますので、よかったらご覧になって下さい。
今回は波形抽出の1つの技術であるトリガ検出を考えてみました。Pythonに慣れてくるとこのくらいの操作は朝飯前になってきますね!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!