3点,4点からなる二直線のなす角度を求める

3点,4点からなる二直線のなす角度を求めるというのは、以下の図のように、各点を通る二直線のなす角度を求める方法を紹介したいと思います。

 

 

4点からなる二直線の角度は、2点が重なり合うように、直線を構成している2点を平行移動すれば、3点の場合と同じ様になるので、ここでは、3点からなる二直線のなす角度を求める方法で説明します。

 

普通のやり方

まず、最初に思いつくのが、2直線のそれぞれの線の傾きをアークタンジェントを使って求め、2つの角度の差を求める方法だと思います。

 

$$\theta_{1}=tan^{-1}(\frac{A_{y}-B_{y}}{A_{x}-B_{x}})$$

$$\theta_{2}=tan^{-1}(\frac{C_{y}-B_{y}}{C_{x}-B_{x}})$$

$$\theta = \theta_{2}-\theta_{1}$$

 

ただし、直線が垂直の場合、アークタンジェントの計算時の分母が0になり、0除算になってしまうため、プログラム上はアークタンジェントの関数は atan() を使うのではなく、 atan2()を使った方がいいです。

atan2()関数を使うと、戻り値が-180°~+180°となりますが、この180°の位置をまたぐ角度の算出には注意が必要です。

 

他にも、2直線のなす角度を求める方法として、内積、外積を使った方法があるので、これを紹介します。

 

内積を使った方法

2つの直線を下図のように2つのベクトルとして捉え、内積で角度を求めます。

ベクトルa と ベクトルb を

$$\overrightarrow{a}=(a_{x}, a_{y}) = (A_{x}-B_{x}, A_{y}-B_{y})$$

$$\overrightarrow{b}=(b_{x}, b_{y}) = (C_{x}-B_{x}, C_{y}-B_{y})$$

とします。

 

ベクトルa と ベクトルb の内積は

$$\overrightarrow{a}\cdot \overrightarrow{b}=a_{x}b_{x} + a_{y}b_{y} = |\overrightarrow{a}||\overrightarrow{b}|cos\theta$$

 

であるから、式を変形して、

$$cos\theta=\frac{a_{x}b_{x} + a_{y}b_{y}}{|\overrightarrow{a}||\overrightarrow{b}|}$$

$$cos\theta=\frac{a_{x}b_{x} + a_{y}b_{y}}{\sqrt{{a_{x}}^{2}+{a_{y}}^{2}}\sqrt{{b_{x}}^{2}+{b_{y}}^{2}}}$$

$$\theta=cos^{-1}\left(\frac{a_{x}b_{x} + a_{y}b_{y}}{\sqrt{{a_{x}}^{2}+{a_{y}}^{2}}\sqrt{{b_{x}}^{2}+{b_{y}}^{2}}}\right)$$

として、角度θを求める事ができます。

ただし、アークコサインで求める事の出来る角度は0°~180°なので、マイナスの角度を求める事ができず、ベクトルbがベクトルaの右側か?左側か?の判断はできません。

 

右側か?左側か?の情報が必要な場合は、外積を用います。

 

外積を使った方法

外積については、少しおさらいです。

内積の結果はノルム(大きさ)となりますが、外積の結果はベクトルです。

外積の計算は

$$\overrightarrow{a}=(a_{x},a_{y},a_{z})$$

$$\overrightarrow{b}=(b_{x},b_{y},b_{z})$$

とすると、外積の結果は

$$\overrightarrow{a}\times \overrightarrow{b}=(a_{y}b_{z}-b_{y}a_{z},a_{z}b_{x}-b_{z}a_{x},a_{x}b_{y}-b_{x}a_{y})$$

さらに、外積を行う2つのベクトルからなる平行四辺形の面積が、外積の大きさと一致します。

ここで、外積の計算は三次元ベクトルで行うのですが、外積を行う2つのベクトルのz成分を0にして、外積を計算すると、外積の結果の大きさは、外積の結果のz成分と一致します。

$$\overrightarrow{a}=(a_{x},a_{y},0)$$

$$\overrightarrow{b}=(b_{x},b_{y},0)$$

$$|\overrightarrow{a}\times \overrightarrow{b}|=a_{x}b_{y}-b_{x}a_{y}=|\overrightarrow{a}||\overrightarrow{b}|sin\theta$$

となります。

ここから式を変形して

$$sin\theta=\frac{a_{x}b_{y}-b_{x}a_{y}}{|\overrightarrow{a}||\overrightarrow{b}|}$$

$$sin\theta=\frac{a_{x}b_{y}-b_{x}a_{y}}{\sqrt{{a_{x}}^{2}+{a_{y}}^{2}}\sqrt{{b_{x}}^{2}+{b_{y}}^{2}}}$$

$$\theta=sin^{-1}\left(\frac{a_{x}b_{y}-b_{x}a_{y}}{\sqrt{{a_{x}}^{2}+{a_{y}}^{2}}\sqrt{{b_{x}}^{2}+{b_{y}}^{2}}}\right)$$

 

として、角度θを求める事ができます。

アークサインで求まる角度は-90°~90°となるので、ベクトルa と ベクトルb の位置関係を判断することができます。

θの値がプラスの場合、ベクトルb は ベクトルa に対して、反時計周りの位置にあります。

θの値がマイナスの場合、ベクトルb は ベクトルa に対して、時計周りの位置にあります。

ただし、この計算だと±90°の範囲しか計算できませんが、その範囲以上の角度を求めたい場合は、ベクトルa と ベクトルb の内積の値も使います。

 

ベクトルa と ベクトルb の内積の値が正であれば、θは±90°の範囲内

ベクトルa と ベクトルb の内積の値が負であれば、θは±90°の範囲外

 

となるので、360°の範囲で、ベクトルa と ベクトルb の位置関係を求める事ができるようになります。

 

まとめ

●アークタンジェントで角度を求めるときは、atan()関数でなくatan2()関数を使う。

●内積や外積を使って角度を求めることもできる。

●内積だと、2つの直線の位置関係がわかりませんが、外積だと位置関係が分かる。

 

参考

内積

外積

内挿と外挿

内挿(Interpolation)外挿(Extrapolation)という言葉は、最近ではDeep Learning関連で目にする事が多い気がしますが、内挿・外挿とは、データを近似し、データ以外の場所を推定する際に、データの範囲内を推定することを内挿といい、データの範囲外を推定することを外挿といいます。

しかしながら、一般的に外挿で推定した値は必ずしも正しいとは限らないため、しない方が良いといわれます。以下に推定した値が正しくならない例を示します。

外挿した値が近似したモデル(近似式)とはズレる場合

下図の例は、かなり恣意的ではありますが、データを近似し、データの範囲内で他のデータを推定する内挿の場合では誤差は少ないですが、データの範囲外を推定する外挿ではデータの変化の傾向が異なり誤差が大きくなる可能性もあります。

このことはDeep Learningでも言われる事ですが、データを学習する際は、様々な状態のデータを学習させ、推論する際は学習させたデータの範囲内に留めておく必要があります。

外挿となってしまう場合は学習データを追加し、推論するデータがデータの範囲内になるようする必要があります。

 

外挿は誤差が大きくなりやすい

前項の例は、内挿と外挿のデータの傾向が異なる場合の例として示しましたが、内挿と外挿とでデータの傾向が同じ場合でも外挿の方が誤差が大きくなる場合があります。

例えば、内挿、外挿とも直線的に変化することが分かっている場合に、2点のデータを使って直線で近似する場合もよくあります。

しかしながら、近似に用いたデータにも、少なからず誤差が含まれる場合がほとんどです。

この時に2点のデータから計算した直線も、下図のように誤差が出てしまいます。

上図を見ても分かるように、近似に持ちるデータに誤差が含まれたとしても、内挿の範囲内であれば、計算した直線もデータの誤差の範囲内に収まりますが、外挿になるとデータの誤差が増幅され、計算した直線は、データの誤差以上の誤差となってしまいます。

 

以上のことから、内挿はいいけれども、外挿をする場合には注意が必要となります。

単位ベクトルとその応用

単位ベクトルとは?長さが1のベクトルとなります。

例えば、ベクトルa の要素を

としたときの単位ベクトルu は

となります。

これを図示すると、

のようになります。

これを学生の時に教わったときには簡単!とだけ思っていましたが、大人になると、

で、単位ベクトルの何がいいの??

となります。

しかし、実は、単位ベクトルには教わった記憶の無い(少なくとも覚えていない)大事な特徴がありました。
それは

単位ベクトルと任意ベクトルの内積を計算すると、
単位ベクトル方向の成分(大きさ)が取得できる!

ということです。

例えば、ベクトルa の単位ベクトルu の方向の成分は、ベクトルa と単位ベクトルu の内積の絶対値で求まります。

なぜ、そうなるのか?は比較的簡単で、ベクトルa の単位ベクトルu の方向の大きさを L として、ベクトルa の単位ベクトルu の成す角をθとして、図示すると

となります。

Lは図から

となるのは、図を見れば分かると思います。

ここで、ベクトルa と単位ベクトルu の内積は

となりますが、単位ベクトルの大きさは 1 なので、

となり、先ほどの L と一致する事が分かります。

