左右対称で周期的な関数の原点を見つける方法

ちょっと事情があって方法を考えていた。すぐ出来るんじゃないかと思ったけどなかなか思いつかなかった。や、厳密に左右対称が保障されていて計算時間も十分あるならいくらでも方法はあるけど元が実験データとかで誤差があり計算時間もあまりない時間の場合とする。計算時間はせいぜいO(n^2)以内がよい。・・・と勝手に足かせをつけたまま考えていました。まあなんとかみつかったっぽいけど。

で、表題の関数だけど定量的に書けばだいたいこんなかんじ。
f( x + L ) = f( x )
f( -( x - \delta ) ) = f( x - \delta )
この2つの条件を満たすf(x)で、Lは分かっているがδがわかっていない状態で、δをどうやって求めるか?という方法だ。もっと具体的に言うと、xがO〜Lまでの整数の値でのf(x)の値が分かっている場合にδをどうやって求めるか?ということ。案外出来そうで出来ない。

まず最初に大抵の人が思いつくだろうと思う総当り法。δの値を0からLまで試して対称の式に当てはめて最も誤差が少ないδが正解という方法。定量的には
\sum_x^N \{ f( -( x - \delta ) ) - f( x - \delta ) \}^2
という量を各δに対して求めるという方法。いわゆる最小二乗法ですね。確かにこれならうまく行きそうだが実は大きな落とし穴がある。誤差がY方向にのみなら精度は高いがX方向に誤差がある場合はとんでもない答えになる可能性がある。例えばピークがいくつかあるような関数の場合で、ピークの位置が誤差としてずれている場合。この場合、上記の式は正解のδでもえらい大きい値になる可能性がある。こういう関数の場合はピークの位置を最初に見つけてそれぞれのピークの位置が一番合うδを見つけるのが一番いいのだがそもそもピークがどの程度あるとかは全然わからないのだ。そうなるとまずはピークがあるかどうかから調べなければいけない。

つぅわけで根本的に違う方法が必要なのだが・・・とりあえず今日思いついた方法を以下説明。


まず仮にδが0だとして周期Lのフーリエ級数展開をしてみる。
f(x) = \sum_n^N \{ A_n \cos(\frac{2\pi n}{L}x) + B_n sin(\frac{2\pi n}{L}x) \}
ここで、f(x)=f(-x)なので、sinの項はすべて0になる。つまりcosだけの展開になる。(もちろん誤差がなければの話だけど)
f(x) = \sum_n^N A_n \cos(\frac{2\pi n}{L}x)
で、実際にはδだけ移動しているわけだから補正する。
f(x-\delta) = \sum_n^N A_n \cos(\frac{2\pi n}{L}( x - \delta ) )
加法定理で右辺を展開する。
f(x-\delta) = \sum_n^N A_n \{ \cos(\frac{2\pi n}{L}x)\cos(\frac{2\pi n}{L}\delta) + \sin(\frac{2\pi n}{L}x)\sin(\frac{2\pi n}{L}\delta) \}
f(x-\delta) = \sum_n^N \{ (A_n\cos(\frac{2\pi n}{L}\delta))\cos(\frac{2\pi n}{L}x) + (A_n\sin(\frac{2\pi n}{L}\delta))\sin(\frac{2\pi n}{L}x) \}
f(x-\delta) = \sum_n^N \{ A'_n\cos(\frac{2\pi n}{L}x) + B'_n\sin(\frac{2\pi n}{L}x )\}
というわけで普通にフーリエ級数展開すればA’とB’が出てきます。適当なnでのA’とB’を持ってきて割り算します。
\frac{B'_n}{A'_n} = \frac{A_n\sin(\frac{2\pi n}{L}\delta)}{A_n\cos(\frac{2\pi n}{L}\delta)}
\frac{B'_n}{A'_n} = \tan(\frac{2\pi n}{L}\delta)
\delta = \frac{L}{2\pi n}\tan^{-1}(\frac{B'_n}{A'_n})
というわけでδが出てきました。さてこの計算方法のいいところは理想的な状態だと計算がO(N)で出来ること、また各モードでδの値を出せるということで誤差率をある程度見積もることが出来ること。・・・だと思っております。
まあ実際にやってみた計算はここまでで精度とか誤差率とかはちゃんと考察してないので分かりません。だれかわかったら教えて(ぇ