Mathematicaを使って実関数のヒルベルト変換を求める

◼
  • 執筆者:技術部・降旗
  • ◼
  • 使用したバージョン:Mathematica14.2
  • ◼
  • 使用した主な関数:Convolve, FourierTransform, InverseFourierTransform, Sign, Abs, Arg, ArkTan, D
  • はじめに

    先日ヒルベルト変換についてのお問い合わせをいただいたため、Mathematicaで実行するにはどうすれば良いかを調べてみました。
    本記事ではMathematicaを使って
    ◼
  • ヒルベルト変換
  • ◼
  • 包絡線
  • ◼
  • 瞬時周波数
  • ◼
  • 瞬時位相
  • を求めてみます。
    なお、計算方法については小野測器様で公開されている資料 ( https://www.onosokki.co.jp/HP-WK/eMM_back/emm180.pdf )を参考にしました。

    ヒルベルト変換

    今回は実信号
    x[t]
    をチャープ信号とし、次のように定義します。
    In[]:=
    Clear["Global`*"]
    In[]:=
    x[t_]:=Cos
    t
    4
    +
    2
    t
    20
    
    In[]:=
    Plot[x[t],{t,0,200}]
    Out[]=
    x[t]
    のヒルベルト変換
    
    x
    [t]
    は
    
    x
    [t]=x[t]*
    1
    πt
    =
    1
    π
    ∞
    ∫
    -∞
    x[τ]
    t-τ
    τ​​*は畳み込み、積分はコーシーの主値積分
    によって定義されるため、 Convolve を使って畳み込みを求めてみます。
    In[]:=
    Convolvex[τ],
    1
    Piτ
    τ,t,PrincipalValue->True
    Out[]=
    ConvolveCos
    τ
    4
    +
    2
    τ
    400
    ,
    1
    π
    ,t,PrincipalValueTrue
    残念ながらこの信号では求めることができませんでした。(他の信号ではこのまま求められるものもありました。)
    そこで、今度はフーリエ変換を行ってから位相をずらし、逆フーリエ変換を行う方法を試してみます。
    まず、
    X[t]
    を求めます。
    In[]:=
    FourierTransform[x[t],t,f]
    Out[]=
    (5-5)Cos
    25
    4
    -50f+100
    2
    f
    +(5+5)Cos
    25
    4
    +50f+100
    2
    f
    +(5+5)Sin
    25
    4
    -50f+100
    2
    f
    +(5-5)Sin
    25
    4
    +50f+100
    2
    f
    
    続いて、
    
    X
    [t]
    を求めます。(%は一つ前に実行した結果です。計算の順序によっては同じ結果が得られないため注意が必要です。必要であれば任意の変数に代入してください。)
    In[]:=
    %*ISign[f]
    Out[]=
    Sign[f](5-5)Cos
    25
    4
    -50f+100
    2
    f
    +(5+5)Cos
    25
    4
    +50f+100
    2
    f
    +(5+5)Sin
    25
    4
    -50f+100
    2
    f
    +(5-5)Sin
    25
    4
    +50f+100
    2
    f
    
    そして、逆フーリエ変換により
    
    x
    [t]
    を求めます。(この信号では実行に少し時間がかかります。)
    In[]:=
    InverseFourierTransform[%,f,t]
    Out[]=
    1
    2
    Cos
    1
    400
    t(100+t)-Sin
    1
    400
    t(100+t)-1-Cos
    1
    200
    t(100+t)+Erfc-
    1
    20
    -
    
    20
    (50+t)
    2
    +Cos
    1
    200
    t(100+t)Erfc
    1
    20
    +
    
    20
    (50+t)
    2
    -Sin
    1
    200
    t(100+t)+Erfc
    1
    20
    +
    
    20
    (50+t)
    2
    Sin
    1
    200
    t(100+t)
    無事に
    
    x
    [t]
    が求まりました。式が少し長いため、FullSimplifyを使って簡略化を試します。
    In[]:=
    FullSimplify[%]
    Out[]=
    -
    1
    2
    
    -
    1
    400
    t(100+t)
    
    1
    200
    t(100+t)
    
    Erf
    1
    20
    1/4
    (-1)
    (50+t)+Erf
    1
    20
    3/4
    (-1)
    (50+t)
    In[]:=
    
    x
    [t_]:=-
    1
    2
    
    -
    1
    400
    t(100+t)
    
    1
    200
    t(100+t)
    
    Erf
    1
    20
    1/4
    (-1)
    (50+t)+Erf
    1
    20
    3/4
    (-1)
    (50+t)
    求まった関数をプロットしてみます。
    In[]:=
    Plotx[t],
    
    x
    [t],{t,0,200}
    Out[]=
    
    x
    [t]
    を求めることができましたので、解析信号
    z[t]
    を求めます。
    In[]:=
    z[t_]:=x[t]+I
    
    x
    [t]
    In[]:=
    z[t]
    Out[]=
    Cos
    t
    4
    +
    2
    t
    400
    +
    1
    2
    -
    1
    400
    t(100+t)
    
    1
    200
    t(100+t)
    
    Erf
    1
    20
    1/4
    (-1)
    (50+t)+Erf
    1
    20
    3/4
    (-1)
    (50+t)

    包絡線

    包絡線は
    z[t]
    の絶対値として求められるため、Absを使用します。
    In[]:=
    envelope[t_]:=Abs[z[t]]
    関数をプロットしてみます。
    In[]:=
    Plot[{x[t],envelope[t]},{t,0,200}]
    Out[]=
    式の形を確認してみます。
    In[]:=
    envelope[t]
    Out[]=
    AbsCos
    t
    4
    +
    2
    t
    400
    +
    1
    2
    -
    1
    400
    t(100+t)
    
    1
    200
    t(100+t)
    
    Erf
    1
    20
    1/4
    (-1)
    (50+t)+Erf
    1
    20
    3/4
    (-1)
    (50+t)
    In[]:=
    FullSimplify[%]
    Out[]=
    1
    2
    1
    400
    Im[t(100+t)]
    
    Abs1+
    1
    200
    t(100+t)
    
    1+Erf
    1
    20
    1/4
    (-1)
    (50+t)+Erf
    1
    20
    3/4
    (-1)
    (50+t)
    tが実数であると仮定すると、もう少しシンプルな形になります。
    FullSimplify[%,Assumptions->t∈Reals]

    瞬時位相

    瞬時位相 θ[t] は
    の式で求められるため、ArcTanを使って求めます。
    関数をプロットします。
    なお、ArcTanを使わずに、Argを使ってz[t]の偏角を求める方法もあります。
    ただし、こちらの方法では式にArgが残ってしまいます。
    Argは微分ができないため、次の瞬時周波数を求めることができません。

    瞬時周波数

    瞬時周波数 f[t] は
    の式によって求められるため、Dを使って求めます。
    求まった関数をプロットします。

    おわりに

    今回はヒルベルト変換を使って実信号を複素時間信号に変換し、包絡線や瞬時周波数を求めてみました。
    他のソフトでは、数値データに対してヒルベルト変換を行う例は見つかりましたが、数式に対してヒルベルト変換を行う例は見当たらなかったため、この辺りはMathematicaの強みではないかと思います。
    なお、いくつかの信号を試してみましたが、信号によっては途中式がかなり長くなってしまい、計算にかかる時間も長くなるケースがありました。
    そのため、場合によってはFullSimplifyを使って途中で出力される式を簡約化するなどの工夫が必要になるかもしれません。