ちなみに、θの角度が 90° ~270°の範囲の場合、cosの値がマイナスとなるため、ベクトルu の方向の大きさを求める場合は、内積の絶対値を求めています。

また、あえて絶対値を取らないで、内積が正の場合は、ベクトルa は単位ベクトルu の向きの方向にあり、内積が負の場合はベクトルa は単位ベクトルu の逆向きになっていることを確認する事もあります。

これを応用すると、内積は二次元のベクトルだけではなく、3次元、4次元・・・とn次元ベクトルに拡張できるので、応用範囲は広くあります。

例えば三次元ベクトルの場合ですが、三次元平面と点の距離を求める方法について説明したいと思います。

平面の方程式は

のように表されますが、この法線ベクトルn は

となります。

この法線ベクトルの単位ベクトルは、各要素を大きさで割って

となります。

あとは、平面上の点(x0, y0, z0)と任意の点(x1, y1, z1)からなるベクトル

との内積を計算すると、

となって、この値の絶対値を取ると平面と点との距離となります。

逆に絶対値を取らないと、値が正の場合、点は法線ベクトルの方向にあり、値が負の場合は点が法線ベクトルとは逆の方向にある事が分かります。値が0の場合は、点は平面上にある事になります。

 

まとめ

・単位ベクトルと任意ベクトルとの内積を計算すると、単位ベクトル方向の大きさを求めることができる。

というのが、大事な特徴です。

私が大人になってから単位ベクトルを使った事があるのは、平面と点との距離のように、単位ベクトルの方向の大きさを求めるような使い方しかないかも?
広い意味で言うと、フーリエ変換も単位ベクトルが係わっていたりもしますが。。

 

【C#】フーリエ変換(FFT, DFT)プログラム

以前、Excelのマクロを使って、データ個数に応じて高速フーリエ変換(FFT)と離散フーリエ変換(DFT)の処理を自動で切り替えるマクロを作成したのですが、Excelではデータ数が多い時など、使いにくい場合もあるので、今度は、C#でフーリエ変換部分をライブラリ(*.dll)にし、そのライブラリを使ったプログラムを作成しました。

 

実行ブログラムはこちら FourierTransform.zip

ソースコードは、すべてGitHubで公開しています。

https://github.com/ImagingSolution/FourierCSharp

 

使用方法は以下の通りです。

 

プログラムの実行

zipファイルを解凍すると、

FourierTransform.exe

FourierCSharp.dll

sampledata

となっていますので、FourierTransform.exeをダブルクリックして実行してください。

 

フーリエ変換できるデータフォーマット

データは1行あたりに1つのデータのCSVファイルとなります。

例)

1
1.30939551
1.59096344
1.820538079
1.980767038
2.06331351
2.069803727
2.01139008
1.906994542
1.780482109
1.65716389
1.560123288
1.506883103
1.506883103
1.560123288

入力データに実数部と虚数部が含まれる場合は、1行あたりに

実数部、虚数部

とします。

例)

50, 0
0, -25
0, 0
0, -12.5
0, 0
0, 0

サンプルのデータとして、ZIPファイル内の sampledataフォルダ内にいくつかCSVファイルを入れてありますので、そちらを参考にしてください。

 

データの読込

メニューの File → LoadData をクリックし、CSVファイルを指定することで、データが読み込まれ、フーリエ変換の結果(フーリエ変換後の各周波数の大きさ)が表示されます。

 

フーリエ変換はデータの個数が2のn乗個の場合:FFT、その他の場合:DFTを行います。

 

フーリエ変換、逆フーリエ変換の切替

メニューの Fourier direction → Forward もしくは Backward をクリックすることで、離散フーリエ変換、逆離散フーリエ変換が切り替わります。

 

離散フーリエ変換は

$$F(t)=\sum _{ x=0 }^{ N-1 }{ f(x){ e }^{ -i\frac { 2\pi tx }{ N } } } $$

逆離散フーリエ変換は

$$f(t)=\frac { 1 }{ N } \sum _{ t=0 }^{ N-1 }{ F(t){ e }^{ i\frac { 2\pi xt }{ N } } } $$

で計算しています。

 

窓関数

メニューの Window→ Hamming, Hanning, Blackman のいづれかをクリックすることで、それぞれの窓関数を通します。

↓ 窓関数

 

ただし、窓関数を通すと、元に戻せないため、元に戻す場合は、再度、データ読込を行って下さい。

 

免責事項

ここに公開されているプログラムは自由に使って頂いて構いませんが、バグ等による責任は待てませんので、自己責任において参照下さい。

 

フリーウェアへ戻る

二分法の処理アルゴリズムと応用例

簡単には解けない複雑な計算式の解を求める手法の一つに二分法という手法があります。

これは、2点間の間に必ず解がある場合、2点間の半分の位置の値を求め、解が小さい方にあるのか?大きい方にあるのか?を確認し、解がある方のさらに半分の位置の値を求め...と解のある位置を追い込む手法です。

 

説明が難しいので具体例で示します。

下図は y = x2 – 10 のグラフですが、y=0 となるxの値を求める場合の例です。

この例では、普通に解を求める事ができますが、あえて二分法で解きます。

 

y=0 となるxの値は、-4 ~ -2 と 2 ~ 4 の間にありそうな事はわかります。

今回は 2 ~ 4 の間にある解を求めます。

 

2と4の中間の3の時のyの値を計算すると、yの値は負になるので、y=0となるxの値は
3 ~ 4 の間にあることがわかります。

 

さらに、3と4の中間の3.5の時のyの値を計算すると、yの値は正になるので、
y=0となるxの値は3 ~ 3.5 の間にあることがわかります。

 

さらに、3と3.5の中間の3.25の時のyの値を計算すると、yの値は正になるので、
y=0となるxの値は3 ~ 3.25 の間にあることがわかります。

 

・・・と、この処理を2点間の範囲が十分小さくなるまで繰り返すことで、y=0 となる値を求める手法が二分法となります。

 

二分法の考え方は非常に簡単ですが、個人的には数式の解を求めるために使うことは、ほとんど無く、二分法の考え方を応用することはよくあります。

 

その一例を示したいと思います。

 

プログラムのエラーの場所を特定する場合

プログラム中のどこかでエラーが発生しているときに、どこで発生しているのか?さっぱり見当が付かない場合に二分法の考え方を応用します。

 

まず、エラーが発生しているプログラムにおいて、プログラムシーケンスのだいたい真ん中あたりとなる位置にブレークポイントを置いてデバック実行を行います。

もし、ブレークポイントまでエラーが無ければ、ブレークポイントの後半の処理でエラーが発生している事になります。

 

次に後半の処理部分のさらに真ん中あたりにブレークポイントを置き、デバッグ実行をしたときに、後半の中の前半の部分でエラーが発生していれば、エラーは全体の後半の中の前半部分で発生することがわかります。

 

これを繰り返すと、エラーが発生している位置は、全体の1/2⇒1/4⇒1/8・・・と追い込む事ができるので、やみくもにエラーの場所を探そうとするよりは、バグの位置を特定しやすくなるかと思います。

 

 

ラインセンサカメラで撮影した画像の縦横比を合わせる場合

ラインセンサカメラ(スキャナのような物)で撮影した画像は、何も考えずに撮影すると、縦横比が合わなく、丸い物を撮影しても楕円状になってしまいます。

これをまじめに縦横比を合わせるには、画像の横方向の撮影分解能(mm/画素)を画像から算出し、カメラのスキャンレート、エンコーダの撮影分解能、被写体の移動速度などから縦横比の合う値を算出します。

 

しかし、計算するのも少し面倒なので、ただ、撮影するだけの場合、私は画像を見ながら被写体の搬送速度を調整して縦横比を調整しています。

(実際の装置の場合、搬送速度は装置の生産能力に係わる部分なので、調整することは仕様的に難しい場合が多く、カメラのスキャンレートやエンコーダの撮影分解能などを調整して縦横比を合わせます。)

 

以下、具体例です。

送り方向に関しては、パルスモータで搬送しているとして、画像が縦長、横長になるパルス速度を見つけます。

(画像が縦長になるのは搬送速度が遅く、画像が横長になるのは搬送速度が速い事を意味します。)

 

ここでは、パルス速度1000Hzで搬送した時に縦長、2000Hzで撮影した時に横長になったとすると、縦横比が合う搬送速度は1000~2000Hzの間にある事がわかります。

ここで、二分法の考え方を応用して、1500Hzで撮影した時に画像が横長になったとすると、縦横比が合う搬送速度は1000~1500Hzの間となります。

 

1250Hzで撮影した時に画像が横長になったとき、1000~1250Hzの間、

1125Hzで撮影した時に画像が縦長になったとき、1125~1250Hzの間、

1187.5Hzで撮影した時に・・・と繰り返していくと、縦横比の合う搬送速度を見つけ出す事ができます。

 

 

 

このように、二分法を知っていると、数式を解くだけでなく、効率的に目的の場所や値を求めることが出来るようになります。

 

使える数学へ戻る

フーリエ変換アプリ

こちらのページでは、フーリエ変換のイメージをビジュアル的に見せるためのプログラムになります。

