{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# Arm Length Fractions\n", "\n", "This notebook performs a parameter study of the projectile and counterweight arm lengths of a hinged counterweight trebuchet. It fixes the total arm length and varies the fraction projectile_arm_length/total_arm_length. For some values of this fraction, the projectile sling is not in tension for the full duration of the launch." ] }, { "cell_type": "code", "execution_count": null, "id": "1", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", "from pytrebuchet.simulation import Simulation\n", "from pytrebuchet.trebuchet import HingedCounterweightTrebuchet, Arm\n", "\n", "\n", "# Define range of arm fraction values to test\n", "arm_fractions = np.linspace(\n", " 0.5, 0.8, 100\n", ") # fraction of total arm length that is projectile arm\n", "total_arm_length = 1.75 + 6.792\n", "\n", "# Define result arrays\n", "distances = np.empty_like(arm_fractions, dtype=np.float64)\n", "in_tension = np.empty_like(arm_fractions, dtype=bool) # Track if sling stays in tension\n", "\n", "# Compute distance for each arm fraction\n", "default = HingedCounterweightTrebuchet.default()\n", "for i, arm_fraction in enumerate(arm_fractions):\n", " # Create trebuchet with specified arm lengths\n", " projectile_arm_length = arm_fraction * total_arm_length\n", " counterweight_arm_length = total_arm_length - projectile_arm_length\n", " trebuchet = HingedCounterweightTrebuchet(\n", " arm=Arm(\n", " length_projectile_side=projectile_arm_length,\n", " length_weight_side=counterweight_arm_length,\n", " mass=default.arm.mass,\n", " ),\n", " weight=default.weight,\n", " pivot=default.pivot,\n", " sling_projectile=default.sling_projectile,\n", " sling_weight=default.sling_weight,\n", " release_angle=default.release_angle,\n", " projectile=default.projectile,\n", " )\n", "\n", " # Simulate\n", " simulation = Simulation(\n", " trebuchet, verify_sling_tension=False\n", " ) # we will check tension manually\n", " simulation.solve()\n", "\n", " # Record distance and tension status\n", " distances[i] = simulation.distance_traveled\n", " in_tension[i] = np.all(simulation.where_sling_in_tension())\n", "\n", "# Plot results\n", "fig, ax = plt.subplots()\n", "ax.plot(arm_fractions, distances, label=\"Distance Traveled\")\n", "ax.fill_between(\n", " arm_fractions,\n", " 0,\n", " np.max(distances),\n", " where=in_tension,\n", " color=\"green\",\n", " alpha=0.3,\n", " label=\"Sling in Tension\",\n", ")\n", "ax.fill_between(\n", " arm_fractions,\n", " 0,\n", " np.max(distances),\n", " where=~in_tension,\n", " color=\"red\",\n", " alpha=0.3,\n", " label=\"Sling Slack\",\n", ")\n", "ax.set_xlabel(\"Projectile Arm Length / Total Arm Length\")\n", "ax.set_ylabel(\"Distance Traveled (m)\")\n", "ax.legend()\n", "plt.show()" ] } ], "metadata": { "kernelspec": { "display_name": ".venv (3.13.9)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.9" } }, "nbformat": 4, "nbformat_minor": 5 }