斜方投射 速度の二乗に比例する空気抵抗がある場合
斜方投射や、自由落下では、速度の二乗に比例して、空気抵抗(慣性抵抗)が発生するのが一般的です。
自由落下では、落下開始のほんの一瞬だけ、速度に比例した抵抗になるようですが、計算上無視できる時間のようです。
斜方投射では、初速度を持っているので、速度の二乗に比例した抵抗しか発生しないのが殆どとなります。
初速度ゼロの場合、自由落下として計算が可能です。
計算式の成り立ちについては、インターネットで"斜方投射"、"慣性抵抗"で検索してください。
単に斜方投射で検索すると、速度に空気抵抗が比例する例が表示されます。
斜方投射の計算は、初速度v0に対して、水平方向の速度
v0x = v0cosθ と、垂直方向の速度v0y = v0sinθ に分けて計算します。
上方投射の垂直方向は、上昇中と、下降中の二つに分けて計算します。
その為に、最初に最高点に達するまでの時間を先に計算して、最高点に達するまでの時間より前か、後かで計算を分けます。
斜方投射計算は、あくまでも、斜め上に投射した場合で、下方への投射は考慮されていません。
投射が水平より、下方になった場合の垂直方向の計算で、下方への初速度がt∞の速度を超えている場合、自由落下 2 初速度がある場合の計算を使用します。
t∞の速度を超えない場合は、自由落下で初速度に達する時間t0、を計算し、投射からの時間tをt0に加算して計算します。
その後、初速度迄の値を減算すれば、目的を達することができます。
投射が下方になった場合でも、水平方向の計算は変わりません。
これで、投射角度 90°~-90°までの範囲で計算ができる様になります。
左図は、斜方投射のプログラム実行画面です。
k:空気抵抗係数を放物線の計算に使用しますが、空気抵抗係数は、単独でも空気抗力係数Cd、空気密度ρ、有効面積Sから計算できるようになっています。
又、k:空気抵抗係数欄に値を入力すれば、入力した値が、放物線計算に使用されます。
プログラム
// 空気抵抗が速度の二乗に比例する場合 unit main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VclTee.TeeGDIPlus, VCLTee.TeEngine, VCLTee.Series, Vcl.ExtCtrls, VCLTee.TeeProcs, VCLTee.Chart, Vcl.StdCtrls, Vcl.Buttons; type TForm1 = class(TForm) Chart1: TChart; Series1: TLineSeries; GroupBox1: TGroupBox; rhoEdit: TLabeledEdit; sumEdit: TLabeledEdit; KcalcBtn: TBitBtn; kEdit: TLabeledEdit; CdEdit: TLabeledEdit; Memo1: TMemo; GroupBox2: TGroupBox; mEdit: TLabeledEdit; v0Edit: TLabeledEdit; thEdit: TLabeledEdit; gEdit: TLabeledEdit; calcBtn: TBitBtn; Series2: TLineSeries; Series3: TLineSeries; tmEdit: TLabeledEdit; Label1: TLabel; Label2: TLabel; tyRadioButton: TRadioButton; XYRadioButton: TRadioButton; TXRadioButton: TRadioButton; tvRadioButton: TRadioButton; Series4: TLineSeries; RedCheckBox: TCheckBox; Series5: TPointSeries; VCheckBox: TCheckBox; mxyRadioButton: TRadioButton; Series6: TLineSeries; Label3: TLabel; Label4: TLabel; Label5: TLabel; procedure calcBtnClick(Sender: TObject); procedure KcalcBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} uses system.Math; //----------------空気抵抗無しx方向位置計算------------------------------------- // t 時間 // v0x 初速度 function xs(t, v0x: double): double; begin result := t * v0x; end; //----------------空気抵抗無しy方向位置計算------------------------------------- // t 時間 // v0y 初速度 // g 重力加速度 // vf 速度計算フラグ true 速度 false 距離 function ys(t, v0y, g: double; vf: boolean): double; begin if vf then // 速度計算 result := v0y - g * t else // 距離計算 result := - g * t * t / 2 + v0y * t; end; //----------------空気抵抗有りx方向位置速度計算------------------------------------- // t 時間 // k 空気抵抗係数 // m 質量 // v0x 初速度 // vf 速度計算フラグ true 速度 false 距離 function xl(t, k, m, v0x: double; vf: boolean): double; begin if m = 0 then begin result := 0; exit; end; if vf then begin // 速度計算 if v0x = 0 then result := 0 else result := 1 / (k / m * t + 1 / v0x); end else // 距離計算 result := m / k * ln(k * v0x / m * t + 1); end; //----------------空気抵抗有りy方向位置速度計算------------------------------------- // t 時間 // k 空気抵抗係数 // m 質量 // v0y 初速度 // th 最高度時間 // g 重力加速度 // vf 速度計算フラグ true 速度 false 距離 function yl(t, k, m, v0y, th, g: double; vf: boolean): double; const KCC = 1.4142; var cc : double; tv : double; // v0yになる迄の仮の時間 yv : double; // tvの落下距離 y1v : double; // 落下距離 v0 : double; // 実行速度 nv0 : double; // 予実行速度 dt : double; // Δt fm : double; // 平均速度 fv : double; // 減速後速度 dm : double; // t∞抗力 dv : double; // 速度抗力 ndv : double; // 予速度抗力 mdg : double; // 減速加速度 nmdg : double; // 予減速加速度 vmax : double; // t∞速度 ymax : double; // 最高点 i, j : integer; begin if vf then begin // 速度計算 if v0y >= 0 then begin // 投射角度 >= 0 if m = 0 then begin result := 0; exit; end; if t < th then begin // 速度上昇計算 result := sqrt(m * g / k) * tan(sqrt(k * g / m) * (th -t)); end else begin // 速度下降計算 result := - sqrt(m * g / k) * tanh(sqrt(k * g / m) * (t - th)); end; end else begin // 投射角度 < 0 if m = 0 then begin result := 0; exit; end; cc := -v0y / sqrt(m * g / k); if cc <= 1 then begin // 下降初速度が最大降下速度より遅い場合 tv := arctanh(cc) / sqrt(k * g / m); // 初速度に達する時間 // ゼロからの時間tv + 指定時間tの速度 result := - sqrt(m * g / k) * tanh(sqrt( k * g / m) * (tv + t)); end else begin // 下降初速度が最大降下速度より早い場合 近似計算 if (t = 0) or (m = 0) then begin // t = 0 なら result := v0y; // 初速度 exit; end; vmax := sqrt(m * g / k); // t∞速度 dm := vmax * vmax * k; // t∞抗力 j := 1000; // 分割数 dt := t / j; // Δt v0 := -v0y; // 速度 cc := power(maxdouble, 1 / 2) * m; // 演算オーバーフローチェック値 for i := 1 to j do begin // 分割積分 dv := v0 * v0 * k; // v0抗力 mdg := (dv - dm) / m; // 加速度 nv0 := v0 - mdg * dt; // Δt減速後速度 ndv := nv0 * nv0 * k; // 予減速後抗力 nmdg := (ndv - dm) / m; // 予減速後加速度 mdg := (mdg + nmdg) / 2; // 平均加速度 v0 := v0 - mdg * dt; // 新速度 if (v0 > cc) or (v0 < 0) then break; // オーバーフローの場合ブレーク end; if (v0 > cc) or (v0 < 0) then begin result := maxdouble; // オーバーフロー数セット exit; end; result := -v0; // 戻り値 速度 end; end; end else begin // 距離計算 if v0y >= 0 then begin // 投射角度 >= 0 if (t = 0) or (m = 0) then begin // t = 0 なら result := 0; // 速度0 exit; end; ymax := ln(1 + k / (m * g) * v0y * v0y); // 最高点 if t < th then begin // 上昇計算 cc := cos(sqrt(k * g / m) * (th - t)); result := m / k * ln(cc) + m / (2 * k) * ymax; end else begin // 下降計算 cc := sqrt(k * g / m) * (t - th); if cc > 710.4 then begin // double の計算で710.4より大きいとcoshがオーバーフロー result := maxdouble; exit; end; cc := cosh(sqrt(k * g / m) * (t - th)); result := - m / k * ln(cc) + m / (2 * k) * ymax; end; end else begin // 投射角度 < 0 cc := -v0y - sqrt(m * g / k); if cc < 0 then begin // 下降初速度が最大降下速度より遅い場合 cc := -v0y / sqrt(m * g / k); tv := arctanh(cc) / sqrt(k * g / m); // 初速度に達する時間 // ゼロからの初速度迄の距離 cc := sqrt(k * g / m) * tv; if cc > 710.4 then begin // double の計算で710.4より大きいとcoshがオーバーフロー result := maxdouble; exit; end; cc := cosh(cc); // 初速度に達するまでの距離 yv yv := - m / k * ln(cc); // 移動距離 = 速度ゼロからの距離 - 初速度に達するまでの距離 cc := sqrt(k * g / m) * (tv + t); if cc > 710.4 then begin // double の計算で710.4より大きいとcoshがオーバーフロー result := maxdouble; exit; end; cc := cosh(cc); // 移動距離 result := - m / k * ln(cc) - yv; end else begin // 下降初速度が最大降下速度より早い場合 近似計算 if (t = 0) or (m = 0) then begin // t = 0 なら result := 0; // 距離 = 0 exit; end; y1v := 0; // 距離0初期化 vmax := sqrt(m * g / k); // t∞速度 dm := vmax * vmax * k; // t∞抗力 j := 1000; // 分割数 dt := t / j; // Δt v0 := - v0y; // 速度 cc := power(maxdouble, 1 / 2) * m; // 演算オーバーフローチェック数 for i := 1 to j do begin // 分割積分 dv := v0 * v0 * k; // v0抗力 mdg := (dv - dm) / m; // 加速度 fv := v0 - mdg * dt; // 予Δt減速後速度 ndv := fv * fv * k; // 予fv抗力 nmdg := (ndv - dm) / m; // 予加速度 mdg := (mdg + nmdg) / 2; // 加速度平均 fm := v0 - mdg * dt; // 速度 y1v := y1v + (fm + v0) / 2 * dt; // Δt距離加算 v0 := fm; // 新速度 if (v0 > cc) or (v0 < 0) then break; // オーバーフローの場合ブレーク end; if (v0 > cc) or (v0 < 0) then begin result := maxdouble; // オーバーフローフラグ数セット exit; end; result := - y1v; // 戻り値 距離 end; end; end; end; //-------------------計算実行--------------------------------------------------- procedure TForm1.calcBtnClick(Sender: TObject); label TV, MXY; var k : double; // 空気抵抗係数 m : double; // 質量 v0 : double; // 初速度 v0x, v0y : double; // x,y方向初期速度 thd, thr : double; // 角度 th : double; // 最高度時間 ymax : double; // 最高点 ymin : double; // 最下点 y <= 0 g : double; // 重力加速度 t, dt : double; // 時間 ty : double; // 落下時間 x, y, xmax : double; // 位置 L0 : double; // 水平距離 ch, i, imax : integer; tm : double; // グラフ表示時間 cc : double; MVF : boolean; // 下向き投射時最大策度より投射速度が速いフラグ mv : double; // 下向き投射時最大策度より投射速度が速い質量 begin Memo1.Clear; val(kEdit.Text, k, ch); if ch <> 0 then begin Memo1.Text := 'k:空気抵抗係数に間違いがあります。'; exit; end; if k <= 0 then begin Memo1.Text := 'k:空気抵抗係数の値は0(ゼロ)より大きくしてください。'; exit; end; val(mEdit.Text, m, ch); if ch <> 0 then begin Memo1.Text := 'm:質量に間違いがあります。'; exit; end; if m <= 0 then begin Memo1.Text := 'm:質量の値は0(ゼロ)より大きくしてください。'; exit; end; val(V0Edit.Text, v0, ch); if ch <> 0 then begin Memo1.Text := 'v0:初速度に間違いがあります。'; exit; end; if v0 < 0 then begin Memo1.Text := 'v0:初速度の値は0(ゼロ)より大きくしてください。'; exit; end; val(thEdit.Text, thd, ch); if ch <> 0 then begin Memo1.Text := 'th:投射角度に間違いがあります。'; exit; end; if thd < -90 then begin Memo1.Text := 'th:投射角度の値は-90°より大きくしてください。'; exit; end; if thd > 90 then begin Memo1.Text := 'th:投射角度の値は90°より小さくしてください。'; exit; end; val(gEdit.Text, g, ch); if ch <> 0 then begin Memo1.Text := 'g:加速度に間違いがあります。'; exit; end; if g <= 0 then begin Memo1.Text := 'g:加速度の値は0(ゼロ)より大きくしてください。'; exit; end; val(tmEdit.Text, tm, ch); if ch <> 0 then begin Memo1.Text := 'tm:計算時間に間違いがあります。'; exit; end; if tm <= 0 then begin Memo1.Text := 'tm:計算時間の値は0(ゼロ)より大きくしてください。'; exit; end; Series1.Clear; Series2.Clear; Series3.Clear; Series4.Clear; Series5.Clear; Series6.Clear; Label1.Visible := false; Label2.Visible := false; Label3.Visible := false; Label4.Visible := false; Label5.Visible := false; thr := thd / 180 * pi; // deg -> rad v0x := v0 * cos(thr); // 水平速度 v0y := v0 * sin(thr); // 垂直速度 if thd = -90 then begin v0x := 0; v0y := -v0; end; if thd = 90 then begin v0x := 0; v0y := v0; end; if thd < 0 then begin // 下向き投射の時 cc := -v0y / sqrt(m * g / k); if cc >= 1 then begin memo1.Lines.Append('下降の初速度が速すぎるので近似計算です。'); end; end; th := 0; ty := 0; memo1.Lines.Append('速度の2乗に抵抗が比例する場合。'); Chart1.BottomAxis.Title.Text := 'X'; Chart1.LeftAxis.Title.Text := 'Y'; if tvradiobutton.Checked = true then goto TV; if mxyradiobutton.Checked = true then goto MXY; if redcheckbox.Checked = true then begin label2.Caption := '桃: 空気抵抗無'; label2.Visible := true; end; label1.Caption := '青: 空気抵抗有'; label1.Visible := true; if thd > 0 then begin th := sqrt(m / (k * g)) * arctan(sqrt(k / (m * g)) * v0y); // 最高点到達時間 ymax := m / (2 * k) * ln(1 + k / (m * g) * v0y * v0y); // 最高点 ty := sqrt(m / (g * k)) * arccosh(exp(ymax * k / m)); // y=0迄の落下時間 ymax >=0 L0 := xl(th + ty, k, m, v0x, false); // y=0水平距離 memo1.Lines.Append(' 最高点 '+ floatTostr(ymax) + ' m'); memo1.Lines.Append(' 最高点時間 '+ floatTostr(th) + ' sec'); memo1.Lines.Append(' y=0水平距離 '+ floatTostr(l0) + ' m'); memo1.Lines.Append(' y=0水平時間 '+ floatTostr(th + ty) + ' sec'); memo1.Lines.Append(floatTostr(tm) + 'sec の距離'); x := xl(tm, k, m, v0x, false); memo1.Lines.Append(' 水平距離 '+ floatTostr(x) + ' m'); y := yl(tm, k, m, v0y, th, g, false); if y = maxdouble then begin memo1.Clear; memo1.Lines.Append('1 表示希望時間が長すぎます。'); exit; end; memo1.Lines.Append(' 垂直距離 '+ floatTostr(y) + ' m'); end else begin x := xl(tm, k, m, v0x, false); memo1.Lines.Append(' 水平距離 '+ floatTostr(x) + ' m'); y := yl(tm, k, m, v0y, th, g, false); if y = maxdouble then begin memo1.Clear; memo1.Lines.Append('2 表示希望時間が長すぎます。'); exit; end; memo1.Lines.Append(' 垂直距離 '+ floatTostr(y) + ' m'); if thd = 0 then begin // 投射角 = 0 ty := sqrt(m / (g * k)) * arccosh(exp(abs(y) * k / m)); memo1.Lines.Append(' 落下時間 '+ floatTostr(ty) + ' sec'); end else begin memo1.Lines.Append(' 落下時間 '+ floatTostr(tm) + ' sec'); end; end; // tm グラフ用表示用計算時間長さ選択 if thd = 0 then begin if (th + ty) > tm then tm := round((th + ty) * 1.1 * 1000) / 1000; end else begin if thd > 0 then begin if ((th + ty) * 1.1) > tm then tm := round((th + ty) * 1.1 * 1000) / 1000; end else tm := round(tm * 1.1 * 1000) / 1000; end; dt := round(tm * 1000) / 1000000; imax := round(tm / dt); t := 0; xmax := 0; ymax := 0; ymin := 0; Chart1.BottomAxis.Title.Text := 'm'; Chart1.LeftAxis.Title.Text := 'm'; // グラフ表示 if XYradiobutton.Checked = true then begin // XY距離 memo1.Lines.Append('グラフ時間計算 tm ' + floatTostr(tm) + ' sec'); for i := 0 to imax do begin t := i * dt; // 時間 if redcheckbox.Checked = true then begin // 空気抵抗なしチェックあり x := xs(t, v0x); // 空気抵抗なし x y := ys(t, v0y, g, false); // 空気抵抗なし y if x > xmax then xmax := x; if y > ymax then ymax := y; if ymin > y then ymin := y; Series2.AddXY(x, y); // 空気抵抗なしグラフデーター追加 end; x := xl(t, k, m, v0x, false); // 空気抵抗有り x y := yl(t, k, m, v0y, th, g, false); // 空気抵抗有り y if y = maxdouble then begin memo1.Clear; memo1.Lines.Append('3 表示希望時間が長すぎます。'); exit; end; if x > xmax then xmax := x; if y > ymax then ymax := y; if ymin > y then ymin := y; Series1.AddXY(x, y); // xyグラフデーター追加 end; // グラフ表示サイズ設定 if xmax > (ymax - ymin) then ymax := xmax + ymin; if (ymax - ymin) > xmax then xmax := (ymax - ymin); Series3.AddXY(-xmax / 100,0); Series3.AddXY(xmax * 1.1, 0); if thd < 0 then Series5.AddXY(xmax * 1.1, ymin * 1.1) else Series5.AddXY(xmax * 1.1, ymax * 1.05); end; dt := tm / 1000; imax := round(tm / dt); if tyradiobutton.Checked = true then begin // 垂直高さ memo1.text := memo1.text + 'グラフ時間軸 tm ' + floatTostr(tm) + ' sec'; for i := 0 to imax do begin t := i * dt; if redcheckbox.Checked = true then begin y := ys(t, v0y, g, false); // 空気抵抗なし y if y > ymax then ymax := y; Series2.AddXY(t, y); // グラフデーター追加 end; y := yl(t, k, m, v0y, th, g, false); // 空気抵抗有り y if y = maxdouble then begin memo1.Clear; memo1.Lines.Append('4 表示希望時間が長すぎます。'); exit; end; if y > ymax then ymax := y; Series1.AddXY(t, y); // tyグラフデーター追加 end; Chart1.BottomAxis.Title.Text := 'sec'; Chart1.LeftAxis.Title.Text := 'm'; // グラフ表示サイズ設定 Series3.AddXY(-t / 100,0); Series3.AddXY(t * 1.1, 0); Series5.AddXY(t * 1.1, ymax * 1.1); end; if txradiobutton.Checked = true then begin // 水平距離 memo1.text := memo1.text + 'グラフ時間軸 tm ' + floatTostr(tm) + ' sec'; for i := 0 to imax do begin t := i * dt; if redcheckbox.Checked = true then begin // 空気抵抗なしチェックあり if thd = -90 then x := 0 // 真下 距離x=0 else x := xs(t, v0x); // 空気抵抗なし x if x > xmax then xmax := x; Series2.AddXY(t, x); // txグラフデーター追加 end; if thd = -90 then x := 0 // 真下なので距離ゼロ else x := xl(t, k, m, v0x, false); // 空気抵抗有り 距離x if x > xmax then xmax := x; Series1.AddXY(t, x); // txグラフデーター追加 end; Chart1.BottomAxis.Title.Text := 'sec'; Chart1.LeftAxis.Title.Text := 'm'; // グラフ表示サイズ設定 Series3.AddXY(-t / 100,0); Series3.AddXY(t * 1.1, 0); Series5.AddXY(t * 1.1, xmax * 1.1); end; exit; TV: // t秒後の速度計算 memo1.Lines.Append(floatTostr(tm) + 'sec 後の速度'); memo1.Lines.Append('速度の2乗に抵抗が比例する場合。'); if thd > 0 then begin th := sqrt(m / (k * g)) * arctan(sqrt(k / (m * g)) * v0y); // 最高点到達時間 x := xl(tm, k, m, v0x, true); memo1.Lines.Append(' 水平速度 '+ floatTostr(x) + ' m / s'); y := yl(tm, k, m, v0y, th, g, true); memo1.Lines.Append(' 垂直速度 '+ floatTostr(y) + ' m / s'); end else begin x := xl(tm, k, m, v0x, true); memo1.Lines.Append(' 水平速度 '+ floatTostr(x) + ' m / s'); y := yl(tm, k, m, v0y, th, g, true); memo1.Lines.Append(' 垂直速度 '+ floatTostr(y) + ' m'); end; memo1.Lines.Append('空気抵抗がない場合。'); x := v0x; // 空気抵抗なし x y := ys(tm, v0y, g, true); // 空気抵抗なし y memo1.Lines.Append(' 水平速度 '+ floatTostr(x) + ' m / s'); memo1.Lines.Append(' 垂直速度 '+ floatTostr(y) + ' m / s'); // tm グラフ用表示用計算時間長さ選択 tm := round(tm * 1.1 * 1000) / 1000; dt := round(tm * 1000) / 1000000; memo1.text := memo1.text + 'グラフ時間軸 tm ' + floatTostr(tm) + ' sec'; imax := round(tm / dt); ymax := 0; ymin := 0; // グラフ表示 label1.Caption := '空気抵抗:有 垂直:青 '; label2.Caption := '空気抵抗:無 垂直:桃 '; label3.Caption := '水平:緑'; label4.Caption := '水平:赤'; label5.Caption := 't∞:茶色'; if redcheckbox.Checked = true then begin // 空気抵抗なしチェックあり label2.Visible := true; label4.Visible := true; end; label1.Visible := true; label3.Visible := true; Chart1.BottomAxis.Title.Text := 'sec'; Chart1.LeftAxis.Title.Text := 'm/s'; for i := 0 to imax do begin t := i * dt; if redcheckbox.Checked = true then begin // 空気抵抗なしチェックあり x := v0x; // 空気抵抗なし x y := ys(t, v0y, g, true); // 空気抵抗なし y if x > ymax then ymax := x; if y > ymax then ymax := y; if ymin > y then ymin := y; if ymin > x then ymin := x; Series2.AddXY(t, y); // グラフデーター追加 Series4.AddXY(t, x); // グラフデーター追加 end; x := xl(t, k, m, v0x, true); // 空気抵抗有り x y := yl(t, k, m, v0y, th, g, true); // 空気抵抗有り y if x > ymax then ymax := x; if y > ymax then ymax := y; if ymin > y then ymin := y; if ymin > x then ymin := x; Series1.AddXY(t, y); // グラフデーター追加 Series3.AddXY(t, x); // グラフデーター追加 end; // グラフ表示サイズ設定 Series5.AddXY(0, -(ymax - ymin) * 0.1 + ymin); Series5.AddXY(0, (ymax - ymin) * 0.1 + ymax); exit; MXY: // 質量と距離速度の関係 // tm グラフ用表示用計算時間長さ選択 Chart1.BottomAxis.Title.Text := 'kg'; if vcheckbox.Checked = false then // 速度表示選択なし Chart1.LeftAxis.Title.Text := 'm' else // 速度表示選択 Chart1.LeftAxis.Title.Text := 'm/s'; label1.Caption := '空気抵抗:有 X:青'; label3.Caption := 'Y:緑'; label1.Visible := true; label3.Visible := true; memo1.Lines.Append('計算時間 ' + floatTostr(tm) + ' sec'); t := tm; tm := round(m * 1.1 * 1000) / 1000; dt := round(tm * 1000) / 1000000; imax := round(tm / dt); if vcheckbox.Checked = true then begin // 速度表示選択 memo1.Lines.Append('水色線 無限大時間速度'); label1.Caption := '空気抵抗:有 X:青 '; label3.Caption := 'Y:緑 '; label5.Visible := true; label5.Caption := 't∞ 速度:茶'; end; memo1.text := memo1.text + 'グラフ X軸 m ' + floatTostr(tm) + ' kg'; ymax := 0; ymin := 0; MVF := false; mv := 0; for i := 0 to imax do begin m := dt * i; // 質量 if thd < 0 then begin // 下向き投射の時 if m > 0 then begin cc := -v0y - sqrt(m * g / k); if cc > 0 then begin // 投射速度が最大速度より早いとき MVF := true; // フラグセット mv := m; end; end; end; if thd > 0 then begin // 上向き投射 th := 0; if m > 0 then th := sqrt(m / (k * g)) * arctan(sqrt(k / (m * g)) * v0y); // 最高点到達時間 end; if vcheckbox.Checked = true then begin // 速度表示選択 x := xl(t, k, m, v0x, true); // 空気抵抗有り速度 x y := yl(t, k, m, v0y, th, g, true); // 空気抵抗有り速度 y ty := -sqrt(m * g / k); if ymin > ty then ymin := ty; Series6.AddXY(m, ty); // m,t∞速度グラフ end else begin x := xl(t, k, m, v0x, false); // 空気抵抗有距離り x y := yl(t, k, m, v0y, th, g, false); // 空気抵抗有距離り y end; if y = maxdouble then begin // オーバーフローだったら memo1.Clear; memo1.Lines.Append('3 表示希望時間が長すぎます。'); memo1.Lines.Append('又は初期速度が速すぎます。'); exit; end; if x > ymax then ymax := x; if y > ymax then ymax := y; if ymin > y then ymin := y; if ymin > x then ymin := x; Series1.AddXY(m, x); // m,x グラフデーター追加 Series3.AddXY(m, y); // m,y グラフデーター追加 end; if MVF then begin // 投射速度が最大速度より早いとき memo1.Lines.Append('質量 m=' + floattostr(mv) + ' kg 迄'); memo1.text := memo1.text + '下降の初速度が速すぎるので近似計算の範囲です。'; end; // グラフ表示サイズ設定 Series5.AddXY(0, -(ymax - ymin) * 0.1 + ymin); Series5.AddXY(0, (ymax - ymin) * 0.1 + ymax); end; //-----------------空気抗力係数から空気抵抗計算kg/m計算------------------------- procedure TForm1.KcalcBtnClick(Sender: TObject); var k : double; // 空気抵抗係数 kg/m Cd : double; // 空気抗力係数 r : double; // 空気密度 kg/m^3 S : double; // 代表面積 m^2 ch : integer; begin memo1.Clear; val(CdEdit.Text, Cd, ch); if ch <> 0 then begin Memo1.Text := 'Cd:空気抗力係数に間違いがあります。'; exit; end; val(rhoEdit.Text, r, ch); if ch <> 0 then begin Memo1.Text := 'ρ:空気密度に間違いがあります。'; exit; end; val(sumEdit.Text, S, ch); if ch <> 0 then begin Memo1.Text := 'S:代表面積に間違いがあります。'; exit; end; k := Cd * r * s / 2; kEdit.Text := floatTostr(k); end; //------------------------------------------------------------------------------ procedure TForm1.FormCreate(Sender: TObject); begin memo1.Text := '放物線の計算'; end; end.