単に、フーリエ変換をしたい場合は、下記のプログラムをご使用下さい。

【C#】フーリエ変換(FFT, DFT)プログラム

フーリエ変換を教える時に、自分の中では糸(データ)を巻き取るようなイメージ↓(こんな感じ)

 

 

があるのですが、これを分かるように説明するのがなかなか難しく、その様子が分かるように、C#でプログラムを作成してみました。

 

動いている様子はこちら↓

 

実際のプログラムはこちら↓(.NET Framework4.5.2以上で動作すると思います)

FourierTransformAnimation.zip

 

上記ファイルを解凍後、FourierTransformAnimation.exeファイルをダブルクリックすると、プログラムが実行できますが、Windowsの警告画面が表示されるので、「詳細情報」をクリック後、プログラムを実行してください。

また、いくつかサンプルデータを入れてありますので、sampledataフォルダ内のcsvファイルを開いてお試しください。

フーリエ変換で用いている式は、いくつかあろうかと思いますが、下記の式に基づいて処理を行っています。

基本的な機能としては

●CSVファイルによる任意データ入力

●データの離散フーリエ変換

●離散フーリエ変~逆離散フーリエ変換までを動画表示

●窓関数

●離散フーリエ変換の結果をファイル保存

となります。

 

プログラムの説明

データファイルを開くと、離散フーリエ変換を行い、大きさと位相を表示します。

処理のアニメーションの時に用いる複素平面のグラフは、90°反時計周りに回転した状態が初期状態になっています。

離散フーリエ変換の途中途中に出てくる赤い線は、複素平面において、原点からデータの平均の位置までの線で、この線の大きさをMagnitudeグラフへ記載しています。(描画スケールが異なります。)

 

さらにこの線の傾き(12時方向が0°で反時計周りが正)をPhaseグラフへ記載しています。

 

 

逆離散フーリエ変換の時は、各周波数のデータを積算していきますが、前回までのデータの合計を太い青い線で、現在の周波数のデータを赤い線で表示しています。

 

 

使用方法

ファイルを開く

ファイルメニューより、File → Open(*.csv) をクリックし、CSVファイルを選択します。

CSVファイルのフォーマットは1行に1データを縦に記載します。

【例】

1.2
1.107165359
0.914844142
0.80157706
0.872515202
1.061803399
1.193716632
1.145793725
0.962523737
0.814044703
0.838196601
1.012558104
1.175261336

入力データに虚数成分がある場合は、実数と虚数をカンマ(,)でつなげて以下のようにします。

【例】

1,0
0.999390827,0.034899497
0.99756405,0.069756474
0.994521895,0.104528463
0.990268069,0.139173101
0.984807753,0.173648178
0.978147601,0.207911691
0.970295726,0.241921896
0.961261696,0.275637356
0.951056516,0.309016994
0.939692621,0.342020143
0.927183855,0.374606593
0.913545458,0.406736643
0.898794046,0.438371147
0.882947593,0.469471563

データ数がどこまでいけるか?評価していませんが、アニメーション表示をするなら50~100個ぐらいまでが目安です。

アニメーション表示しなければ、そこそこいける?!

 

アニメーションの開始/停止

Youtubeの動画のように、処理の様子を動かすには、ファイルメニューの Animation → Start/Stop をクリックします。スペースキーを押しても同様の動きをします。

 

アニメーションのステップ実行

処理を1つ1つのデータで行う場合は、アニメーションを停止させ、矢印キーの右()を押します。

 

アニメーション速度の調整

アニメーション速度を速くする場合は、矢印キーの上()、遅くする場合は、矢印キーの下()を押します。

 

窓関数処理

基本的に全データを1周期分を想定していますが、この1周期に窓関数(Hamming、Hanning、Blackman)を通します。

ファイルメニューの Window → Hamming、Hanning、Blackman をクリックします。

 

フーリエ変換のイメージ

フーリエ変換では、データを複素平面へ巻き取るようなイメージでになります。

 試しにCosθのデータ全体を1回転で巻き取るようにすると

 

最終的に複素平面の原点から、データが巻き取られた点(複素平面上の点)の平均の位置までの線の大きさが、その周波数の大きさで、線の傾きが位相となります。

 

このデータを巻き取るときの回転の速度が、データ全体を0回転、1回転、2回転・・・で巻き取るようにすると、それぞれの周波数(0,1,2・・・)の大きさと位相が取得できます。

 

試しにCosθのデータ全体を2回転で巻き取るようにしてみると、複素平面上の点の平均は0となります。

もともとのデータにない周波数成分(Cos2θの成分)は、複素平面上で平均を取ると、データが相殺されて0になるのが面白い!

 

逆変換の場合は、取得した各周波数ごとの大きさと位相からコサイン波形を生成し、足し合わせた結果が変換後の実部となります。

ここで、ちょっと違和感があるであろう コサイン波形 と書きましたが、サイン波形を足し合わせた結果は、虚部となります。

 

おそらくこんな書き方をする人はいないのですが、データの個数をN、周波数tの時の大きさをAt、位相をφtとすると、逆変換後の実部(Re)と虚部(Im)は以下のようになります。

 

$$Re(x)\quad =\quad \sum _{ t=0 }^{ N-1 }{ { A }_{ t }Cos(\frac { 2\pi t }{ N } x+{ \varphi }_{ t }) } \\ Im(x)\quad =\quad \sum _{ t=0 }^{ N-1 }{ { A }_{ t }Sin(\frac { 2\pi t }{ N } x+{ \varphi }_{ t }) } $$

 

以下の画像は周波数1の結果を逆変換したものになります。

これだけを見ると、実部のグラフのcosθの振幅は小さくない?!

と思われたかもしれませんが、フーリエ変換を行う元々のデータに虚数部分が含まれない場合、大きさが同じで位相がマイナスの関係になった周波数が存在します。

こんな感じ↓

 

この2つの波形を足し合わせる事で、逆変換では元の波形に戻ります。

この部分の詳細を知りたい場合は、複素共役で調べてもらうと分かるかも?しれません。

 

このフーリエ変換を発明したジョゼフ・フーリエさんは、自分自身をミイラのように包帯でグルグル巻きになるという、ちょっと変わった趣味の持ち主だったそうですが、このグルグル巻きになった時にフーリエ変換が思いついたのではないのかな?(詳細は不明)

 

フーリエ変換へ戻る

 

【Excel】高速フーリエ変換(FFT)のマクロ(VBA)

Excelには標準でフーリエ解析の機能を備えていますが、解析用のデータを変更してもフーリエ変換の結果は自動更新してくれないので、少し使い勝手の悪い物になっています。

 

そこで、エクセルのセルの部分にSUMAVERAGE のような関数と同じように動くマクロ(ユーザー定義関数)で作成したフーリエ変換の関数(Fourier)を作成しました。

ユーザー定義関数で作成しているため、解析用のデータを変更すると、フーリエ変換の結果も自動で変更されます。

 

 

ファイルのダウンロードはこちら↓より

fourier_transform_rev3.zip

(Excel2016推奨、それ以前だとファイルを開いた直後はフーリエ変換の値が0になるようです。)

 

使用方法

このファイルはマクロを使用しているため、ファイルを起動するとセキュリティ警告が表示さている場合は、コンテンツの有効化をクリックしてください。

 

まず、フーリエ変換の結果の出力先のセルを縦方向にデータ個数と同じ分だけ選択し、

= Fourier( データのセル)

と入力し、Enterではなく、Ctrl + Shift + Enterキー を入力します。

これで、フーリエ変換の結果が複素数で表示されます。

 

複素数はいらないから、絶対値だけ欲しいという場合にはFourierAbs関数を使って下さい。(使い方は同じです。)

 

フーリエ変換の結果は標準のフーリエ解析の結果と同じになるようにしていますが、10の-15乗ぐらいの誤差が出ています。

 

フーリエ変換の結果の複素数の大きさを計算するには、Excelの標準関数の IMABS関数 で求まります。

 

同様に位相は IMARGUMENT関数 で求まります。

 

このマクロのポイント!

  • 窓関数に対応
    = Fourier( データのセル, “Hamming”)
    のように入力することで、入力データに対して窓関数を通します。
    対応している窓関数の名前は
    ハミング Hamming
    ハニング Hanning
    ブラックマン Blackman

    の3つ。

  • FFT/DFTの自動切換え
    マクロ処理内部で、フーリエ変換するデータ個数が2のN乗個の場合はFFT、それ以外の場合はDFTとなり、データの個数が2のN乗個の制限はありません。

 

逆フーリエ変換を追加

2018.6.19追記

逆フーリエ変換に対応したIFourier関数を追加しました。

逆フーリエ変換の計算は別シートの逆フーリエ変換のシートを参照ください。

 

使用方法については、普通のフーリエ変換の時と同じように

= IFourier( データのセル)

と入力し、Enterではなく、Ctrl + Shift + Enterキー を入力します。

ただし、逆フーリエ変換なので、データのセルの部分は、基本的に複素数となります。

 

逆フーリエ変換の結果はこちら↓です。

 

