pypy.com/

Python、Unity、FX自動化などを勉強しています。あと、コーラと車も好きです。そこらへんについて、たまに記事を書きます。

C言語で自由落下をシミュレートする(オイラー法)

こんにちは。

今回は、自由落下のシミュレーションをC言語でやってみたいと思います。
いままで、いろいろな微分方程式の解法をやってきましたが、少し実問題っぽくやっていきます。

それでは、書いていきます。

自由落下の方程式

まず、高校で、以下のような運動方程式を習います。 $$ ma = F $$ 自由落下では、質点が重力を受けることを考慮するので、重力加速度gを用いて、 $$ ma = -mg $$ 両辺から、mを除して、 $$ a = -g $$ 今回求めるのが、位置xだとして、 $$ \frac{d^{2}x}{{dt}^2}=-g $$ これが、解かなければならない微分方程式になります。
この方程式は、2階の情微分方程式なので、前に紹介したオイラー法で解くことができます。
オイラー法で解く際に、速度vを導入し、以下のように式を変形します。 $$ \frac{dx}{dt} = v $$ $$ \frac{dv}{dt} = -g $$ 上式を踏まえて、
オイラー法では、次のように、xとvを更新していきます。

$$ x_{i+1} = x_i + vdt $$

$$ v{i+1} = v{i} - gdt $$

自由落下を解くC言語コード

今回は、問題設定として、上向きに初期速度100で投げて、地面に落ちてくるまでをシミュレートします。
時間刻み$dt$、速度の初期値$v_0$、位置の初期値$x_0$を次のようにします。 $$ dt = 0.01 $$ $$ v_0 = 100.0 $$ $$ x_0 = 0.0 $$ これを踏まえて、厳密解は以下のように求まります。

$$ x(t) = {-0.5gt}^{2} + 100.0t $$

$$ v(t) = -gt + 100.0 $$ これを踏まえて、コードは以下のようになります。

#include <stdio.h>
#include <math.h>

double f_x(double x_pre, double v_pre, double dt);
double f_v(double x_pre, double v_pre, double g, double dt);
double calc_true_x_val(double t, double g);
double calc_true_v_val(double t, double g);

int main(void){
    FILE *outputfile;
    outputfile = fopen("out.txt", "w");
    // パラメータ
    double m = 1.0;
    double g = 9.80665;
    // 初期値
    double x = 0.0;
    double v = 100.0;
    // 解析範囲
    double t_start = 0.0;
    double t_end = 50.0;
    // 刻み時間
    double dt = 0.01;
    // 分割数
    int n = (int)((t_end-t_start) / dt) + 1;

    printf("t, x, v, true_x, true_v\n");
    for(double i=0; i<n; i++){
        double x_new = f_x(x, v, dt);
        double v_new = f_v(x, v, g, dt);
        double true_x_val = calc_true_x_val(t_start+dt*i, g);
        double true_v_val = calc_true_v_val(t_start+dt*i, g);
        x = x_new;
        v = v_new;
        printf("%5.5lf,%5.5lf,%5.5lf,%5.5lf,%5.5lf\n", t_start+dt*i, x, v, true_x_val, true_v_val);
        fprintf(outputfile, "%5.5lf,%5.5lf,%5.5lf,%5.5lf,%5.5lf\n", t_start+dt*i, x, v, true_x_val, true_v_val);
        if(x_new<=0.0){
            break;
        }
    }
}

double f_x(double x_pre, double v_pre, double dt){
    return x_pre + v_pre * dt;
}

double f_v(double x_pre, double v_pre, double g, double dt){
    return v_pre - g * dt;
}

double calc_true_x_val(double t, double g){
    return -0.5*g*t*t + 100.0*t;
}

double calc_true_v_val(double t, double g){
    return -g*t + 100.0;
}

これを実行して、得た結果をプロットしてみると、以下のようになります。

プロットを見ると、厳密解とほぼ一致していることが確認できます。