Projectile Motion in 2D with Air Drag

This notebook simulates 2D projectile motion with quadratic air drag and compares it to the no-drag case.

Setup

If[NotebookDirectory[] =!= $Failed, SetDirectory[NotebookDirectory[]]];

ClearAll[simulateProjectile];
Options[simulateProjectile] = {
  "g" -> 9.81,          (* m/s^2 *)
  "m" -> 0.145,         (* kg *)
  "c" -> 0.02,          (* drag coefficient *)
  "DragLaw" -> "quadratic",
  "tmax" -> 20
};

simulateProjectile[v0_, thetaDeg_, opts : OptionsPattern[]] := Module[
  {g = OptionValue["g"], m = OptionValue["m"], c = OptionValue["c"],
   dragLaw = OptionValue["DragLaw"], tmax = OptionValue["tmax"],
   θ, drag, sol, rfun, tEnd},

  θ = thetaDeg Degree;

  drag[v_] := Which[
    dragLaw === "linear", -c v,
    dragLaw === "quadratic", -c v Norm[v],
    True, -c v Norm[v]
  ];

  sol = NDSolve[
    {
      r''[t] == drag[r'[t]]/m + {0, -g},
      r[0] == {0, 0},
      r'[0] == v0 {Cos[θ], Sin[θ]},
      WhenEvent[r[t][[2]] <= 0 && t > 0, "StopIntegration"]
    },
    r,
    {t, 0, tmax},
    MaxStepFraction -> 1/200
  ];

  rfun = r /. First@sol;
  tEnd = Last@rfun["Domain"][[1]];

  <|"Solution" -> rfun, "tEnd" -> tEnd|>
];

Parameters

v0 = 35;    (* m/s *)

theta = 50; (* degrees *)

simDrag = simulateProjectile[v0, theta, "c" -> 0.02, "DragLaw" -> "quadratic"];
simNoDrag = simulateProjectile[v0, theta, "c" -> 0.0, "DragLaw" -> "quadratic"];

Trajectory Comparison

trajDrag = ParametricPlot[
  Evaluate[simDrag["Solution"][t]],
  {t, 0, simDrag["tEnd"]},
  PlotStyle -> {Thick, RGBColor[0.85, 0.2, 0.1]},
  PlotRange -> All
];

trajNoDrag = ParametricPlot[
  Evaluate[simNoDrag["Solution"][t]],
  {t, 0, simNoDrag["tEnd"]},
  PlotStyle -> {Dashed, Thick, RGBColor[0.1, 0.3, 0.8]},
  PlotRange -> All
];

comparisonPlot = Show[
  trajDrag,
  trajNoDrag,
  Frame -> True,
  FrameLabel -> {"x (m)", "y (m)"},
  PlotRange -> All,
  ImageSize -> 700,
  PlotLegends -> Placed[LineLegend[{"Quadratic drag", "No drag"}], {0.75, 0.8}]
];

comparisonPlot

Interactive Manipulate

Manipulate[
  Module[{simD, simND, trajD, trajND, tt},
    simD = simulateProjectile[v0, theta, "c" -> c, "DragLaw" -> dragLaw];
    simND = simulateProjectile[v0, theta, "c" -> 0.0, "DragLaw" -> dragLaw];

    trajD = ParametricPlot[
      Evaluate[simD["Solution"][τ]],
      {τ, 0, simD["tEnd"]},
      PlotStyle -> {Thick, RGBColor[0.85, 0.2, 0.1]},
      PlotRange -> All
    ];

    trajND = ParametricPlot[
      Evaluate[simND["Solution"][τ]],
      {τ, 0, simND["tEnd"]},
      PlotStyle -> {Dashed, Thick, RGBColor[0.1, 0.3, 0.8]},
      PlotRange -> All
    ];

    tt = t * simD["tEnd"];

    Show[
      trajD,
      If[showNoDrag, trajND, Graphics[{}]],
      Graphics[{RGBColor[0.85, 0.2, 0.1], PointSize[Large], Point[simD["Solution"][tt]]}],
      Frame -> True,
      FrameLabel -> {"x (m)", "y (m)"},
      PlotRange -> All,
      ImageSize -> 700,
      PlotLegends -> Placed[LineLegend[{"Drag", "No drag"}], {0.75, 0.8}]
    ]
  ],
  {{v0, 35, "v0 (m/s)"}, 5, 60, 1},
  {{theta, 50, "theta (deg)"}, 10, 80, 1},
  {{c, 0.02, "drag c"}, 0, 0.1, 0.002},
  {{dragLaw, "quadratic", "drag law"}, {"quadratic", "linear"}},
  {{showNoDrag, True, "show no-drag"}, {True, False}},
  {{t, 0, "flight progress"}, 0, 1, Animator},
  ControlPlacement -> Left
]

Notes

- Change "c" to adjust drag strength.
- Switch to linear drag by setting "DragLaw" -> "linear" in simulateProjectile.
- Units are SI throughout.