上の絵を見ても分かるように、虚数成分の10の-15乗程度の誤差が入ってしまっているので、複素数の実部だけを取得するIMREAL関数で実部を取得すると、ほぼフーリエ変換の時に用いたデータに戻っていることが確認できるかと思います。

 

 

フーリエ変換へ戻る

合成関数の微分

Deep Learningをお勉強していたら、合成関数の微分が出てきたのですが、もう30年ぶりぐらいに見たので、その復習です。

\(y=f(u), u=g(x)\)としたとき、\(y=f(g(x))\)を合成関数とよび、この合成関数を\(x\)に関して微分すると、

 

$$\frac{ dy }{ dx } =\frac { dy }{ du } \frac { du }{ dx } \\ \quad =\frac { d }{ du } f(u)\frac { d }{ dx } g(x)$$

 

となります。

合成関数を教わったときは、合成関数の微分は「外側の微分x内側の微分」って覚えてたような。。

 

試しに\(y=sin({ x }^{ 2 })\)の微分は\(u={ x }^{ 2 }\)と置くと

 

$$\frac { dy }{ dx } =\frac { d }{ du } f(u)\frac { d }{ dx } g(x)\\ \quad =cos(u)\times 2x\\ \quad =cos({ x }^{ 2 })\times 2x$$

 

これをPythonのmatplotlibを使ってグラフにしてみると

 

となり、青の線の微分(傾き)がオレンジ色の線なので、合ってそう。

【Excel】フーリエ解析(FFT)

ここではExcelの標準の機能であるフーリエ解析について紹介したいと思います。

フーリエ変換は、ざっくり言うと信号の中から各周波数ごとの大きさ位相を求める変換です。

この”信号”と言っている部分が音や画像のような測定データの場合、この”信号(データ)”に対してフーリエ変換を行うのが離散フーリエ変換となります。

しかし、離散フーリエ変換は処理速度が遅いので、離散フーリエ変換を行うんだけど、データ個数を2のn乗(2, 4, 8, 16, 32・・・)個に制限することで、高速に処理することができる処理アルゴリズムが高速フーリエ変換[Fast Fourier Transform(FFT)]となります。

 

ここで、フーリエ変換の公式ですが、主に以下の3つの公式があります。下図の公式を見て頂くと分かりますが、異なるのはシグマの頭についているデータ個数Nに関する係数のみ異なります。
いくつも公式があるのは、おそらくプログラム的な都合で、

1番目の公式が本来の公式?
2番目の公式は、フーリエ変換では各周波数の大きさが相対的にどの周波数が大きいのか?を解析的に用いる場合が多く、離散フーリエ変換しかしない(逆変換をしない)場合も多いので、1/Nの計算を省き処理を軽くしたかった?エクセルでは、この2番目の公式を用いています。
3番目の公式は離散フーリエ変換と逆離散フーリエ変換のプログラムをできるだけ共通にしたかったため?異なるのは e の乗数の符号のみとなります。

N :   データ個数
t:   全データに含まれる波の個数(何周期分か?)
x :   データのインデックス番号 x = 0, 1, 2,… , N-1

データの準備

エクセルのフーリエ解析はFFTなので、データの個数は2のn乗個(2, 4, 8, 16, 32, 64・・・)に限られ、最大4096個まで処理が可能です。

今回はデータの個数は32個用意しました。
実際にフーリエ解析したいデータは各自、用意してください。
データはどこかに1列に書いておけば大丈夫です。(あとで、データの場所を指定します)

結果が分かりやすくなるように、

全く振動していない(t=0)データ(値=3)と、
2周期分(t=2)のデータ(振幅=2、位相=30°)と、
4周期分(t=4)のデータ(振幅=1、位相=-60°)

の3つの波形を合計したデータに対してフーリエ変換を行います。

Excelでフーリエ解析の手順

Excelでフーリエ解析を行うには分析ツールというのを表示する必要があります。

この分析ツールの表示方法は下記のページを参照下さい。

【Excel】分析ツールの表示

 

メニューのデータデータ分析を選択します。
ホーム→データ分析にあるデータ分析とは別なので注意してください。

 

表示されたウィンドウからフーリエ解析を選択しOKを押します。

 

 

表示されたウィンドウの入力範囲の部分にある上矢印の部分をクリックします。

 

 

この状態で、フーリエ解析を行うデータを選択(2のn乗個の最大4096個まで)し、それでよければ下矢印をクリックします。

フーリエ解析の結果の出力先はいくつか選べるのですが、今回は新規ワークシートにするとして、OKボタンをクリックします。

 

 

そしてこれ↓がフーリエ変換された結果です。

フーリエ変換の結果の見方

※ここから先は、入力データが実数(虚数成分が無い)の場合を前提として説明します。

フーリエ変換の結果は

96
0
27.7128129211021+16i
0
7.99999999999999-13.856406460551i
0
0

のように複素数(実数と虚数成分が含まれる)が並んでいますが、これは上から順にt=0、1、2、…の時の結果になっています。

tの値は、FFTに用いたデータ全体に何周期分の波が含まれているか?を表しています。

tの値から周波数f(Hz)を求めるには、データ全体のサンプリング時間をΔt(sec)とすると、周波数は

$$f=\frac{t}{\triangle t}  (Hz)$$

となります。

ここで、フーリエ変換の結果に、tの値と周波数fを書き加えます。

この結果を見ると、多少の計算誤差はありますが、 t= 2 と t = 30、 t = 4 と t = 28 の値が、虚数成分(i の係数)の正負が異なるだけで、似ている事がわかります。

この実数は同じで虚数の正負が異なる値を複素共役と言います。

フーリエ変換の入力データが実数の場合、必ずこのようになるのですが、t と N – t が共役となるため、フーリエ変換では、 t = 0~N/2 までの結果のみを使う場合がよくあります。

 

フーリエ変換の結果から各周波数の振幅Aを求めるには、フーリエ変換の結果(複素数[実数と虚数])の大きさ |F(t)| を用いると

t = 0 と t = N/2のとき

$$A=|F(t)| / N$$

t = 1 ~ N/2-1 のとき

$$A=|F(t)| / N \times 2$$

となります。

エクセルで複素数の大きさを求めるには IMABS()関数 を用います。

さらに複素数の偏角(位相)を求めるには IMARGUMENT()関数 を用いますが、偏角の結果はラジアン単位なので、度の単位に変換するには DEGREES()関数 を用います。

 

これらの事をエクセルの結果に複素数の大きさ、各周波数ごとの振幅および位相を追加すると以下のようになります。

これで、データをFFTして、各周波数ごとの振幅(A)と位相(φ)を求める事ができています。

各周波数ごと(各tごと)の波形は

$$A_{t} \cos(2\pi t\frac{x}{N}+\phi_{t})$$

となります。

 

今回のFFT解析に用いたExcelファイル(*.xlsx)は、下記リンクをクリックしてダウンロードできます。

フーリエ解析(FFT)_rev1.zip

 

パワースペクトルは??

FFT解析は、各周波数のパワースペクトルを求めること!

みたいな認識もあるかと思いますが、ここまでの説明にパワースペクトルが出てきていません。

パワースペクトルは、FFTで求めた各周波数の結果(複素数)の大きさを振幅スペクトルと言い、振幅スペクトルを2乗したものをパワースペクトルと言います。

パワーという響きから、どうしても力?みたいなのをイメージしてしまいますが、どちらかというと、C言語でn乗の計算をするときに pow関数 を用いると思いますが、このn乗の方に近いでしょうか?(本当のところはよく知りません。。)

 

各周波数ごとに求められたFFTの結果(複素数)を a + bi とすると

$$振幅スペクトル=\sqrt{a^{2}+b^{2}}$$

$$パワーペクトル=(振幅スペクトル)^{2}=a^{2}+b^{2}$$

となることから、プログラム的にはパワースペクトルの計算の方がルートの計算をしていない分だけ計算コストが低くなります。

エクセルでは、IMABS()関数で振幅スペクトルを求め、振幅スペクトルを2乗(^2)することで、パワースペクトルを求める事になり、計算コストが増えてしまい、ちょっと微妙。。

複素共役の性質

入力データが実数のときのFFTの結果で tN – t が共役になると説明しましたが、

複素数 a + bi と、共役の複素数 a – bi と足し合わせると

$$(a+bi)+(a-bi) = 2a$$

となるので、虚数成分は打ち消しあい、実数成分が2倍となります。

この性質から、振幅を求める際に、t = 1 ~ N/2-1 のとき、最後に x 2 を付けているのは、そのためです。

 

 

フーリエ変換へ戻る

参考

複素数の計算

複素数については実在しないものの様に教わったので、なかなか理解できないままでいたのですが、実際に使ってみると便利に感じることもあるので、数学的には厳密でないかもしれませんが、私なりの理解でまとめてみます。

結論からすると、複素数は複素平面(横軸:実数、縦軸:虚数)におけるベクトルみたいなものです。ベクトルなので、大きさと角度を持ちます。
計算もベクトルと同じ様に、足し算、引き算ができます。
ただ、ベクトルと異なるのが、掛け算、割り算は、指数関数のように計算します。

 

まず、複素平面については、覚えるしか無さそうなので、複素数Zは実数成分がa、虚数成分がbのとき、虚数iを使って以下のように定義されます。

 

 複素数Z = a + bi

