Scilabで数値微分 その1

数値計算から関数の微分を求めようと考えたとき、微分の定義の通りに差分を計算すれば良いということはすぐに思いつきます。

f'(x) = \lim_{h \to 0} \frac{f(x+h)-f(x)}{h}

上記の式のhを次第に小さくしていけばf'(x)の近似値が得られます。
しかしながらhの数を小さくしすぎると数値計算の丸め誤差の影響で逆にf'(x)の値からずれていってしまうことが知られています。

これに関連する重要なポイントをまとめると以下の3つになります。

  • 倍精度浮動小数点数を使い丸め誤差を小さくする
  • 打切り誤差の小さいアルゴリズムを使う
  • 丸め誤差と打切り誤差のトータルで誤差が小さくなるhを探す


Scilabは特に指定をしなくても倍精度浮動小数点数演算をしてくれるので、今回は数値計算の常識に倣って数値微分の式とhの大きさを色々と変更したときに誤差の大きさがどのようになるのかを見てみます。


数値微分の近似式


数値微分を計算する公式として数値計算の常識に倣って前進差分f1(x)、中心差分f2(x)、及びそれらのRomberg 1段公式を用いました。

前進差分
f_1(x,h) = \frac{f(x+h)-f(x)}{h}

中心差分
f_2(x,h) = \frac{f(x+h)-f(x-h)}{2h}

前進差分に対するRomberg 1段
\frac{f_1(x,h)-\frac{1}{2}f_1(x,2h)}{1-\frac{1}{2}}

中心差分に対するRomberg 1段
\frac{f_2(x,h)-\frac{1}{4}f_2(x,2h)}{1-\frac{1}{4}}

Scilabプログラム


実際に計算する関数は普通のサイン関数f(x)=sin(x)とします。
当然ながら解析的に微分が可能でf'(x)=cos(x)です。

数値計算の常識と同様にx=0.3πのときの微分を計算します。

微分の刻み幅hは
h = 2^{-n}

とし、nが大きくなるほどhは小さくなります。

作成したScilabのプログラムはdiff_sce.txtです。

clear;

// *** 刻み幅の設定 ***
n = [0:1:50];
h = 2 ^ (- n);

x = 0.3 * %pi;

// *** 微分の近似値 ***
// 前進差分
f1 = (sin(x + h) - sin(x)) ./ h;
// 中心差分
f2 = (sin(x + h) - sin(x - h)) ./ (2 * h);
// 前進差分に対するRomberg 1段公式
romberg1 = 2 * ((sin(x + h) - sin(x)) ./ h - 0.5 * (sin(x + 2 * h) - sin(x)) ./ (2 * h));
// 中心差分に対するRomberg 1段
romberg2 = ((sin(x + h) - sin(x - h)) ./ (2 * h) - 0.25 * (sin(x + 2 * h) - sin(x - 2 * h)) ./ (4 * h)) / 0.75;

// *** グラフの軸設定 ***
a = gca();
a.data_bounds = [0,1E-16;50,1];
a.log_flags = "nl";

// *** グラフのプロット ***
plot(n,abs(f1 - cos(x)),'-sr');
plot(n,abs(f2 - cos(x)),'-sm');
plot(n,abs(romberg1 - cos(x)),'-sb');
plot(n,abs(romberg2 - cos(x)),'-sg');

// *** グラフの体裁 ***
xlabel("n");
ylabel("Err");
legend(['f1(x)','f2(x)','Romberg f1(x)','Romberg f2(x)'],4);


結果


以下に示すFig.1は上記の4つの式で計算したf(x)のx=0.3πでの微分の値とf'(x)=cos(x)の値の差の絶対値を取ったものです。
この2つの差が数値計算の誤差ということになります。

001_20131110042107c73.png

Fig.1: 数値微分と解析的な微分の間の関係。縦軸は誤差の絶対値、横軸はnで、nが大きくなるほどhは小さくなる(h = 2-n)。


まずn>25では、全てのグラフにおいて同じ挙動を示しています。これが丸め誤差によるものでどの式を使っても丸め誤差の問題は改善されないことが分かります。

次にnが小さい側、すなわち打切り誤差の影響を見てみます。
前進差分f1(x)(赤)と中心差分f2(x)(ピンク)を比べてみると、nが小さいとき中心差分f2(x)(ピンク)の方が誤差が小さくなることが分かります。

