diff --git a/GettingStarted-02-InteractiveVisualization.ipynb b/GettingStarted-02-InteractiveVisualization.ipynb index 85e4a01..9a22d49 100644 --- a/GettingStarted-02-InteractiveVisualization.ipynb +++ b/GettingStarted-02-InteractiveVisualization.ipynb @@ -1,488 +1,497 @@ { "cells": [ { "cell_type": "markdown", "id": "42235b78-7365-4921-8034-a7139a839952", "metadata": { "toc-hr-collapsed": true }, "source": [ "# Workshop \"Teaching Sciences and Engineering with Jupyter Notebooks\" 2022\n", "\n", "Notebook by Cécile Hardebolle, 2023
\n", "Except where otherwise noted, the content of this notebook is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
\n", "\"Creative \n", "\n", "
\n", " How to use this notebook?
\n", " This notebook is made of text cells and code cells. The code cells have to be executed to see the result of the program.
To execute a cell, simply select it and click on the \"play\" button () in the tool bar just above the notebook, or type shift + enter.
It is important to execute the code cells in their order of appearance in the notebook.\n", "
" ] }, { "cell_type": "markdown", "id": "a2774ae7-2192-4acc-9b04-39a894706ab5", "metadata": {}, "source": [ "# Tutorial: creating interactive visualizations with Matplotlib\n", "\n", "This very short tutorial walks you through the steps for creating an interactive visualization with matplotlib. \n", "Please note that there are *multiple ways* to achieve the same result. This tutorial is just one possible example.\n", "\n", "Our goal in this tutorial is to obtain the interactive figure below, that represents a house (ok, it's a bit silly 😅 but it's just an example). \n", "The two sliders change the height of the roof and the width of the door.\n", "\n", "" ] }, { "cell_type": "markdown", "id": "a7ecbc64-f2c7-4066-ab9c-eeabe7675d06", "metadata": {}, "source": [ - "## Technical setup" + "# Technical setup\n", + "\n", + "## Importing libraries" ] }, { "cell_type": "markdown", "id": "2ca6f8ff-3012-47f2-8f91-f0c05c4ec0a7", "metadata": {}, "source": [ "We need to import two libraries: \n", "* matplotlib for plotting\n", "* ipywidgets for interaction elements such as sliders" ] }, { "cell_type": "code", "execution_count": null, "id": "178a7a7c-86dd-4bad-80ee-70c250708b82", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import ipywidgets as widgets" ] }, { "cell_type": "markdown", - "id": "8322fb56-37f2-45b0-9c40-2ddfa29eb4b6", + "id": "593bf85a-c041-442b-be27-d152f5ab9f05", "metadata": {}, "source": [ + "## Choosing a \"backend\"\n", + "\n", "Before starting to construct a figure, we need to tell matplotlib what we want to generate:\n", "* static images: `%matplotlib inline`\n", - "* or dynamic interactive visuals: `%matplotlib widget`\n", + "* or a dynamic interactive visual: `%matplotlib widget`\n", "\n", - "This setting changes the type of `backend` that matplotlib will use. \n", - "With the static backend, matplotlib will generate a new image each time we make a modification. \n", - "With the interactive backend, only one image will be generated and all the actions and drawings will update the image - this is what we want to do in this tutorial." + "This setting changes the type of `backend` that matplotlib will use: \n", + "* with the static backend, matplotlib will generate a new image each time we make a modification \n", + "* with the interactive backend, only one image will be generated and all the actions and drawings will update the image - this is what we want to do in this tutorial." ] }, { "cell_type": "code", "execution_count": null, "id": "2f42895d-8a0a-41b9-aca7-118ed0c476cd", "metadata": {}, "outputs": [], "source": [ "# In this tutorial, we will create an interactive figure\n", "%matplotlib widget" ] }, { "cell_type": "markdown", "id": "c7a1a710-02f9-4ce0-b546-6422f2db7549", "metadata": {}, "source": [ "*Watchout: code written with one backend usually does not work with another backend!*" ] }, { "cell_type": "markdown", "id": "568a1cf2-9745-4396-8575-4d245dfa125a", "metadata": {}, "source": [ - "## Data to generate the visualization\n", - "Let's generate some data to plot. \n", + "# Data to generate the visualization\n", + "To generate a visualization, we need some some data to plot.\n", + "\n", "To simplify, we model the house by a rectangle and its roof by a triangle. \n", "These figures are drawn using lines defined by successive points represented by their x and y coordinates. \n", "\n", "For instance, to draw a rectangle, we plot a line defined by four points A, B, C and D, as in the figure below. \n", "\n", "\n", "\n", "To plot the line, we need to define two lists:\n", "* the x coordinates of these four points: [$x_A$, $x_B$, $x_C$, $x_D$]\n", "* the y coordinates of the same points: [$y_A$, $y_B$, $y_C$, $y_D$]" ] }, { "cell_type": "code", "execution_count": null, "id": "b2ec3458-425c-4d66-9f25-239471e2764b", "metadata": {}, "outputs": [], "source": [ "# We will plot a rectangle to model a house\n", "house_x = [2, 2, 4, 4]\n", "house_y = [0, 2, 2, 0]" ] }, { "cell_type": "markdown", "id": "fe94291e-3ff6-4d5d-baff-2e052c198a95", "metadata": {}, "source": [ "Then we do the same for the triangle that represents the roof." ] }, { "cell_type": "code", "execution_count": null, "id": "c22828f5-8b07-48de-bdc8-25b78bc89dcb", "metadata": {}, "outputs": [], "source": [ "# We will plot a triangle to model the roof\n", "roof_x = [2, 3, 4]\n", "roof_y = [2, 5, 2]" ] }, { "cell_type": "markdown", "id": "fea1da5d-f18d-48f4-8b4f-e24d3d1cb745", "metadata": {}, "source": [ - "## Building the visualization" + "# Building the visualization" ] }, { "cell_type": "markdown", "id": "b0530b84-7d3d-4e65-9960-e222f434686f", "metadata": {}, "source": [ + "## Turning off the output temporarily\n", "Before starting to build the figure, we first tell matplolib to wait until we tell him to show the figure where we want in the notebook. \n", "If we don't do that, it will start to display the figure right after the first instructions we write." ] }, { "cell_type": "code", "execution_count": null, "id": "9d65ead3-efc7-40f5-823a-306980328261", "metadata": {}, "outputs": [], "source": [ "# Turn the output off for the moment\n", "plt.ioff();" ] }, { "cell_type": "markdown", "id": "22c696c5-f1bb-48cc-b68a-286bea11396e", "metadata": {}, "source": [ + "## Creating the components of the figure\n", "Now let's build the plot. It has two main components:\n", "* a figure, which is an overall container (usually \"invisible\")\n", "* one or more \"axes\" i.e. plots" ] }, { "cell_type": "code", "execution_count": null, "id": "f99f07ce-f750-493e-bac0-76427ac83ffb", "metadata": {}, "outputs": [], "source": [ "# Creation of the figure\n", "fig = plt.figure(num='Interactive figure', figsize=(6,4))\n", "\n", "# Creation of one subplot/axe - it will take position index number 1 in a grid of 1 row and 1 column, as described by (nrows, ncols, index)\n", "ax = fig.add_subplot(1,1,1)" ] }, { "cell_type": "markdown", "id": "19d36c78-ecb3-4f17-8199-a48437331805", "metadata": {}, "source": [ + "## Plotting the data\n", "Once we have created these components, we can plot our data. \n", "The `plot` method of the `axe` object plots y versus x as lines and/or markers. It returns the resulting `line` object(s)." ] }, { "cell_type": "code", "execution_count": null, "id": "a061a2e0-1775-4752-8884-88bf00639903", "metadata": {}, "outputs": [], "source": [ "# First let's plot the \"house\" i.e. the rectangle\n", "ax.plot(house_x, house_y)\n", "\n", "# Then plot the roof/triangle, and get the resulting line, on which we will add interactivity later - NOTICE the syntax with the comma \"roof_line, =\"\n", "roof_line, = ax.plot(roof_x, roof_y)" ] }, { "cell_type": "markdown", "id": "69412705-47f2-40b3-9cd0-95422a0b6309", "metadata": {}, "source": [ + "## Finally showing the figure\n", "Now let's show the resulting figure! \n", "For that we need to turn on again the interactive mode of matplotlib." ] }, { "cell_type": "code", "execution_count": null, "id": "d940f221-813c-4f52-8fa3-766fd0fa9b2f", "metadata": {}, "outputs": [], "source": [ "# Turn the output on\n", "plt.ion()\n", "\n", "# Show the figure\n", "display(fig.canvas)" ] }, { "cell_type": "markdown", "id": "425f9a44-f36b-417b-a9de-35e855bd5487", "metadata": {}, "source": [ - "## Adding some interactivity \n", + "# Adding some interactivity \n", "Now we can add some interactivity to this plot. For that, we proceed in four steps:\n", - "1. We create a slider" + "1. We create a slider, i.e. a button that allows the user to choose a value in a defined range." ] }, { "cell_type": "code", "execution_count": null, "id": "eadae473-19a9-4f18-b453-4aec54012015", "metadata": {}, "outputs": [], "source": [ "# We create a slider with values ranging from 2 to 10 in steps of .5, by default it will be set on value 5\n", "roof_widget = widgets.FloatSlider(min=2, max=10, step=0.5, value=5, description='Roof height:')" ] }, { "cell_type": "markdown", "id": "37549dfa-026c-4ee2-9c45-5e55b06f84b8", "metadata": {}, "source": [ "2. We create a function that will be called when the slider is moved and will update the figure: \n", - " it will change the coordinates of the points in the line that represents the roof, using the value indicated by the slider" + " it will change the coordinates of the points in the line that represents the roof, using the value indicated by the slider." ] }, { "cell_type": "code", "execution_count": 2, "id": "93c29bff-d13f-477f-ab8d-9723856472b1", "metadata": {}, "outputs": [], "source": [ "# This function will be called when the slider is moved\n", "def roof_event_handler(change):\n", " # It allows us to retrieve the new value of the slider\n", " newposition = change.new\n", "\n", " # Then we can update the y coordinates of the points in the roof line - this is the important part of the function!!\n", " # Note: to change the height of the roof, we only change the y coordinate of the middle point (top of the triangle), the first and last points do not change\n", " roof_line.set_ydata([2, newposition, 2])\n", " \n", " # Finally we tell the figure to draw the changed parts\n", " fig.canvas.draw_idle()" ] }, { "cell_type": "markdown", "id": "bfc19f67-fd2a-4d99-a138-3e84c25a962b", "metadata": {}, "source": [ "3. We link the slider to the callback function" ] }, { "cell_type": "code", "execution_count": null, "id": "c7155220-f5f2-40f4-aad6-38d055441646", "metadata": {}, "outputs": [], "source": [ "# Finally we link the widget to the callback function \n", "roof_widget.observe(roof_event_handler, names='value')" ] }, { "cell_type": "markdown", "id": "3242d42a-706b-4040-bf08-a2d118829ab4", "metadata": {}, "source": [ "4. And then we display both the figure and the slider" ] }, { "cell_type": "code", "execution_count": null, "id": "9ebd1106-589f-46ad-b7cd-bfce1db0744a", "metadata": {}, "outputs": [], "source": [ "# Display the figure again, and the widget below (no need to turn the interactive mode on again since we did it earlier)\n", "display(fig.canvas, roof_widget)" ] }, { "cell_type": "markdown", "id": "03b9a626-ee0a-4bec-ba57-d2691252d881", "metadata": {}, "source": [ "Note that the slider udpates both the figure here and also the figure above. \n", "This is the work of the interactive backend!" ] }, { "cell_type": "markdown", "id": "e6c31f99-06b2-42a5-988f-a8e81951b6e2", "metadata": {}, "source": [ "---\n", "\n", "# Your turn now!" ] }, { "cell_type": "markdown", "id": "b4c41719-fe79-4c76-ba62-68e5fbb3edc1", "metadata": {}, "source": [ "
\n", " Activity
\n", "\n", "Add a line to the plot that draws a door to the house. \n", "Then create a slider that will let the user choose the width of the door. \n", " \n", "
" ] }, { "cell_type": "markdown", "id": "8a9f7b39-9bf7-48e4-aedf-a4583815794a", "metadata": {}, "source": [ "Here are the steps you need to follow:\n", "1. First define the x and y coordinates of the line that will represent the door\n", "1. Plot the line, retrieve the result\n", "1. Create a slider\n", "1. Create a function that will update the coordinates of the points of the door line depending on the value of the slider\n", "1. Link the slider to the function\n", "1. Display the figure and the sliders" ] }, { "cell_type": "code", "execution_count": 3, "id": "f0f60b17-d9cb-4b51-93b4-d472edf2cd2e", "metadata": {}, "outputs": [], "source": [ "# Your code here...\n" ] }, { "cell_type": "markdown", "id": "206b7ae1-02b9-44d0-9af9-4472df30adbe", "metadata": {}, "source": [ "
\n", "\n", "**Solution** - You can see *one possible solution* by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": null, "id": "15d0e85e-abc0-4ff1-af59-47eb4c19869b", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "outputs": [], "source": [ "# First define the x and y coordinates of the door\n", - "door_x = [2.25, 2.25, 2.50, 2.50]\n", + "door_x = [2.25, 2.25, 2.50, 2.50] # originally, the door has a width of 0.25, i.e. the points on the right side are at x_left + 0.25\n", "door_y = [0, 1, 1, 0]\n", "\n", "# Draw the door on the plot and get the resulting line (to be able to update it with the slider)\n", "door_line, = ax.plot(door_x, door_y)\n", "\n", - "# Create a widget for the width of the door\n", + "# Create a widget for the width of the door, which starts at 0.25 and can go up to 1.5 in steps of 0.05\n", "door_widget = widgets.FloatSlider(min=0.25, max=1.5, step=0.05, value=0.25, description='Door width:')\n", "\n", "# This function will be called when the door slider is moved\n", "def door_event_handler(change):\n", " # It allows us to retrieve the new value of the slider\n", " newwidth = change.new\n", "\n", - " # Then we can change the points of the door line\n", + " # Then we can change the points of the door line - in this case we only change the x coordinates of the points on the right side of the door\n", " door_line.set_xdata([2.25, 2.25, 2.25+newwidth, 2.25+newwidth])\n", " \n", " # Finally we tell the figure to draw the changed parts\n", " fig.canvas.draw_idle()\n", " \n", "\n", "# Finally we link the widget to the callback function \n", "door_widget.observe(door_event_handler, names='value')\n", "\n", "# Let's display again the whole figure with the two sliders\n", "display(fig.canvas, roof_widget, door_widget)" ] }, { "cell_type": "markdown", "id": "9690331e-446d-4062-97d0-069276e335bf", "metadata": {}, "source": [ "---\n", "\n", "# Additional resources\n", "\n", "More on figures and axes of Matplotlib: \n", "https://medium.com/@kapil.mathur1987/matplotlib-an-introduction-to-its-object-oriented-interface-a318b1530aed\n", "\n", "Using the widgets to add interactivity: \n", "https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20Events.html\n", "\n", "Details about the backends of matplotlib: \n", "https://matplotlib.org/3.4.3/users/interactive.html" ] } ], "metadata": { "kernelspec": { "display_name": "Python", "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.8.10" } }, "nbformat": 4, "nbformat_minor": 5 } diff --git a/LearningPhysics.ipynb b/LearningPhysics.ipynb index 9a2936f..c8b1f43 100644 --- a/LearningPhysics.ipynb +++ b/LearningPhysics.ipynb @@ -1,1411 +1,1405 @@ { "cells": [ { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": true }, "source": [ "# Workshop \"Teaching Sciences and Engineering with Jupyter Notebooks\" 2023-2024" ] }, { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": true }, "source": [ "
\n", " How to use this notebook?
\n", "
Simply read the text and follow the instructions.
\n", " This notebook contains some code cells, which have to be executed to see the result of the program.
\n", " To execute a cell, select it and click on the \"play\" button () in the tool bar just above the notebook, or type shift + enter.
It is important to execute the code cells in their order of appearance in the notebook.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notebook by Cécile Hardebolle (2023).
\n", "Problem adapted and translated with permission from Marc Legrand. Source: [1] [Legrand, M. (1993), Débat scientifique en cours de mathématiques et spécificité de l’analyse. Repères-IREM, 10, 123–159](https://publimath.univ-irem.fr/biblio/IWR97066.htm).
\n", "Except where otherwise noted, the content of this notebook is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0 International).
\n", "\"Creative" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "tags": [], "toc-hr-collapsed": true }, "source": [ "# The physics of suspended objects\n", "\n", "In this notebook, you will learn about the physical principles that apply when suspending objects (forces in static equilibrium) and you will apply them to a concrete problem using Python. " ] }, { "cell_type": "markdown", "metadata": { "tags": [], "toc-hr-collapsed": true }, "source": [ "## Learning goals\n", "\n", "After using this notebook, you should be able to:\n", "* Identify the forces involved when suspending an object with a cable\n", "* Analyze how the position of the cable influences the tension force\n", - "* Use Python to make mathematical calculations and write simple functions" + "* Use Python to make mathematical calculations and write simple functions\n" ] }, { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": false }, "source": [ "
\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "# Problem: suspended jeans\n", "\n", + "## The question\n", "The question we want to answer in this notebook is the following (source: [[1]](#ref1)): \n", "**Which counterweight allows to suspend wet jeans (3kg) on the cable in the position illustrated below?**\n", "\n", "\"suspended\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "
\n", + "\n", "\n", - "The activities below will guide you to find out the answer to this question by exploring how the counterweight affects the position of the jeans suspended on the cable. " + "
" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## What does your intuition say?\n", "\n", "Before diving into the problem, it is interesting to figure out if you have an intuition about the answer. \n", "Research on problem solving has shown that knowing the extent and limits of your intuition plays a role in problem solving expertise. \n", "Therefore your first activity in this notebook is to try to **guess the correct answer** without solving the problem." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " Activity
\n", "\n", "**Execute the code cell below to display the poll**, then **vote for the answer you think is correct**. \n", "This poll is completely anonymous, you will not see the answers of the others (and you will not see if your answer is correct or not either). \n", "The goal here is only for you to **commit to an answer**.\n", "\n", "*You will need to accept the privacy policy to be able to vote.*\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import IFrame\n", "IFrame('https://speakup.epfl.ch/poll/14804/fb73c759-0f0c-4138-986f-ce8c13958964?theme=EPFL&lang=en', 400, 500)" ] }, { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": false }, "source": [ "
\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "# 1. Analyzing the problem\n", "\n", "Now lets' dive into the problem! \n", "Our first step should be to analyze the question into more details and this includes:\n", "* Identifying assumptions we can make to simplify the problem\n", "* Making a sketch and identifying the parameters of the problem, in particular the forces involved\n" ] }, { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": false }, "source": [ "## First, let's simplify\n", "We can make the assumption that the jeans do not move on the cable, i.e. the whole system is in **static equilibrium**. \n", "In that case, it is like the cable is attached to fixed points on both sides, we can have a look at the pulley later. \n", "Let's make a sketch.\n", "\n", "\"sketch\"\n", "

Figure 1: Simplified suspended jeans situation

\n", "\n", "\n", "In addition, we can also suppose that the jeans are positioned exactly mid-way between the poles. \n", "In this case, it's like the jeans are suspended with **two identical cables on both sides**.
" ] }, { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": false }, "source": [ "## What are the forces involved?\n", "The forces applied to the jeans are then:\n", "* The **weight** $\\vec{F}$ ;\n", - "* Two **tension forces** $\\vec{T}$ on both sides, which are identical in norm if we assume that the jeans are suspended right in the middle of the cable. \n", - " These two tensions add up (vector sum) to form a **resulting vertical tension** $\\vec{T}_r$.\n", + "* Two **tension forces** $\\vec{T}$, one for each of the cables on both sides of the jeans.\n", + " These two tensions are identical in norm if we assume that the jeans are suspended right in the middle of the cable. \n", + " Each force follows the direction of the corresponding cable, which makes an angle $\\alpha$ with the horizon (the same angle on both sides if we assume the jeans are in the middle of the cable). \n", + " They add up (vector sum) to form a **resulting vertical tension** $\\vec{T}_r$. \n", "\n", "Let's add the forces to our sketch.\n", "\n", "\"sketch\"\n", "

Figure 2: Forces and angle in the suspended jeans situation

\n", "\n", "
\n", "\n", "Now from there, how do we get to the counterweight? \n", "The tension force is transmitted to the jeans by the cable, which is connected to the counterweight through the pulley. While we will have a closer look at the pulley later, for now we can still hypothesize that **the heavier the counterweight, the higher the tension in the cable** and vice versa. \n", "\n", "Now since the tension force follows the direction of the cable, it likely **depends on the angle $\\alpha$ that the cable makes with the horizon**. \n", "🡆 Let's explore the influence of the angle $\\alpha$ on $\\lvert\\vec{T}\\rvert$." ] }, { "cell_type": "markdown", "metadata": { "tags": [], "toc-hr-collapsed": false }, "source": [ "## How does the angle $\\alpha$ influence the tension force?\n", "\n", "\n", "In the following, we are going to use the `suspendedobjects` library to visualize concretely how the angle $\\alpha$ influences the tension force. \n", "For this, we need to import some useful Python libraries. \n", "\n", "
\n", " Activity
\n", "\n", "**Execute the code cell below** so that the necessary libraries get imported.\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# We need Numpy for some mathematical functions (e.g. sinus)\n", "import numpy as np\n", "\n", "# We will do some plotting with Bokeh\n", "from bokeh.plotting import figure\n", "\n", "# We will use a custom library with visualizations developed for this exercise\n", "from lib.suspendedobject import *\n", "\n", "# And display a message once all libraries are imported\n", "print(\"Libraries imported.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can start to use Python for visualizing the influence of our angle $\\alpha$. \n", "The `suspendedobjects` library generates a situation with poles 1.5 meters high, separated by a 5 meter distance, and shows the angle $\\alpha$ as well as the forces on the jeans." ] }, { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": false }, "source": [ "
\n", " Activity
\n", " \n", "Execute the code cell below to launch the interactive visualization with the jeans suspended on the cable.
\n", "Then use the slider at the bottom to vary the value of $\\alpha$ and **compare the tension $\\vec{T}$ in the cable** with $\\alpha$ = 20$^\\circ$ and with $\\alpha$ = 5$^\\circ$. \n", "**What do you observe?** \n", "\n", "You can check your answer against the solution below the visualization.\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Build a concrete situation where poles measure 1.5 meters and are distant from 5 meters\n", "lab = SuspendedObjectLab(m_object = 3, height = 1.5, distance = 5)\n", "\n", "# Launch the interactive visualization\n", "lab.launch();" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "\n", "We can observe that, while the weight and the resulting vertical tension don't change, the tension $\\vec{T}$ (red arrows) is much bigger when $\\alpha$ = 5$^\\circ$ than when $\\alpha$ = 20$^\\circ$. \n", "The smaller the angle, the higher the tension in the cable.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2. Computing the tension in the cable with Python\n", "\n", "To get a more precise view of what is happening, we will now compute the value of the tension in the cable using its equation. \n", "NB: it can be obtained using Newton's First Law of Motion, we will not go into more details here but you can [find the derivations in this slide deck](figs/Physics-slides.pdf) \n", "\n", "$\n", "\\begin{align}\n", "\\lvert\\vec{T}\\rvert = \\frac{\\frac{1}{2}.m.g}{sin(\\alpha)}\n", "\\end{align}\n", "$\n", "\n", "In the following we are going to use Python to **compute the tension in the cable** for **different values of the angle $\\alpha$**." ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## Defining the constants of our physics problem\n", "\n", "In the above equation we have two constants:\n", "- $g$ the gravity of earth, which is 9.81m.s$^{-2}$\n", "- $m$ the mass of the suspended object, which is 3 kg in the case of the jeans\n", "\n", "
\n", " Activity
\n", "\n", "**Execute the code cell below** so that these two constants get defined in Python.\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Let's define the value of gravity\n", "g = 9.81\n", "\n", "# And the mass of the jeans\n", "m = 3\n", "\n", "# Display the value of the constants to check they are well defined\n", "print(\"gravity:\", g, \", jeans mass:\", m)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"lightbulb\"\n", "Why bother defining these constants instead of using numerical values directly in our computations? Giving names to numerical values is actually a good programming practice: in the case you need to change one of these values at some point, you can do it in one place only, instead of replacing the values everywhere in your code." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating a function to compute the tension in the cable\n", "\n", "Let's define a Python function that represents the equation of the tension. \n", "Its input parameters are:\n", "* `g`: the gravity of earth\n", "* `m`: the mass of the jeans\n", - "* `alpha`:the angle that the cable makes with the horizon\n", + "* `alpha`: the angle that the cable makes with the horizon\n", "\n", "It returns the value of the mass of the counterweight as computed with the equation $\n", "\\begin{align}\n", "\\frac{\\frac{1}{2}.m.g}{sin(\\alpha)}\n", "\\end{align}\n", "$\n", "\n", "
\n", " Activity
\n", "\n", "In the code cell below, **complete the code of the function `tension_norm`** by implementing the equation above. \n", "Here is some syntax you will need:\n", "* variables: you can use `g`, `m` and `alpha`\n", "* multiplication: `*`\n", "* division: `/`\n", "* sinus function $sin(x)$: `np.sin(x)`\n", "\n", "You can also use parentheses to indicate the order of operations.\n", " \n", "Then **execute the code cell** so that this function gets defined in Python.\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Then let's define the function\n", "def tension_norm(g, m, alpha):\n", " tension = 1 # REPLACE \"1\" BY YOUR EQUATION HERE\n", " return tension\n", "\n", "# And display a message once it is defined\n", "print(\"Function defined.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "Your function should look like the following:\n", "\n", "def tension_norm(g, m, alpha):\n", " tension = (1/2 * m * g) / np.sin(alpha)\n", " return tension\n", "\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"lightbulb\"\n", "Why bother defining a function instead of doing the computation directly? This is actually a good programming practice: by defining a function that computes the norm of the tension like this, we can reuse it several times in the notebook instead of copy-pasting the same computation several times. Functions make code reusable. In addition, if we make a mistake or need to do a modification, we can do it in one place only, instead of having to find all the places where we have written the same piece of code.

" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "## Computing the tension in the cable using our function\n", "\n", "Now let's use this Python function to compute the norm of the tension in the cable for a given angle of $\\alpha$.\n", "\n", "Because our function takes the sinus of our angle $\\alpha$, we first need to convert it from degrees into radians. \n", "This is where the library we have imported gets useful as it provides us with a function `degrees_to_radians` which we can use to convert our angle.\n", "\n", "The code cell below defines a value for $\\alpha$ in degrees, converts it to radians, then computes the tension on the cable using our previously defined function with `g` = 9.81 m.s$^{-2}$ and `m` = 3 kg and prints the result." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# First choose an angle alpha in degrees\n", "alpha = 2\n", "\n", "# Then convert it to radians\n", "alpha_radians = degrees_to_radians(alpha)\n", "\n", "# Then compute the tension using our equation with the values we have defined for g, m and alpha (in radians)\n", "T = tension_norm(g, m, alpha_radians)\n", "\n", "# And print the result\n", "print(\"Norm of the tension in the cable: T =\", T, \"N\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " Activity
\n", "\n", "**Execute the code cell** to see the value of the tension force $\\lvert\\vec{T}\\rvert$ corresponding to an angle $\\alpha$ of 2$^\\circ$, expressed in Newtons. \n", " \n", "**Compare the value you obtain** to the force exerted by earth gravity on the jeans, which weight 3 kg: $\\lvert\\vec{F}\\rvert = $ 29 $N$ \n", "Is the tension in the cable bigger or smaller than the weight of the jeans on the cable? Why? \n", "Note down your answer in the cell below, then you can check the solution by clicking on the \"...\" below.\n", "\n", "*NB: you can also change the value of $\\alpha$ in the code cell above and then execute the cell again to see the corresponding value for the tension force.*\n", " \n", "
" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Just note down your answer here (this cell is for note taking):\n", "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "For an angle $\\alpha$ of 2$^\\circ$, you can observe that the tension $\\lvert\\vec{T}\\rvert$ is more than 10 times bigger than the weight of the jeans (T = 421.63931833852183 N).\n", " \n", "This is because such small angles make the cable more horizontal whereas the weight of the jeans is purely vertical, therefore a higher tension will be necessary to create the vertical resulting force that compensates for the weight of the jeans.\n", " \n", "\"sketch\"\n", "\n", "Mathematically speaking, remember that the tension is defined by the following equation: \n", "$\n", "\\begin{align}\n", "\\lvert\\vec{T}\\rvert = \\frac{\\frac{1}{2}.m.g}{sin(\\alpha)}\n", "\\end{align}\n", "$\n", "\n", "Because the weight of the jeans is $\\lvert\\vec{F}\\rvert = m.g$, the tension can also be written: \n", "$\n", "\\begin{align}\n", "\\lvert\\vec{T}\\rvert = \\frac{\\frac{1}{2}}{sin(\\alpha)}.\\lvert\\vec{F}\\rvert\n", "\\end{align}\n", "$\n", "\n", "As a consequence:\n", "* For angles between 0$^\\circ$ and 30$^\\circ$, $sin(\\alpha)$ will be between 0 and $\\frac{1}{2}$ and therefore we will have $\\lvert\\vec{T}\\rvert > \\lvert\\vec{F}\\rvert$\n", "* For angles between 30$^\\circ$ and 90$^\\circ$ (although such high values do not really make sense in the real situation), $sin(\\alpha)$ will be between $\\frac{1}{2}$ and 1 and therefore we will have $\\lvert\\vec{T}\\rvert < \\lvert\\vec{F}\\rvert$\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. From the tension to the counterweight\n", "\n", "Now how can we relate this tension to the counterweight in our original question? \n", "A key here is to understand that **the tension is transmitted in the cable to the counterweight**, and that **the pulley only changes the direction of the force**, it does not affect its value.\n", "\n", "Therefore the weight $\\vec{F_{cw}}$ of the counterweight will have to compensate exactly the tension $\\vec{T}$ in the cable, as indicated on the sketch below.\n", "\n", "\"sketch\"\n", "

Figure 3: Forces on the counterweight

\n", "\n", "Using again Newton's First Law of Motion ([derivations in this slide deck](figs/Physics-slides.pdf)), we can find the mass of the counterweight: \n", "$\n", "\\begin{align}\n", "m_{cw} = \\frac{\\lvert\\vec{T}\\rvert}{g}\n", "\\end{align}\n", "$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using Python for the computation\n", "\n", "Again we can use python to make this simple computation, using the values `T` and `g` computed earlier." ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "
\n", " Activity
\n", "\n", "**Complete the code cell below** to compute the mass of the counterweight according to the equation above. \n", "You can use the variables `T` and `g` that we have defined earlier. \n", "Then **execute the code cell** to see which counterweight would allow the jeans to be suspended with the angle $\\alpha$ chosen earlier.\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Let's compute the mass of the counterweight to compensate for the tension in the cable\n", "m_cw = 1 # REPLACE \"1\" WITH YOUR EQUATION HERE\n", "\n", "# And print the result\n", "print(\"Mass of the counterweight: m_cw =\", m_cw, \"kg\")" ] }, { "cell_type": "markdown", "metadata": { "tags": [] }, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "Your code could look like the following:\n", "\n", "m_cw = T / g\n", " \n", "Of course, if you are at ease with Python you can write this as a function, which could also call the ``tension_norm`` function defined earlier instead of using ``T``, which would be a better programming design...\n", "\n", "For an angle of $\\alpha$ = 2$^\\circ$, you should find a mass ``m_cw`` = 42.98056252176573 kg. \n", "Note: If you changed the value of $\\alpha$ in the previous cell, then you will find a different mass for the counterweight.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Back to the original question\n", "\n", "Let's come back to our original question: \"which counterweight do you think would allow to suspend the jeans (3kg) on the cable in the position illustrated below?\" \n", "**How does the result you obtained just above compare to your guess at the beginning of this notebook?** \n", "\n", "\"suspended\n", "\n", "
\n", " Activity
\n", "\n", "This is an opportunity to **look back at your intuition**: Was it correct or not? Why? \n", "Note down your thoughts in the cell below. \n", "\n", "
\n" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Just note down your answer here (this cell is for note taking):\n", "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4. What have you learned so far?\n", "\n", "You have now spent some time doing a number of activities. \n", "However, research shows that it is very hard to learn from **doing** things, and that we actually learn from **reflecting** on what we have done. \n", "This is why the last two activities in this notebook are designed to help you identify what you have learned from doing all of this and where it could apply.\n", "\n", "
\n", " Activity
\n", "\n", "Write down **2 things you learned** from this notebook - for instance about the tension force (or about how to design a notebook 😉). \n", "
" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Just note down your answer here (this cell is for note taking):\n", "- \n", "- \n", "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " Activity
\n", "\n", "Can you identify other real-life situations in which cables are used to suspend objects or in which cables are taut between poles? \n", "\n", "**Execute the code cell below to display the chat**, then **post messages with your ideas** (one message per idea). \n", "You can vote for the ideas of the others that you find interesting. \n", "This chat room is completely anonymous. \n", "\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import IFrame\n", "IFrame('https://speakup.epfl.ch/room/45263?theme=EPFL&lang=en', 400, 500)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "\n", "That's it, you're done! \n", "Unless you want to keep exploring and take a look at the additional exercises below 😉" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "---\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Additional exercises (optional)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Looking at how the tension in the cable evolves with the angle $\\alpha$\n", "\n", "Now we want to look at **how the tension evolves** when the angle $\\alpha$ changes. \n", "Thanks to our previously defined Python function, we are going to compute the tension in the cable for 100 different values of $\\alpha$, from 30$^\\circ$ to 0$^\\circ$, and plot the result on a graph. \n", "\n", "
\n", " Activity
\n", "\n", "**Execute the code cell below** to see the resulting graph.\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Let's define the boundaries of the graph\n", "a_start = 30 # start the angle at 30°\n", "a_stop = 0 # stop at O° (excluded)\n", "\n", "# Now we generate 100 possible values for the angle alpha between a_start and a_stop (excluded)\n", "a_deg = np.linspace(start=a_start, stop=a_stop, num=100, endpoint = False)\n", "print(\"The 100 different values for the angle alpha:\\n\", a_deg, \"\\n\")\n", "\n", "# Since our previously defined function works with angles expressed in radians, we first convert our list of angles from degrees to radians\n", "a_rad = degrees_to_radians(a_deg)\n", "\n", "# Then we compute the value of the tension for all the 100 possible angles alpha using our previously defined function\n", "t = tension_norm(g, m, a_rad)\n", "print(\"The corresponding values for the tension in the cable:\\n\", t)\n", "\n", "# Finally we generate the plot and customize its appearance\n", "fig = figure(title='Tension in the cable', x_axis_label = 'Angle ⍺ (°)', y_axis_label = 'Tension T (N)', x_range=(a_deg[0],0), width=500, height=400, toolbar_location=None)\n", "fig.line(a_deg, t, color=\"red\", line_width=2)\n", "show(fig)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " Activity
\n", "\n", "What happens to the tension when the angle $\\alpha$ gets closer to 0$^\\circ$? \n", "Could we ever have $\\alpha$ = 0$^\\circ$, i.e. **could we ever pull the cable taught completely horizontally**?\n", " \n", "Note down your answer in the cell below, then you can check the solution by clicking on the \"...\" below.\n", "
\n" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Just note down your answer here (this cell is for note taking)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "The curve on the graph indicates that the tension in the cable is getting infinitely big as the angle $\\alpha$ gets closer to 0$^\\circ$. \n", "This means that we will never be able to pull the cable taught horizontally as this would mean an infinite tension (the cable would break before that).\n", "\n", " \n", "From a mathematical point of view, remember that the tension is defined by the following equation: \n", "$\n", "\\begin{align}\n", "\\lvert\\vec{T}\\rvert = \\frac{\\frac{1}{2}.m.g}{sin(\\alpha)}\n", "\\end{align}\n", "$\n", "\n", "When $\\alpha$ tends toward 0, $sin(\\alpha)$ also tends toward 0, therefore the limit of the expression defining the tension in the cable is:\n", "\n", "$\n", "\\begin{align}\n", "\\lim_{\\alpha\\to0}\\; \\lvert\\vec{T}\\rvert = \\lim_{\\alpha\\to0}\\;\\frac{\\frac{1}{2}.m.g}{sin(\\alpha)} = +\\infty\n", "\\end{align}\n", "$\n", "\n", "You can find out the detailed answer to this question below, in the [solution section of the notebook](#Solution:-Is-it-possible-to-pull-the-cable-taut-completely-horizontally?).\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How does our Python function behave with $\\alpha$ = 0?\n", "\n", "What happens with our piece of Python code when we say that the cable it taut completely horizontal, i.e. the angle $\\alpha$ = 0$^\\circ$, which is actually impossible in real life? \n", "\n", "
\n", " Activity
\n", "\n", "In the cell below, call your ``tension_norm`` function with a value of $0$ for `alpha` and execute the cell. \n", "What happens? \n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Compute the tension with alpha = 0°\n", "T = 1 # REPLACE 1 WITH THE CALL TO YOUR FUNCTION tension_norm HERE\n", "\n", "# And print the result\n", "print(\"Norm of the tension in the cable: T =\", T, \"N\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "Here is how to call your function:\n", "T = tension_norm(g, m, 0)\n", " \n", "When you execute this code, two things happen:\n", "* You get a warning message which says `RuntimeWarning: divide by zero encountered in double_scalars`\n", "* The function nonetheless returns a value which is `inf`\n", "\n", "When the angle $\\alpha$ = 0 then $sin(\\alpha)$ = 0 and therefore we divide `(.5 * jeans_mass * gravity)` by 0 so on one hand, mathematically speaking, we know that the result should be $+\\infty$. On the other hand, we also know that usually division by 0 is not well supported by computers.\n", "\n", "Actually, division by 0 is not supported in standard Python. \n", "You can create a code cell (click on the `+` icon in the toolbar above) and try to execute the following computation to see what happens: ``(0.5 * 3 * 9.81)/0``\n", " \n", "Now, because in the calculation we use the function `np.sin()` from the Numpy library, our data is automatically converted to Numpy types, which support division by zero and return the \"real\" result which is $+\\infty$. \n", "By convention, Numpy also generates a warning message but this can be deactivated when not necessary. \n", "If you are curious, you can take a look at [the errors generated by Numpy for floating-point calculations](https://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html#numpy.seterr).\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What are the consequences?\n", "\n", "It is important to know that high tension in a cable is very dangerous and can lead to serious accidents, especially when the cable is not well adapted for its intended use (i.e. not strong enough) or when the cable is progressively deteriorating with use. \n", "\n", "
\n", " Activity
\n", "\n", "Execute the cell below to see the video and watch the first minute (sound is not necessary). \n", "What happens at time 0:53? Why?\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import YouTubeVideo\n", "YouTubeVideo('KIbd5zBek5s', 600, 337, start=45, mute=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "At time 0:53, the cable desintegrates completely. This is probably because it has grown weaker and weaker after repeated use until it cannot withstand the high tension anymore.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Improving the `tension_norm` function\n", "\n", "As you have noticed, each time you want to call your `tension_norm` function with an angle expressed in degrees, you have first to convert your angle from degrees to radians. \n", "A better design would be to do the conversion of the angle inside the function so that you can pass it angles in degrees directly.\n", "\n", "
\n", " Activity
\n", "\n", "Define a new function `tension_norm_degrees` which converts `alpha` from degrees to radians using the `degrees_to_radians` function, then calls the `tension_norm` function to compute the norm of the tension and returns the result. \n", " \n", "Then **execute the code cell** so that this function gets defined and then tested with an angle $\\alpha$ of 20$^\\circ$. \n", "If your function works correctly, the result of the execution should be `Tension norm: T = 43.023781748399834 N`.
\n", "You can further check your answer with the solution by clicking on the \"...\" below. \n", "\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Define your function\n", "def tension_norm_degrees(g, m, alpha):\n", " # WRITE YOUR CODE HERE\n", " return\n", "\n", "# Let's test it: the execution of these lines should give T = 43.023781748399834 N\n", "alpha = 20\n", "T = tension_norm_degrees(g, m, alpha) \n", "print(\"Tension norm: T =\", T, \"N\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Solution** - you can check your answer with the solution by clicking on the \"...\" below.\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": { "jupyter": { "source_hidden": true }, "tags": [] }, "source": [ "
\n", " Solution
\n", "\n", "Your function could look like the following:\n", "\n", "def tension_norm_degrees(g, m, alpha):\n", " apha_rad = degrees_to_radians(alpha)\n", " tension = tension_norm(g, m, apha_rad)\n", " return tension\n", "\n", "\n", "Of course the three lines in this function can be combined into just one: \n", "\n", "def tension_norm_degrees(g, m, alpha):\n", " return tension_norm(g, m, degrees_to_radians(alpha))\n", "\n", " \n", "
Note: Another way to test such a function would be to use [Python assertions](https://zetcode.com/python/assert/). \n", "
However, comparing float values can get tricky. These can be made simpler by the use of more elaborate libraries such as ``pytest``, which support [approximations](https://randycoulman.com/blog/2018/06/19/comparing-floats-in-tests/).\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A function that computes the mass of the counterweight\n", "\n", "From the exercises above, we have learned that \n", "$\n", "\\begin{align}\n", "\\lvert\\vec{T}\\rvert = \\frac{\\frac{1}{2}.m.g}{sin(\\alpha)}\n", "\\end{align}\n", "$ and that\n", "$\n", "\\begin{align}\n", "m_{cw} = \\frac{\\lvert\\vec{T}\\rvert}{g}\n", "\\end{align}\n", "$\n", "\n", "From there, we can write the equation for the mass of the counterweight as a function of $\\alpha$:\n", "\n", "$\n", "\\begin{align}\n", "m_{cw} = \\frac{\\frac{1}{2}.m}{sin(\\alpha)}\n", "\\end{align}\n", "$\n", "\n", "
\n", " Activity
\n", "\n", "In the code cell below, write a function `counterweight_mass` that takes `m` and `alpha` as an inputs and returns the mass of the counterweight as computed by the equation above. \n", "Of course you can reuse code from the previous activities as a model. \n", " \n", "Then use this function to compute the counterweight necessary so that the cable makes an angle of 1.5$^\\circ$ with the horizon. \n", "You should find a counterweight of approximately 57 kg.\n", "\n", "You can find the complete solution in the [detailed solution section below](#Numerical-application).\n", "\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Write your code here\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "



\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": { "tags": [], "toc-nb-collapsed": true }, "source": [ "# General solution\n", "\n", "In this section we demonstrate the physical and mathematical reasoning to solve the problem. \n", "## Method\n", "\n", "To answer the question, we need to look for an expression defining the **mass of the counterweight $m_{cw}$**.\n", "\n", "Given that the system is in static equilibrium, the sum of external forces exerted on the system will be zero, so using Newton's First Law of Motion should be easy. The force that the counterweight exerts on the system will involve the mass of the counterweight so we should be able to rewrite Newton's second law to get an expression of the form $m_{cw} = ...$.\n", "\n", "## Hypotheses and simplifications\n", "\n", "We make the following assumptions and simplifications:\n", "* the jeans are considered as positioned exactly mid-way between the poles so the tension is equal on both sides of the cable\n", "* we represent the jeans by the point at which they are suspended\n", "* the cable is considered as rigid (not bended), with a negligible mass\n", "* the pulley is considered as perfect, without mass nor friction\n", "* we consider the static equilibrium obtained after changing the weight, once the system is stabilized\n", "\n", "## Resolution\n", "\n", "First, let's draw a diagram and represent the different forces involved.\n", "\n", "\n", "The *forces applied on the jeans* are:\n", "* the weight: $\\vec F_j = m_j \\vec g$ \n", "* the force exerted by the cable on each side of the jeans: assuming the jeans are suspended at the exact center of the cable, then the tension applied on each of the two sides is equally distributed with two tensions of equal magnitude $T$ on each side but with opposite directions on the $x$ axis, which combine into a vertical resulting tension $\\vec T_r$\n", "\n", "From Newton's second law in a static equilibrium we can write: $\\sum \\vec F_j = \\vec 0$ \n", "With the forces on the jeans we get: $\\vec F_j + \\vec T_r = 0$ \n", "\n", "If we project on $x$ and $y$ axes, we get: \n", "$\\left\\{\\begin{matrix} F_{jx} + T_{rx} = 0 \\\\ F_{jy} + T_{ry} = 0\\end{matrix}\\right. $\n", "\n", "Since $\\vec T_r$ is the result of two tensions of same magnitude $T$ on both sides of the jeans but of opposite directions on the $x$ axis, we can decompose $T_{rx}$ and $T_{ry}$ into the $x$ and $y$ components of $T$: \n", "$\\left\\{\\begin{matrix} T_{rx} = T_{x} - T_{x} \\\\ T_{ry} = 2.T_{y} \\end{matrix}\\right. $\n", "\n", "\n", "Now we can use this in our previous equations, which gives: \n", "$\\left\\{\\begin{matrix} F_{jx} + T_{x} - T_{x} = 0 \\\\ F_{jy} + 2.T_{y} = 0\\end{matrix}\\right. $\n", "\n", "\n", "Since the two $T_{x}$ cancel out we cannot know their value yet and so we focus on the second equation: \n", "$\\begin{align} F_{jy} + 2.T_y = 0 \\end{align}$\n", "\n", "The component of the weight on the y axis is $F_{jy} = - m_j.g$, which gives us: \n", "$\\begin{align} - m_j.g + 2.T_y = 0 \\end{align}$\n", "\n", "Using the angle $\\alpha$ we can get the tension $T_y$ expressed as a function of T since $sin(\\alpha) = \\frac{T_y}{T}$, therefore $T_y = T.sin(\\alpha)$\n", "\n", "By replacing $T_y$ by this expression in the above equation we get: \n", "$\\begin{align} - m_j.g + 2.T.sin(\\alpha) = 0 \\end{align}$\n", "\n", "From there we can get $T$, and this is equation number $(1)$: \n", "\n", "$\n", "\\begin{align}\n", "T = \\frac{m_j.g}{2.sin(\\alpha)}\n", "\\end{align}\n", "$\n", "\n", " \n", "\n", "We now want to make the mass of the counterweight appear in this expression. \n", "So we will now look at the forces applied on the *counterweight*.\n", "\n", " \n", "\n", "The forces applied on the *counterweight* are:\n", "* the weight: $\\vec F_{cw} = m_{cw} \\vec g$ \n", "* the force exerted by the cable: a simple pulley simply changes the direction of the tension so the tension applied on the counterweight is therefore of the same magnitude $T$ as before but with a different direction - we will note it $\\vec T$\n", "\n", "From Newton's second law in a static equilibrium we can write: $\\sum \\vec F_{cw} = \\vec 0$ \n", "With the forces involved in our problem : $\\vec F_{cw} + \\vec T = \\vec 0$ \n", "\n", "All forces being vertical, there is no need to project on $x$ so we get: $- F_{cw} + T = 0$ \n", "We replace the weight by its detailed expression: $-m_{cw}.g + T = 0$ \n", "Now we can express $T$ as a function of the other parameters, which is equation number $(2)$: $T = m_{cw}.g$ \n", "\n", " \n", "\n", "Let's now summarize what we have so far with equations $(1)$ and $(2)$: \n", "\n", "$\n", "\\begin{align}\n", "\\left\\{\\begin{matrix}T = \\frac{m_j.g}{2.sin(\\alpha)} \\\\ T = m_{cw}.g\\end{matrix}\\right. \n", "\\end{align}\n", "$\n", "\n", "These two equations combined give us:\n", "\n", "$\n", "\\begin{align}\n", "\\frac{m_j.g}{2.sin(\\alpha)} = m_{cw}.g\n", "\\end{align}\n", "$\n", "\n", "This allow us to find the mass of the counterweight as a function of the *mass of the jeans* and of the *angle that the cable makes with the horizon*: \n", "\n", "
\n", "\n", "$$m_{cw} = \\frac{m_j}{2.sin(\\alpha)}$$\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Numerical application\n", "\n", "Let's define a Python function that represents the above equation. \n", "The function takes two input parameters, `mj` which represents the mass of our jeans and `alpha`, the angle that the cable makes with the horizon. \n", "It returns the mass of the counterweight as computed with the equation above." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Define the function\n", "def counterweight_mass(mj, alpha):\n", " return mj / (2 * np.sin(alpha))\n", "\n", "# And display a message once it is defined\n", "print(\"Function defined.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For an angle $\\alpha$ of $1.5^\\circ$, we need to put a counterweight of:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Define the mass of the jeans\n", "mj = 3\n", "\n", "# Choose a value for angle alpha\n", "alpha = 1.5\n", "\n", "# Then convert it to radians\n", "alpha_radians = degrees_to_radians(alpha)\n", "\n", "# Compute the mass of the counterweight using our function\n", - "m_cw = counterweight_mass(m, alpha_radians)\n", + "m_cw = counterweight_mass(mj, alpha_radians)\n", "\n", "# And print the result\n", "print(\"Mass of the counterweight: m_cw =\", m_cw, \"kg\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Is it possible to pull the cable taught?\n", "\n", "When the cable approaches the horizon, $\\alpha$ is really small i.e. really close to zero. \n", "This means that $sin(\\alpha)$ is also close to zero, which means in turn that $m_{cw}$ is very big.\n", "Therefore, **the more we want the cable to be close to the horizon, the bigger $m_{cw}$ we will need!**\n", "\n", "Mathematically speaking, the limit of the expression defining the mass of the counterweight when alpha tends to 0 is:\n", "\n", "$\n", "\\begin{align}\n", "\\lim_{\\alpha\\to0}m_{cw} = \\lim_{\\alpha\\to0}\\frac{m_j}{2.sin(\\alpha)} = +\\infty\n", "\\end{align}\n", "$\n", "\n", "So basically, we would need to put an **infinitely heavy counterweight** to make the angle null and that is why it is impossible to get the cable taut so that it is absolutely straight (the cable would break before that!)..." ] } ], "metadata": { "kernelspec": { "display_name": "Python", "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.8.10" }, "toc-autonumbering": false, "toc-showcode": false, "toc-showmarkdowntxt": false }, "nbformat": 4, "nbformat_minor": 4 }