複素数の大きさ(絶対値は)

 

 

傾き(偏角)は

 

 

となります。

ここまでは、ほとんどベクトルもしくは極座標の計算と同じです。

 

さらに、オイラーの公式というのがあり、

e = cosθ + i sinθ

 

となります。

ここで登場するeネイピア数と呼ばれるのですが、自然対数のeと同じフナ一羽二羽のe=2.718281828..と同じですが、指数のところに虚数のiが付いており、まじめにeの何乗か?と考えない方が良いかと思います。

 

eは、複素平面上での半径1の円として捉えて下さい。

 

θ=0の時は

ei0 = cos0 + i sin0 = 1 + i 0  =  1

となり、θ=π / 2 のときは

eiπ/2 = cos(π/2) + i sin(π/2)= 0+i 1  =  i

 

となります。

オイラーの公式では大きさが1ですが、最初の複素数の定義のように任意の大きさAとすると、合わせ技で

 

Ae = A(cosθ + i sinθ)  = a + bi

ただし、 a = Acosθ、 b = Asinθ

 

となります。

ここで大事なのが、複素数の定義ではベクトルのように見えますが、オイラーの公式を用いると指数関数のようにも見えます。

このどちらにも見える特性を都合のいい方で扱えるところが便利なところです。

 

例えば、2つの複素数Z1とZ2の足し算は

  Z1 = a1 + b1 i

  Z2 = a2 + b2 i

  Z + Z2 = a1 + b1i + a2 + b2i  

      = a1 + a2 + (b1 + b2)i

 

となります。

この計算は、ベクトル(a1, b1)とベクトル(a2, b2)の足し算と同じです。

 

 

同様のことは引き算でも言えます。

 

それでは、掛け算の場合は、どうなるかというと

  Z1 = a1 + b1 i

  Z2 = a2 + b2 i

  Z x Z2 = (a1 + b1i) x (a2 + b2i  )

      = a1a2  +  a1b2 i + a2b1 i  + b1b2  i2 

      = a1a2  + (a1b2  + a2b1 )i  ー b1b2 

      = a1a2  ー b1b2 +(a1b2  + a2b1 )i 

 

としてもいいのですが、オイラーの公式を使って、Z1の絶対値をA1,偏角をθ、Zの絶対値をA,偏角をθとして

 

  Z1 = a1 + b1 i = A1eiθ

  Z2 = a2 + b2 i = A2eiθ2

  Z x Z2 = A1A2 ei(θ1+θ2)

 

のように指数関数として複素数の掛け算(割り算)は計算した方が良い場合がよくあります。

 

 

中間まとめ。

●複素数の足し算、引き算はベクトルの足し算、引き算

●複素数の掛け算、割り算は指数関数

 

と思って解ける場合が多い。

ここまで覚えると、複素数に関する公式は、覚えていなくても導き出せる場合が多いです。

 

例えば、虚数i は i2 = -1 となる値として教わったのですが、

$${ i }^{ 2 }={ \left( 0+1i \right) }^{ 2 }={ \left( { e }^{ i\frac { \pi }{ 2 } } \right) }^{ 2 }={ e }^{ i\left( \frac { \pi }{ 2 } +\frac { \pi }{ 2 } \right) }={ e }^{ i\pi }=-1$$

 

と考えると、回りくどいですが、自分の中ではスッキリと整理ができました。

 

他にも複素数の虚数成分を負にした(θをマイナスにした)ものを複素共役(ふくそきょうやく)といいますが、

$$Z\quad =\quad a\quad +\quad bi\quad =\quad A{ e }^{ i\theta }\quad \\ \bar { Z } \quad =\quad a\quad -\quad bi\quad =\quad A{ e }^{ -i\theta }\quad $$

 

図示するとこんな感じ↓

この特性から、実部aは複素共役を使うと

 

 

となりますが、図を見れば一目瞭然なので、あまり公式としては覚えていません。。

ただ、この複素共役ですが、分かりやすく eπ/3 と e-π/3 のようにペアになってくれてればいいのですが、 eπ/3 と e5π/3 のような場合が多いので、ご注意下さい。

 

 

結局、この複素数を使うと何がよいか?というと、

●実数と虚数が同時に計算できる。普通の実数の空間で言うのなら、XとYが同時に計算できる。

●都合の良い方で計算できる。ベクトル演算だったり、指数関数だったり。。

●フーリエ変換的な要素(バンドパスフィルタ)が計算できる。

 

というのは、個人的な意見なのですが、実際にはプログラムを組む時は、実部と虚部で別々で計算していたりもします。

まぁ、画像処理アルゴリズムを考える時の手助けにはなっています。

 

フーリエ変換使える数学へ戻る

【Excel】フーリエ変換

エクセルでフーリエ変換をするには、Webで検索するとほとんどの場合、分析ツールのフーリエ解析で行う方法が紹介されているかと思います。

この方法は以下のページを参照ください。

【Excel】フーリエ解析(FFT)

 

しかしながら、分析ツールで行うフーリエ解析では、解析対象のデータを変更しても、自動で結果を再計算しれくれない上に、Excelのフーリエ解析はFFTであるため、データ個数が2のn乗個(2,4,8,16,32,64,128・・・)という制限があります。

 

そのため、エクセルのセルの関数のみを使い、フーリエ変換(離散フーリエ変換[DFT])を行う方法を紹介します。

ただし、結論からすると処理が重いため、データ個数が多い場合はExcelのフーリエ解析(FFT)を使った方が良さそうです。

ここでは、フーリエ変換のお勉強用に使って頂ければ幸いです。

 

エクセルでフーリエ変換を行ったファイルはこちら↓

discrete_fourier_transform_rev1.zip

 

エクセルのイメージはこちら↓

 

データf(x)と書かれた下の黄色いセルの部分にデータを入力すると、フーリエ変換され、振幅スペクトルと位相が計算されます。

 

エクセルの分析ツールで行うフーリエ解析では以下の式を用いていますが、

 

ここでは、フーリエ変換の結果の値に意味合いを持つ下記の式を用いています。

 

 

離散フーリエ変換についてはこちらのページでも紹介していますが、エクセルでフーリエ変換を行うために必要な情報をまとめておきます。

 

まず、フーリエ変換を行うと、各周波数ごとに複素数の成分として変換されます。

 

複素数zは実数成分をa、虚数成分をb、実数Aとすると

      z = a + bi = Ae

 

のように表示され、図示すると下図のようになります。

 

  a = A x Cos θ

  b = A x Sin θ

 

複素数の絶対値は

 

位相(複素数では偏角といいますが)は

 

となります。

このへんの感覚は、ベクトルの成分が(a, b)、ベクトルの長さがA、傾きがθの場合と同じなので、覚えやすいかと思います。

 

 

 エクセルで用いる複素数の関数

エクセルで複素数の計算に用いる関数は関数名の先頭にIMが付く関数を用いますが、今回用いた関数を紹介します。

 

■複素数 COMPLEX関数

実部をa、虚部をbとする複素数は  COMPLEX(a, b)

 

■複素数の絶対値 IMABS関数

複素数(a + bi)の絶対値 IMABS(“a + bi”)

結果は√(a2 + b2) となります。

 

■複素数の実部の取得 IMREAL関数

複素数(a + bi)の実部は  IMREAL(“a + bi”) = a

 

■複素数の虚部の取得 IMAGINARY関数

複素数(a + bi)の虚部は  IMAGINARY(“a + bi”) = b

 

■複素数の偏角の取得 IMARGUMENT関数

複素数(a + bi)の偏角は  IMARGUMENT(“a + bi”)  で-π~πの範囲でラジアン単位で取得

 

■複素数のべき乗 IMEXP関数

zが複素数のべき乗は IMEXP(z)

(例)ei π/3 を計算するには

IMEXP(COMPLEX(0, PI() / 3))

= 0.866 + 0.5i

となります。

 

■複素数の足し算(合計を含む) IMSUM関数

複素数xと複素数yの足し算(片方が実数の場合も含む)は IMSUM(x, y)

(例)

セルA1の複素数とセルA2の足し算は IMSUM(A1, A2)

実数の合計の関数(SUM関数)と同様にセルA1~A10を合計するには IMSUM(A1:A10)となります。

 

■複素数の掛け算 IMPRODUCT関数

複素数xと複素数yの掛け算(片方が実数の場合も含む)は IMPRODUCT(x, y)

 

■複素数の割り算 IMDIV関数

複素数xと複素数yの掛け算(片方が実数の場合も含む)は IMDIV(x, y)

 

 

フーリエ変換の意味合いを読み解く

今回、フーリエ変換の式に

の式を用いたのには、フーリエ変換後の値に意味合いを持つため、あえてこの式を用いました。

 