また前進差分f1(x)(赤)とそのRomberg 1段(青)を比較すると、Romberg 1段(青)で打切り誤差が改善していることが見て取れます。

中心差分f2(x)(ピンク)とf1(x)に対するRomberg 1段(青)では誤差はほとんど変わりませんが、中心差分f2(x)(ピンク)にさらにRomberg 1段(緑)をおこなうとこれら4つの式の中で最も誤差の少ない式に出来ることがわかります。

関連エントリ




付録


このエントリで使用したScilabのプログラムを添付します。ファイル名末尾の".txt"を削除して、"_"を"."に変更すれば使えるはずです。(参考:ねがてぃぶろぐの付録)


参考文献/使用機器




フィードバック



にほんブログ村 その他趣味ブログ 電子工作へ

 ↑ 電子工作ブログランキング参加中です。1クリックお願いします。


コメント・トラックバックも歓迎です。 ↓      


 ↓ この記事が面白かった方は「拍手」をお願いします。


tag: Scilab 数値微分 

comment

Secret

FC2カウンター
カテゴリ
ユーザータグ

LTspiceAkaiKKRScilabmachikaneyamaKKRPSoCOPアンプPICCPA強磁性モンテカルロ解析常微分方程式トランジスタode状態密度インターフェースDOSPDS5022ecaljスイッチング回路定電流半導体シェルスクリプトレベルシフト乱数HP6632A温度解析ブレッドボードI2CR6452A分散関係トランジスタ技術可変抵抗確率論数値積分反強磁性セミナー非線形方程式ソルバ絶縁バンドギャップ熱設計偏微分方程式バンド構造GW近似カオス三端子レギュレータLEDフォトカプラシュミットトリガISO-I2CA/DコンバータLM358USBカレントミラーTL431マフィンティン半径PC817C数値微分アナログスイッチ発振回路サーボ直流動作点解析74HC40532ちゃんねる標準ロジックチョッパアンプLDAアセンブラFFTbzqltyイジング模型ブラべ格子開発環境補間量子力学電子負荷BSchパラメトリック解析単振り子基本並進ベクトル熱伝導繰り返しGGAMaximaTLP621ewidthSMP相対論抵抗位相図ランダムウォークスピン軌道相互作用六方最密充填構造不規則合金FETコバルト失敗談QSGWcygwinスレーターポーリング曲線スイッチト・キャパシタラプラス方程式gfortranキュリー温度状態方程式条件分岐格子比熱TLP552LM555TLP521三角波NE555過渡解析FXA-7020ZRWriter509テスタ詰め回路MCUマントルダイヤモンドQNAPデータロガーガイガー管自動計測UPS井戸型ポテンシャルawk第一原理計算仮想結晶近似ブラウン運動差し込みグラフ平均場近似fsolve起電力熱力学OpenMPスーパーセル固有値問題最適化最小値VCAシュレディンガー方程式VESTAubuntu最大値面心立方構造PGAOPA2277L10構造非線型方程式ソルバ2SC1815fccフェルミ面等高線ジバニャン方程式ヒストグラム確率論マテリアルデザイン正規分布結晶磁気異方性interp1フィルタ初期値ウィグナーザイツ胞c/aルチル構造岩塩構造スワップ領域リジッドバンド模型edeltBaOウルツ鉱構造重積分SIC二相共存ZnOquantumESPRESSOCapSensegnuplotmultiplot全エネルギー固定スピンモーメントFSM合金ノコギリ波フォノンデバイ模型ハーフメタル半金属TeXifortTS-110不規則局所モーメントTS-112等価回路モデルパラメータ・モデルヒストグラムExcel円周率GimpトラックボールPC直流解析入出力文字列マンデルブロ集合キーボードフラクタル化学反応三次元Realforce縮退日本語最小二乗法関数フィッティング疎行列シンボル線種ナイキスト線図陰解法負帰還安定性熱拡散方程式EAGLECrank-Nicolson法連立一次方程式P-10クーロン散乱Ubuntu境界条件MBEHiLAPW軸ラベルトランスCK1026MAS830L凡例PIC16F785LMC662AACircuit両対数グラフ片対数グラフグラフの分割specx.f

最新コメント
リンク

にほんブログ村 その他趣味ブログ 電子工作へ