ONLY DO WHAT ONLY YOU CAN DO

こけたら立ちなはれ 立ったら歩きなはれ

C++で常微分方程式(ルンゲ・クッタ法)

※再度修正
参考 http://www.enjoy.ne.jp/~k-ichikawa/Satellite3.html
初速 250 km/h で, 45°の角度で打ったボールの軌跡をルンゲ・クッタ法で計算する
(空気抵抗係数を 0.01 で計算)

重力による鉛直方向の減速分は, 重力加速度を g, 時間を t とすると,

空気抵抗による水平方向の減速分は,速度を v, 速度の水平方向成分を vx, 空気抵抗係数を k とすると,

同様に, 鉛直方向の減速分は, 速度の鉛直方向成分を vy とすると,

初期値 x0 から次の式によって, 順次 x1, x2, … を求める.

#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;

// 重力加速度
const double g = -9.8;
// 空気抵抗係数
const double k = -0.01;
// 時間間隔(秒)
const double h = 0.01;

// 空気抵抗による水平方向の減速分
double fx(double vx, double vy);
// 重力と空気抵抗による鉛直方向の減速分
double fy(double vx, double vy);

int main()
{
    // 角度 
    double degree = 45;
    double radian = degree * M_PI / 180.0;
    // 初速 250 km/h -> 秒速に変換
    double v = 250 * 1000 / 3600; 
    // 水平方向の速度
    double vx[5]; 
    vx[0] = v * cos(radian); 
    // 鉛直方向の速度
    double vy[5]; 
    vy[0] = v * sin(radian); 
    // 経過秒数
    double t = 0.0;
    // 位置
    double x[5];
    x[0] = 0.0;
    double y[5];
    y[0] = 0.0;

    // Runge-Kutta法
    for (int i = 1; y[0] >= 0.0; i++) 
    {
        // 経過秒数
        t = i * h;
        cout << setw(4) << fixed << setprecision(2) << t << "\t";

        // 位置・速度
        x[1]  = h *    vx[0];
        y[1]  = h *    vy[0];
        vx[1] = h * fx(vx[0], vy[0]);
        vy[1] = h * fy(vx[0], vy[0]);

        double wx = vx[0] + vx[1] / 2;
        double wy = vy[0] + vy[1] / 2;
        x[2]  = h *    wx;
        y[2]  = h *    wy;
        vx[2] = h * fx(wx, wy);
        vy[2] = h * fy(wx, wy);

        wx    = vx[0] + vx[2] / 2;
        wy    = vy[0] + vy[2] / 2;
        x[3]  = h *    wx;
        y[3]  = h *    wy;
        vx[3] = h * fx(wx, wy);
        vy[3] = h * fy(wx, wy);

        wx    = vx[0] + vx[3];
        wy    = vy[0] + vy[3];
        x[4]  = h *    wx;
        y[4]  = h *    wy;
        vx[4] = h * fx(wx, wy);
        vy[4] = h * fy(wx, wy);

        x[0]  += ( x[1] +  x[2] * 2 +  x[3] * 2 +  x[4]) / 6;
        y[0]  += ( y[1] +  y[2] * 2 +  y[3] * 2 +  y[4]) / 6;
        vx[0] += (vx[1] + vx[2] * 2 + vx[3] * 2 + vx[4]) / 6;
        vy[0] += (vy[1] + vy[2] * 2 + vy[3] * 2 + vy[4]) / 6;

        cout << setw(8) << fixed << setprecision(5) << vx[0] << "\t";
        cout << setw(9) << fixed << setprecision(5) << vy[0] << "\t";
        cout << setw(9) << fixed << setprecision(5) <<  x[0] << "\t";
        cout << setw(8) << fixed << setprecision(5) <<  y[0] << endl;
    }
    return 0;
}

// 空気抵抗による水平方向の減速分
double fx(double vx, double vy)
{
    return k * sqrt(vx * vx + vy * vy) * vx;
}
// 重力と空気抵抗による鉛直方向の減速分
double fy(double vx, double vy)
{
    return g + (k * sqrt(vx * vx + vy * vy) * vy);
}
0.01	48.45619	 48.35852	  0.48623	 0.48574
0.02	48.12689	 47.93222	  0.96914	 0.96719
0.03	47.80236	 47.51133	  1.44878	 1.44440
0.04	47.48250	 47.09575	  1.92520	 1.91743
0.05	47.16722	 46.68537	  2.39845	 2.38633
0.06	46.85642	 46.28007	  2.86856	 2.85116
0.07	46.55001	 45.87974	  3.33559	 3.31195
0.08	46.24790	 45.48430	  3.79958	 3.76877
0.09	45.94999	 45.09363	  4.26056	 4.22165
0.10	45.65621	 44.70764	  4.71859	 4.67066
省略
6.20	 9.25063	-23.74826	125.74997	 2.41410
6.21	 9.22707	-23.78565	125.84236	 2.17643
6.22	 9.20355	-23.82289	125.93451	 1.93839
6.23	 9.18006	-23.85997	126.02643	 1.69997
6.24	 9.15661	-23.89690	126.11811	 1.46119
6.25	 9.13319	-23.93366	126.20956	 1.22203
6.26	 9.10982	-23.97027	126.30078	 0.98251
6.27	 9.08647	-24.00673	126.39176	 0.74263
6.28	 9.06317	-24.04303	126.48251	 0.50238
6.29	 9.03990	-24.07917	126.57302	 0.26177
6.30	 9.01667	-24.11516	126.66330	 0.02080
6.31	 8.99347	-24.15100	126.75335	-0.22053