今回、用いたデータはこちらのページ(http://www.data.jma.go.jp/gmd/risk/obsdl/)より2015年と2016年の東京の2年分(731日分)のデータを用いました。

 

2年分の気温データのため、731個のデータの周波数は2になることを期待しています。

 

そこで、あらためてエクセルのシートを眺めてみると、振幅ペクトルは周波数tが0の時の次に最大になるのはt=2の時で周波数2の成分が大きい事がわかります。

 

このことは、731 / 2 = 365.5日 が1周期分のデータ個数となります。

 

t=0 の時の振幅ペクトルの値(16.4625171)は全体の値の平均値を示しています。

 

t=2 の時の振幅スペクトルの値(5.12963)の2倍の値(10.25926)が周波数が2の時の振幅を示しています。

※実際にはt=2と複素共役と呼ばれる虚数成分がt=2のときの負になるt=729の時の2つの波形を足し合わせることで、虚数成分が打ち消しあい、実数部分の振幅が2倍となります。

 

つまり、今回の2年間の気温データは 平均16.4625171 ± 10.25926 ℃ の傾向で気温変化した事がわかります。

 

t=2 の時の位相(155.3578°)の負の値(-155.3578°)の位置にピークの位置が来ることを意味しています。

 

ここまでわかると、2年間の気温データの変化の主な成分はCOS波形で表現する事ができ

 

16.4625171 + 10.25926 × Cos(x / 365.5 × 360° +155.3578°)

 

となります。

この式を気温データに重ね合わせると↓

 

 

見事、気温変化の傾向がつかめました!!

 

(追記)

フーリエ変換のマクロ処理版のページも作成しました。

合わせてご参照頂けたら幸いです。

【Excel】高速フーリエ変換(FFT)のマクロ(VBA)

 

フーリエ変換へ戻る

標準偏差計算の注意点

標準偏差の説明としては、

   標準偏差はデータのバラツキを表す

というのが多いでしょうか?

その性質からデータの誤差などの指標としても用いられる事が多くあります。

しかしながら、 標準偏差=バラつき とだけ覚えていると、実際に標準偏差を用いる時に、思わぬ落とし穴にハマる場合があります。

 

そこで、標準偏差の式を改めて眺めてみると

$$\sigma =\sqrt { \frac { 1 }{ n } \sum _{ i=1 }^{ n }{ { \left( { x }_{ i }-\overline { x } \right) }^{ 2 } } } $$

となっています。

この式が何の計算をしているのか?を言葉で表すと

全データの平均(\(\overline { x } \))と各データ(\({ x }_{ i }\))の差の2乗の平均の平方根

を計算しています。

この計算を図示すると下図のようになります。

 

平均とデータの差の二乗の平均をルートした値が標準偏差です。

 

それでは、具体的に標準偏差を計算するとどうなるのか?を見ていきたいと思います。

 

問題1)AとBのデータの標準偏差は、どちらが大きいでしょうか?

答え)B

平均とデータの差が全体的に大きいBのデータの方が標準偏差が大きくなります。

 

問題2)AとBのデータの標準偏差は、どちらが大きいでしょうか?

AとBのデータのばらつきは、ほぼ同じでデータの個数が異なる場合

答え)AとBもほぼ同じ

バラつきの具合が同じ場合、データの個数が変化しても、標準偏差は平均とデータの差の二乗の平均のルートを計算しているので、標準偏差の値はほぼ同じになります。
ただし、データ個数の少ないBの方がデータの個数が少ないため、1つ1つのデータに平均の値が影響されやすくなり、標準偏差の値が各データの値に依存しやすく(標準偏差の値がバラつきやすく)なります。

 

ここまでは、標準偏差=バラつき と思っていても問題にならない場合ですが、次からは注意が必要な場合の例を示します。

 

問題3)AとBのデータの標準偏差は、どちらが大きいでしょうか?

AとBのデータのばらつきは、ほぼ同じでデータの個数が異なります。
ただし、1点だけ大きく平均からズレたデータが含まれます。

答え)B

AとBのデータのバラつき具合は、一見、同じように見えますが、平均とデータの差の二乗の値の合計をデータ個数で割る際に、データ個数の少ないBの方が値としては大きくなるため、標準偏差はBの方が大きくなります。

 

問題4)AとBのデータの標準偏差は、どちらが大きいでしょうか?

Aのデータは前半25個のデータと、後半25個のデータは同じ。
BのデータはAのデータの前半25個のみ

答え)AとBも同じ

一見、Aのデータの方が大きな誤差を含む点が2点(Bのデータは1点)あるため、Aの方が標準偏差の値が大きくなるように見えなくもありませんが、全データの平均と各データの差の2乗の平均の値(分散という)が同じになるため、標準偏差も同じになります。

 

問題5)AとBのデータの標準偏差は、どちらが大きいでしょうか?

Bのデータは、Aのデータに比べ、細かいデータのバラつきは小さいですが、全体的にデータが傾いています。

答え)B

全データの平均と各データの差の2乗の平均の値がBの方が大きくなるため、標準偏差もBの方が大きくなります。

 

問題6)AとBのデータの標準偏差は、どちらが大きいでしょうか?

Bのデータは、Aのデータに比べ、細かいデータのバラつきは小さいですが、全体的にデータが歪んでいます。

答え)B

問題5と同様に、全データの平均と各データの差の2乗の平均の値がBの方が大きくなるため、標準偏差もBの方が大きくなります。

 

まとめ

問題1~6に示したように、人の目で見たデータのバラつきの大きさと、標準偏差の値の大小とは、必ずしも一致しない場合があります。

そのため、 標準偏差=バラつき とだけ認識するのではなく、標準偏差の計算である

標準偏差 = 全データの平均と各データの差の2乗の平均の平方根

として、計算方法を言葉で覚えておく事をおススメします。

 

それでは、人の感じるバラつきと一致するような値を求めるには、どうすれば良いのか?を考えると、決まりきった計算方法は知らないのですが、問題3のようにデータの個数が異なるデータを比較する場合は、標準偏差の計算をデータ全体で計算するのではなく、部分的に標準偏差を計算すると、ある領域ではAとBのバラつきは同じだが、他の領域ではAの方がバラつきが小さい事が分かります。

問題5、問題6のようにデータ全体に傾きや歪みがある場合は、ガウシアンフィルタなどのノイズ除去処理を強めにかけて(下図の紫の線)、そのノイズ除去された値と各データの値の差(下図の赤の点)に関して標準偏差を計算すると、データ全体の傾きや歪みに影響される事なく、バラつきを求める事ができます。

 

 

 

使える数学へ戻る

離散フーリエ変換(DFT)の直感的理解

フーリエ変換に関しては

と説明してきて、ようやく本題の離散フーリエ変換(DFT:Discrete Fourier Transform)となりました。

いきなり離散フーリエ変換って何?と思われる事もあるかと思いますが、画像や音声、AD信号などのデータに対するフーリエ変換は離散フーリエ変換となります。

フーリエ変換と言えば、FFTの方が有名ですよね。FFTは、Fast Fourier Transformの略で、日本語では高速フーリエ変換となります。このFFTは、データの個数を2のn乗個に制限することで、高速に処理を行う処理アルゴリズムであって、基本的には離散フーリエ変換を行っています。
そのため、いきなりFFTを理解するのではなく、まずは離散フーリエ変換を理解すると、FFTの理解も深まります。

そこで以下については、離散フーリエ変換にいての説明です。

 

フーリエ変換に関しては、数々の説明が本やHPでされていますが、なかなか理解するには至らず、ここでは私なりの理解で説明したいと思います。

説明の途中でベクトルという言葉が出てきますが、厳密なベクトルではなく、複素数のイメージで説明しているように複素数を指している場合があるので、ご了承下さい。

e(ネイピア数)を使った説明

※e(ネイピア数)を使わない説明は後半に記載しました。

 

ここで、いきなり離散フーリエ変換の公式ですが、主に以下の3つの公式を目にします。

 

どの公式もΣ以降は同じで離散フーリエ変換はeの指数部分がマイナス、逆離散フーリエ変換のeの指数部分がプラスとなっています。

異なるのはΣの頭に付く係数のみです。

 

3つも公式を並べると、どれを使えばいいの?みたいに思われるかもしれませんが、どれの公式も正解で使う公式によってパワースペクトルの大きさが異なってきますが、各周波数によって得られるパワースペクトルの相対的に大きさには変わりがありません。

しかし、最初の式だけはパワースペクトル(振幅スペクトル)の値に意味を持つので、最初の式を用いて説明します。
※一般には2番目の式が用いられる場合が多いです。(エクセルも2番目の式となります)

【Memo】
離散フーリエ変換を行った結果[F(t)]は複素数となります。
この複素数の絶対値(大きさ)を振幅スペクトルと言います。
振幅スペクトルを2乗したものがパワースペクトルとなります。

まず、公式のf(x)がフーリエ変換を行うデータの配列で、データ個数がN個となります。

が周波数に近い値で全データ中に含まれる波(1周期分の波)の数を表し、データの個数と同じ0~N-1分だけ波が存在します。

フーリエ変換を行った結果F(t)はある特定の周波数tの時の結果で、やはり0~N-1分だけの結果が存在し、この結果は複素数となります。

 

それでは離散フーリエ変換の詳細を見てみたいと思います。

まず、フーリエ変換の公式の複素数(e)の部分に着目します。

 

 

これを見ると複素数のイメージの部分でも説明しましたが、θの部分が

\(\theta=-\frac{2\pi tx}{N}\)

ですが、x はデータのインデックス番号(0, 1, 2…, N-1)で、Nはデータの個数となっています。

これを少々変形し、

\(\theta=-2\pi t\frac{x}{N}\)

とすると、x/Nの部分は、N個のデータ全体(0, 1, 2,…,N-1)が、0~1になるように調整されているので、tの値により、θの範囲が変わります。

t = 0 のとき、θ = 0
t = 1 のとき、0<= θ < -2\(\pi\)
t = 2 のとき、0<= θ < -4\(\pi\)
t = 3 のとき、0<= θ < -6\(\pi\)
:

となります。

つまり、複素空間におけるベクトルがtの値により時計周り(回転角度が負の方向)にt回転するイメージです。

こんな感じ↓

 

tの値が大きくなると矢印の回転も速くなっていくのですが、途中から回転が逆になり、遅くなるように見えます。

この現象はちょうど、走っている車のタイヤをビデオカメラで撮影すると、タイヤが途中で止まって、さらに車の速度が速くなると、タイヤが逆転するように見えるのと似ています。

 

次にf(x)の部分に着目すると複素数(e)の頭の部分にf(x)が付いているので、各xに対応した複素数の大きさ(ベクトル)がf(x)倍される事になります。

 

 

最後にΣでN個の値を合計して、Nで割っているので、複素数を平均している事が分かります。

 

 

ここで、データの個数が16個だけの簡単な例を示します。

f(0)~f(15)のデータを以下のようにします。

 

このデータを周波数t(0~15)ごとに離散フーリエ変換を行います。

(この結果がF(0)~F(15))

 

 

上図のように、複素平面に変換されたデータ(左側の黒い点)の平均へ向かうベクトル(赤い矢印)こそが、離散フーリエ変換した結果となります。

つまり、離散フーリエ変換の結果は各周波数ごとの複素数となります。

 

このベクトル(赤い矢印)の大きさが各周波数における波形の大きさ(振幅スペクトル)でベクトルの向きが各周波数の位相となります。

ただし、一般に、この振幅スペクトルは各周波数の波形の振幅ではない事にご注意下さい。

 

ここで着目して頂きたいのが、t=7 と t=9、t=6 と t=10、t=5 と t=11・・・がベクトル(赤い矢印)の大きさ同じで位相(ベクトルの向き)が±逆となる組み合わせが存在しています。

 

さらにもう少し詳しく見ていきます。

 

フーリエ変換とは?のページで紹介してますが、任意の波形を以下のように定めます。

 

ただし、

N:データ個数

t = 0、1、2、・・・・N-1

n = 0、1、2、・・・・N-1

At:tの時の振幅

φt:tの時の位相

t:データ全体に含まれる1周期分の波の個数。この値で周波数を調整します。

 

この時、波形の位相φが変化すると、フーリエ変換を行うと、どのように変化するのか?

周波数t=2の時、位相を変えながらフーリエ変換を行う例を以下に示します。

 

上図の左側が複素平面で右側が実数平面です。

 

当然ながら、途中に出てくるベクトル(赤い矢印)の角度(位相)が変化します。

 

次に振幅を変えるとどうなるか?やってみると

 

 

途中に出てくるベクトル(赤い矢印)の大きさ(振幅スペクトル)が変化します。

この振幅スペクトルの大きさが、本記事の上部で紹介している離散フーリエ変換の公式の一番最初に出てくる公式を用いると、振幅スペクトルの大きさは信号の振幅の半分の大きさになるのが、好きなとこ。

 

ここまでは、普通な感じでしょうか。

次からが、フーリエ変換を使う大事なところ!?

 

離散フーリエ変換を行う特定の周波数(ここではt = 2の時)に着目し、それ以外の周波数の信号をフーリエ変換するとどうなるのか?見てみると...

 

 

上図のように、信号の周波数とフーリエ変換を行う周波数とが一致した時のみ振幅スペクトルが出現し、それ以外は振幅スペクトルの大きさが0となります。

上図を見ても分かるように、周波数が一致しないと、複素平面上で中心から放射状にデータを打ち消しあう作用が働き、特定の周波数のみの成分を抽出する事が可能となります。

この辺が、フーリエ変換に複素数を使うのが好きなところ。

 

今度は、各データにバイアス成分というか、直流成分というか、ただのオフセットを加えて変化させてみます。

 

 

途中に出てくるベクトル(赤い矢印)の大きさ(振幅スペクトル)が変化しません!

つまり、信号の周波数が分かっていれば、バイアス成分の影響を受ける事なく、信号の位相を抽出する事ができます。

この性質は、フーリエ変換の位相を使った処理では大事なところです。

 

さらに、周波数t=2の時の例を示してきましたが、この信号に周波数t=2以外の信号を加えたら、周波数t=2の時のフーリエ変換がどうなるか?見ていきます。

 

上図右側の緑色の線が周波数t=2の信号、水色の線が周波数t=2以外の信号、

青色の線が足し合わせた信号です。

 

これを見てもやはり、途中に出てくるベクトル(赤い矢印)の大きさ(振幅スペクトル)が変化しません!

 

もはや複素平面の黒い点はバラバラに見えるのですが、他の周波数の影響を受けずに周波数t=2の信号成分のみを抽出してくれています。

この性質が、よくフーリエ変換を行って、各周波数の振幅スペクトルを解析する事で、周波数の特性を使った処理に使われる要因です。

 

ただし、ここで挙げている例は、少し意図的な部分もあって、合成している波形は全て整数倍で示される周波数の波形を足し合わせた例を示しています。

しかし、実際の信号では、必ずしも整数倍の周波数となる訳もなく、整数倍でない周波数が加わると、複素平面の円の放射方向にデータを打消し合わないなので、振幅スペクトルにも影響が出るのでご注意下さい。

 

と、フーリエ変換については、少し前までは、各周波数成分との正規直交との射影をとる事で、各周波数成分を抽出する!ぐらいの認識でいたのですが、これだといまいちビジュアル的にイメージできません。

 

ここに書いてあるイメージだと、なんだかよく分からなかった複素数もビジュアル的にイメージできて、ようやくフーリエ変換を理解できた気になってます。

 

ちなみに、このフーリエ変換のイメージ、自称 ぐるぐるフーリエ変換

 

e(ネイピア数)を使わない説明

eを使うと、数式的にはシンプルに書けますが、実際のプログラムではeを使えない場合も多いので、sinとcosを使った説明をしたいと思います。

 

離散フーリエ変換は、例えば、周波数が1の場合は、全データをちょうど1回転するようにデータをぐるぐる、複素平面へ変換し、変換したデータの平均(平均すると、実数成分と虚数成分の2つ出てきます)が周波数1の時の離散フーリエ変換の結果となります。

周波数が2の時は、全データをちょうど2回転するようにデータを変換し、平均します。

下図は周波数が2の場合を示していますが、この変換を周波数0~N-1(Nはデータ個数)まで行います。

 

ぐるぐる回す、つまりデータを回転させているのですが、回転といえば、画像処理をしているとアフィン変換に出てくる回転行列がありますよね。

 

$$\left( \begin{matrix} { { x }^{ ‘ } } \\ { y }^{ ‘ } \end{matrix} \right) =\begin{pmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{pmatrix}\left( \begin{matrix} x \\ y \end{matrix} \right) $$

 

離散フーリエ変換における\(x\)と\(y\)は何に相当するか?というと\(x\)が実部、\(y\)が虚部となります。

そのため、\(n\)番目の実部データを\({ Re }_{ n }\)、\(n\)番目の虚部データを\({ Im }_{ n }\)、周波数\(t\)の時の\(n\)番目の角度を\({ \theta t }_{ n }\)とすると、実部と虚部のデータの回転を行列で表すと

 

$$\left( \begin{matrix} { { Re }_{ t,n }^{ ‘ } } \\ { Im }_{ t,n }^{ ‘ } \end{matrix} \right) =\begin{pmatrix} cos{ \theta t }_{ n } & -sin{ \theta t }_{ n } \\ sin{ \theta t }_{ n } & cos{ \theta t }_{ n } \end{pmatrix}\left( \begin{matrix} { Re }_{ n } \\ { Im }_{ n } \end{matrix} \right) $$

 

となります。

周波数\(t\)の時の\(n\)番目の角度\({ \theta t }_{ n }\)は、データの個数Nの全体で1周期分、2周期分…となるように調整し、

 

$${ \theta t }_{ n }=-2\pi t\frac { n }{ N } $$

 

となります。離散フーリエ変換の場合(逆離散フーリエ変換ではなく)、回転方向がマイナス方向(時計回り)になるため、角度の頭にマイナスが付きます。

 

この \({ { Re }_{ t,n }^{ ‘ } }\) と \({ { Im }_{ t,n }^{ ‘ } }\) の\(n\)について、0~N-1の値を平均すると、周波数\(t\)の時の離散フーリエ変換後の値が求まります。

 

周波数\(t\)の時の離散フーリエ変換後の

実部は

$$\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ { Re }_{ t,n }^{ ‘ } } =\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ \left\{ cos\left( -2\pi t\frac { n }{ N } \right) \times { Re }_{ n }-sin\left( -2\pi t\frac { n }{ N } \right) \times { Im }_{ n } \right\} } $$

虚部は

$$\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ { Im }_{ t,n }^{ ‘ } } =\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ \left\{ sin\left( -2\pi t\frac { n }{ N } \right) \times { Re }_{ n }+cos\left( -2\pi t\frac { n }{ N } \right) \times { Im }_{ n } \right\} } $$

となります。

 

あとは周波数\(t\)に関して t = 0 ~ N-1 の時の実部と虚部の値を求めると、各周波数ごとの実部と虚部の成分が求まります。

残すは周波数ごとの実部と虚部の値から、大きさと位相に変換する場合が多いのですが、これは三平方の定理的に考えればいいだけなので簡単です。

 

 

 

 

 

 

 

 

 

 

 

$$大きさ=\sqrt { { 実部 }^{ 2 }+{ 虚部 }^{ 2 } } $$

$$位相={ tan }^{ -1 }\frac { 虚部 }{ 実部 } $$

 

となります。

 

これで以上ですが、実際の離散フーリエ変換では、二次元フーリエ変換でもない限り?変換する元のデータの虚部(Im)は0(ゼロ)の場合が多いので、プログラム的には

実部を

$$\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ { Re }_{ t,n }^{ ‘ } } =\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ \left\{ cos\left( -2\pi t\frac { n }{ N } \right) \times { Re }_{ n } \right\} } $$

虚部を

$$\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ { Im }_{ t,n }^{ ‘ } } =\frac { 1 }{ N } \sum _{ n=0 }^{ N-1 }{ \left\{ sin\left( -2\pi t\frac { n }{ N } \right) \times { Re }_{ n } \right\} }$$

として計算する場合もあります。

まとめ

以上のように、離散フーリエ変換はデータを周波数に合わせてグルグル巻きにして平均を計算します。

1周期の成分は、全データを1回転させて平均する。
2周期の成分は、全データを2回転させて平均する。
3周期の成分は、全データを3回転させて平均する。
・・・
のようにします。

この時、平均した位置と原点までの距離がその周波数の大きさ、X軸と原点ー平均の位置のなす角度が位相になります。フーリエ変換では、何かと大きさばかりに注目されがちですが、位相も有用です。

周波数という言葉を使うと単位はHz(1/秒)?と思ってしまうかもしれませんが、記事中では厳密な使い方をしていません。単位が必要な場合は、全データを何秒でサンプリングしたのか?が重要になってきます。

例えば、全データを2秒でサンプリングした場合は、
1周期と言っていた周波数は、2秒で1回転するので、0.5Hzとなります。
同様に2周期の場合は2秒で2回転するので1Hz
3周期の場合は2秒で3回転するので1.5Hz
となります。

実際のところ、個人的にはFFTや離散フーリエ変換を画像処理に使う機会は、ほとんどありません。
0~N-1周期分の全てのデータが必要ではなく、ある特定の周波数成分はどの程度あるのか?みたいな使い方は良くします。
そのためFFTよりも離散フーリエ変換の方を部分的に使う事が多いので、ぜひ、離散フーリエ変換を理解して応用できるようになって欲しい!という思いで、この記事を書きました。

 

フーリエ変換へ戻る

複素数のイメージ

離散フーリエ変換を勉強すると、突然

 

e = cosθ + i sinθ

 

みたいな式が突然出てきて、これが何だかよく分からないまま、とりあえず公式だけを覚えてみたり...

しかも i  は「実際には存在しない虚数」みたいに教わったので、存在しない物は、なかなかイメージもしにくい。

 

で、いろいろ調べてみて、今ではなんとなく

 

e は複素平面における 長さ1傾きθ のベクトル

 

ぐらいの認識でいます。

 

 

複素平面ではX軸に相当する部分が実部(Real part)、Y軸に相当する部分が虚部(Imaginary part)と呼ばれます。

 

回転方向は反時計まわりが正で時計まわりが負となります。

 

よく e-iθ というのも目にしますが、これはむしろ ei(-θ) と 書いてくれた方が分かりやすいと思いますが、e-iθ は、回転方向がマイナス、つまり時計まわりになります。

 

また、e の頭に係数が付く場合がありますが、その係数分だけベクトルの長さが変化します。

例えば 2e の場合だと

 

のようにベクトルの長さが2となります。

係数の値が負の場合は、ベクトルの向きが逆になり、-2e の場合だと

 

のようになります。

ただ、実際には e の頭に係数はθの値に応じて変化する場合が多く、例えば

 

(sinθ) e

 

のθの値を0~360°で変化させるとどうなるか?というと、このよう↓になります。

 

 

実はフーリエ変換をイメージで覚えるうえで、上図のように思えた事が最大のポイントで、とても嬉しかった~!!!

 

上図をよ~く見てみると、ベクトルの先端は円を描き、この円の中心が(0, 0.5)の座標になっています。

これを少し言い方を変えると、円の中心へのベクトルは長さ0.5、傾きが+90の位置にあります。

この事は、すでに少しだけフーリエ変換になってます。

 

と、ここまで説明しといて、例題としては  (sinθ) e -iθ  の方が良かったかな...ちょっと失敗??

ちなみに(sinθ) e -iθ  だと、円の中心は(0, -0.5)の位置に来ます。

 

複素数、複素関数について、もう少し詳しく知りたい方は、下記ファイルが参考になると思います。

 

複素関数を学ぶ人のために

http://collie.low-temp.sci.yamaguchi-u.ac.jp/~ashida/work/comp.pdf

 

フーリエ変換へ戻る

関連記事

複素数の計算

フーリエ変換の種類

フーリエ変換と言っても、フーリエという言葉が付く変換はいくつかあります。

 

簡単に分類すると、こんな感じ↓でしょうか?

 

フーリエ変換
    フーリエ変換(Fourier Transform)
    離散フーリエ変換(DFT:Discrete Fourier Transform)
            高速フーリエ変換(FFT:Fast Fourier Transform)

 

フーリエとは付きませんが近いのに離散コサイン変換(DCT:Discrete Cosine Transform)というのもあります。

 

フーリエ変換を大きく分類すると、頭に何も付かないフーリエ変換と離散という言葉の付く離散フーリエ変換とがあります。

 

この頭に何も付かないフーリエ変換は変換相手がsinやcosなどの数式で、フーリエ変換の公式にも積分の式()が用いられます。

 

対して離散フーリエ変換は音声や電圧、画像などのように測定データが対象で離散フーリエ変換の公式には積算の式(Σ)が用いられます。

 

高速フーリエ変換(FFT)は離散フーリエ変換の一種で、データの個数が2のn乗(2,4,8,16,32・・・)個の時に特別に高速に処理をできるアルゴリズムで、基本的な処理は離散フーリエ変換となります。

 

私がフーリエ変換を行う場合は、画像や電圧などの測定データを相手にする場合がほとんどなので、単に「フーリエ変換」と言っておきながら「離散フーリエ変換」の事を指して言っている場合もあるかもしれません...

 

フーリエ変換へ戻る

 

フーリエ変換とは?

フーリエ変換は何をしているのか???

 

下図の示すように、任意波形を各周波数の成分に分解し、その大きさ(振幅)および位置(位相)を求める計算がフーリエ変換となります。

 

逆に、振幅と位相から元の波形を求める計算が逆フーリエ変換となります。

 

このフーリエ変換を行うと何が良いのか???

用途は様々なのですが、

 

  • 振幅から、どの周波数成分が強いのか?解析を行う。
  • 位相から、位相のズレで距離(形状)を算出する。
  • 特定周波数の振幅を0(ゼロ)にして、逆フーリエ変換を行い、フィルタ処理(ノイズ除去など)を行う。
  • 振幅および位相から元のデータを算出する事で、元のデータを少ない値から算出する。
    (データ圧縮)

 

などなど。

 

ここで、私がなかなかフーリエ変換を理解できなかったポイントですが、

 

「任意波形はサイン波形を足し合わせると求める事ができる!」

 

みたいな説明が良くあります。さらに位相についても触れられていない場合が多いです。

 

しかし、この説明だとsin(0°)は、いつも0(ゼロ)なので、いくら各周波数成分を足し合わせても0°の値は0になってしまいます。

 

そのため、sin波形で考えるのではなく、cos波形で考えた方が良いと思います。

この時、各周波数の成分は下記の式で表されます。

 

ただし、

N:データ個数

t = 0、1、2、・・・・N-1

n = 0、1、2、・・・・N-1

t:tの時の振幅

φt:tの時の位相

t:データ全体に含まれる1周期分の波の個数。この値で周波数を調整します。

 

また、一度は聞いた事があるであろうパワースペクトルの値は振幅そのものを求めていない場合が多い。

(この事にはついては、別の記事で説明したいと思います。)

 

画像処理をやった事がある人では、フーリエ変換は、各周波数をテンプレートとしたテンプレートマッチングを行い、相関値がフーリエ変換のパワースペクトルに相当していると思えば、感覚的には似ています。

(ただし、数学的には異なります。)

 

と、ざっくりなイメージはこんな感じです。

 

もう少し、まじめにフーリエ変換を理解したい場合は内積正規直交規定を理解しておくと、良いかと思います。

 

フーリエ変換へ戻る