"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"from IPython.display import Markdown\n",
"Markdown('This is markdown text.\\n\\n* Some **more** markdown...\\n* This is a [greek](https://en.wikipedia.org/wiki/Greek) letter: $\\phi$')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## External HTML page (in an IFRAME)\n",
"\n",
"In the next example, an **IFRAME** is created in the output cell, showing you the complete documentation of the **IPython Display** module."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import IFrame\n",
"IFrame('https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html', 1024, 400)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## External PDF file (in an IFRAME)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import IFrame\n",
"IFrame('https://rogerdudler.github.io/git-guide/files/git_cheat_sheet.pdf', 1024, 800)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### End of notebook"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.8"
}
},
"nbformat": 4,
- "nbformat_minor": 2
+ "nbformat_minor": 4
}
diff --git a/TeachingExamples/FallingObjects-demo.ipynb b/TeachingExamples/FallingObjects-demo.ipynb
index 3d6bcc5..c4cba24 100644
--- a/TeachingExamples/FallingObjects-demo.ipynb
+++ b/TeachingExamples/FallingObjects-demo.ipynb
@@ -1,189 +1,181 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"
Use case scenario
\n",
" This notebook is made to be used in class as a virtual demonstration which is operated by the teacher (the notebook is not meant to be used by students).
\n",
"
Features
\n",
" This notebook embeds different types of questions to engage students with the virtual demonstration and uses the type of visualisations that students will be asked to use when solving similar problems (i.e. in this case graphing height, velocity and acceleration as functions of time).
\n",
" The example chosen is voluntarily simple so that anyone can understand what is illustrated and focus the pedagogical features of the example.
\n",
"
More information on using notebooks for virtual demonstrations.
\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Falling objects\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Problem\n",
"\n",
"Present the following problem to your students:\n",
"\n",
"We **drop** an object from a given height with **no initial velocity**. Just like an apple would fall from a tree. \n",
"We consider the movement of the object, **ignoring resistance from the air**.\n",
"\n",
"### Questions\n",
"1. Ask the following **prediction questions** to your students - make sure they write down their answers on a piece of paper:\n",
" * Which object would reach the ground first: a bowling ball (5 kg) or a tennis ball (0.05 kg)?\n",
" * Why? **Discuss your explanations with your neighbour.**\n",
" * Sketch your prediction for the *height* of the object as a function of time. Describe in words what this graph means.\n",
" * Sketch your prediction for the *velocity* of the object as a function of time. Describe in words what this graph means.\n",
" * Sketch your prediction for the *acceleartion* of the object as a function of time. Describe in words what this graph means.\n",
"\n",
"\n",
"2. **Run the demo** and ask the following **observation questions** :\n",
" * When does the each object reaches the ground (time in seconds)?\n",
" * What do you observe when we plot multiple objects at the same time?\n",
" * What can you conclude from this experiment?\n",
"\n",
"\n",
"3. Provide the explanation (e.g. solving the problem on the board), and have students compare their explanation with your own explanation. \n",
"Then ask the following **reflection questions**:\n",
" * What happens if we don't ignore the resistance from the air? -- here you can use the virtual lab to show the effect of air resistance: `FallingObjectsLab(show_withair=True);`\n",
" * What are the criteria to decide when we can ignore resistance from the air or not when solving problems?\n",
"\n",
"\n",
"4. For additional impact, you can show an excerpt of the video below, which demonstrates how a bowling ball and ostrich feathers fall in a vacuum chamber"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Virtual demo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"from lib.fallingobjects import *\n",
"\n",
"FallingObjectsLab(show_withair=False);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*If you wonder how the virtual lab works and would like to see the code, [you can have a look at it at the end of this notebook](#How-does-the-virtual-demo-work%3F).*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Video"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import YouTubeVideo\n",
"YouTubeVideo('E43-CfukEgs', 560, 315, start=171)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" \n",
"\n",
"---\n",
"\n",
"# How does the virtual demo work?\n",
"\n",
"You can have a look at the code of the virtual demo by [opening this python file](lib/fallingobjects.py). \n",
"\n",
"## Use of the virtual demo\n",
"\n",
"Execute the cell below to see the documentation:"
]
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Object `FallingObjectsLab` not found.\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"FallingObjectsLab?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Utility computation functions\n",
"\n",
"You can see the code of the functions used to compute the movement equations for the falling objects using the same kind of syntax. \n",
"Below are two examples showing the code of the function computing height without and with air resistance.\n",
"\n",
"These functions can be redefined and given as parameters when initializing the lab."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"height_time??"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"height_time_withair??"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
diff --git a/TeachingExamples/SuspendedObjects-demo.ipynb b/TeachingExamples/SuspendedObjects-demo.ipynb
index cdf08e2..c50ed45 100644
--- a/TeachingExamples/SuspendedObjects-demo.ipynb
+++ b/TeachingExamples/SuspendedObjects-demo.ipynb
@@ -1,172 +1,123 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
" WORK IN PROGRESS This notebook is under development, please bear with us...\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"
Use case scenario
\n",
" This notebook is made to be used in class as a virtual demonstration which is operated by the teacher (the notebook is not meant to be used by students).
\n",
"
Features
\n",
" This notebook embeds different types of questions to engage students with the virtual demonstration and uses different types of visualisations to help students understand the phenomena.
\n",
" The example chosen is voluntarily simple so that anyone can understand what is illustrated and focus the pedagogical features of the example.
\n",
"
More information on using notebooks for virtual demonstrations.
\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Suspended objects\n",
"\n",
"### Problem\n",
"Present the following problem to your students:\n",
"\n",
"\n",
"\n",
"We consider a clothesline made of two poles and a cable. The cable is fixed on one pole. A pulley on the other pole allows to attach a counterweight to pull the cable taut. \n",
"The focus of our problem is the counterweight.\n",
"\n",
"### Questions\n",
"\n",
"1. Ask the following **prediction question** to students **using the polling software of your choice** \n",
"\\[[For instance you could use clickers, more on that on the EPFL clickers website](http://clickers.epfl.ch)\\]\n",
" * Estimate which counterweight allows to suspend wet jeans (3kg) on the cable so that the cable is taut as shown on the diagram? The question is about the order of magnitude, NOT the exact value.\n",
" * 1,5 kg\n",
" * 3 kg\n",
" * 6 kg\n",
" * 20 kg\n",
" * 50 kg or more\n",
" * Why? Discuss in words your explanation for this behavior. \n",
" \n",
" \n",
"2. Run the demo and ask the following **observation questions** :\n",
" * What is the height of the point at which the jeans are suspended for a counterweight of 3kg? 6kg? 20kg? 50kg?\n",
" * What can you conclude from this experiment?\n",
"\n",
"\n",
"3. Provide the explanation (e.g. solving the problem on the board), and have students compare their explanation with your own explanation."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Virtual demo"
]
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "0c7178c9a8454cabb05d09396da0a40d",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(HBox(children=(Label(value='Mass of the counterweight ($kg$):', layout=Layout(margin='5px 10px'…"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"%matplotlib inline\n",
"from lib.suspendedobjects import *\n",
"SuspendedObjectsLab();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"# How does the virtual demo work?\n",
"\n",
"If you wonder how the virtual lab works: \n",
"* You can have a look at the code of the virtual demo by [opening this python file](lib/suspendedobjects.py).\n",
"* You can see the documentation by executing the cell below:"
]
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "\u001b[0;31mInit signature:\u001b[0m\n",
- "\u001b[0mSuspendedObjectsLab\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mm_object\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mdistance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mheight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mx_origin\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0my_origin\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mget_angle_from_masses\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m<\u001b[0m\u001b[0mfunction\u001b[0m \u001b[0mget_angle_from_masses\u001b[0m \u001b[0mat\u001b[0m \u001b[0;36m0x7f51acd6c0d0\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mget_object_coordinates\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m<\u001b[0m\u001b[0mfunction\u001b[0m \u001b[0mget_object_coordinates\u001b[0m \u001b[0mat\u001b[0m \u001b[0;36m0x7f51acd6c158\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mDocstring:\u001b[0m This class embeds all the necessary code to create a virtual lab to study the static equilibrium of an object suspended on a clothesline with a counterweight.\n",
- "\u001b[0;31mInit docstring:\u001b[0m\n",
- "Initiates and displays the virtual lab on suspended objects.\n",
- "\n",
- ":m_object: mass of the suspended object\n",
- ":distance: horizontal distance between the two poles\n",
- ":height: height of the poles (same height for both)\n",
- ":x_origin: x coordinate of the bottom of the left pole (origin of the coordinate system)\n",
- ":y_origin: y coordinate of the bottom of the left pole (origin of the coordinate system)\n",
- "\n",
- ":get_angle_from_masses: function to compute the angle that the cable makes with the horizon, as a function of the respective masses of the object and the counterweight -- angle(m_object, m_counterweight, distance, height)\n",
- ":get_object_coordinates: function to compute the coordinates of the point at which the object is suspended on the cable -- coord(angle, x_origin, y_origin, distance, height)\n",
- "\u001b[0;31mFile:\u001b[0m ~/git/noto-poc-notebooks/TeachingExamples/lib/suspendedobjects.py\n",
- "\u001b[0;31mType:\u001b[0m type\n",
- "\u001b[0;31mSubclasses:\u001b[0m \n"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"SuspendedObjectsLab?"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
diff --git a/TeachingExamples/SuspendedObjects-exercise.ipynb b/TeachingExamples/SuspendedObjects-exercise.ipynb
index efa2cea..0f89313 100644
--- a/TeachingExamples/SuspendedObjects-exercise.ipynb
+++ b/TeachingExamples/SuspendedObjects-exercise.ipynb
@@ -1,373 +1,240 @@
{
"cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "\n",
- " WORK IN PROGRESS This notebook is under development, please bear with us...\n",
- "
"
- ]
- },
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"
Use case scenario
\n",
" This notebook is made to be used by students as an assignment or exercise, in autonomy (at home or in an exercise session).
\n",
"
Features
\n",
" This notebook embeds auto-corrected quizzes to engage students with the virtual demonstration and uses different types of visualisations to help students understand the phenomena.
\n",
" The example chosen is voluntarily simple so that anyone can understand what is illustrated and focus the pedagogical features of the example.
\n",
"
More information on using notebooks for exercises or assignements.
\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Suspended objects\n",
"\n",
- "\n",
- "\n",
"## The problem\n",
"We consider a clothesline made of two poles and a cable.\n",
- "The cable is fixed on one pole. A pulley on the other pole allows to attach a counterweight to pull the cable taut.\n",
+ "The cable is fixed on one pole. A pulley on the other pole allows to attach a counterweight to pull the cable taut. \n",
+ "\n",
+ "\n",
"\n",
- "## Quiz 1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
"Execute the cell below to activate the interactive quiz."
]
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- " \n",
- " "
- ],
- "text/plain": [
- ""
- ]
- },
- "execution_count": 1,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
"from IPython.display import IFrame\n",
- "IFrame('https://moodle.epfl.ch/mod/hvp/embed.php?id=1028285', 1024, 550)"
+ "IFrame('https://moodle.epfl.ch/mod/hvp/embed.php?id=1028285', 1024, 500)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Virtual lab\n",
"\n",
"The virtual demonstration below illustrates position of the clothesline for different counterweights. \n",
- "Execute the cell below to launch the virtual demonstration, then *answer the quiz 2 below*."
+ "Execute the cell below to launch the virtual lab, then *answer the quiz below*."
]
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "application/vnd.jupyter.widget-view+json": {
- "model_id": "25bcb56c45c44e1f9d4536ca09593515",
- "version_major": 2,
- "version_minor": 0
- },
- "text/plain": [
- "VBox(children=(HBox(children=(Label(value='Mass of the counterweight ($kg$):', layout=Layout(margin='5px 10px'…"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"%matplotlib inline\n",
"from lib.suspendedobjects import *\n",
- "SuspendedObjectsLab();"
+ "SuspendedObjectsLab();\n",
+ "IFrame('https://h5p.org/h5p/embed/584119', 1024, 350)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Quiz 2\n",
+ " \n",
"\n",
- "Execute the cell below to activate the interactive quizz."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- " \n",
- " "
- ],
- "text/plain": [
- ""
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from IPython.display import IFrame\n",
- "IFrame('https://h5p.org/h5p/embed/584119', 1024, 400)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
"*If you wonder how the virtual lab works and would like to see the code, [you can have a look at it at the end of this notebook](#How-does-the-virtual-lab-work%3F).*\n",
"\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analytic solution\n",
"\n",
"### Goal\n",
"\n",
"The question is which counterweight allows to suspend wet jeans (3kg) on the cable so that the cable is taut as shown on the diagram. \n",
"We are therefore looking for the expression of the **mass of the counterweight $m_{cw}$ as a function of the other parameters of the problem**. \n",
"\n",
"### Method\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 second law 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 is equally distributed $\\vec T$, which combine into a vertical resulting tention $\\vec T_r = 2.\\vec T$\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",
"Using the fact that the tension is equal on both sides of the jeans we get: $\\vec F_j + 2.\\vec T = 0$\n",
"\n",
"If we project on $x$ and $y$ axes, we get: \n",
"$\\left\\{\\begin{matrix} F_{jx} + 2.T_x = 0 \\\\ F_{jy} + 2.T_y = 0\\end{matrix}\\right. $\n",
"\n",
"Since the weight does not have a component on the x axis, it simplifies into: \n",
"$\\left\\{\\begin{matrix} T_x = 0 \\\\ F_{jy} + 2.T_y = 0\\end{matrix}\\right. $\n",
"\n",
"The component of the weight on the y axis is $F_{jy} = - m_j.g$, which gives us: \n",
"$\\left\\{\\begin{matrix} T_x = 0 \\\\ - m_j.g + 2.T_y = 0\\end{matrix}\\right. $\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",
"$\\left\\{\\begin{matrix} T_x = 0 \\\\ - m_j.g + 2.T.sin(\\alpha) = 0\\end{matrix}\\right. $\n",
"\n",
"From there we can get $T$, and this is equation number $(1)$: \n",
"$T = \\frac{m_j.g}{2.sin(\\alpha)}$\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 line: a simple pulley simply changes the direction of the tension so the tension applied on the counterweight is therefore $\\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",
"$\\left\\{\\begin{matrix}T = \\frac{m_j.g}{2.sin(\\alpha)} \\\\ T = m_{cw}.g\\end{matrix}\\right. $\n",
"\n",
"These two equations combined give us:\n",
"\n",
"$\\frac{m_j.g}{2.sin(\\alpha)} = m_{cw}.g$\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 line makes with the horizon*: \n",
"\n",
"$m_{cw} = \\frac{m_j}{2.sin(\\alpha)}$\n",
"\n",
" \n",
"\n",
"### Conclusion\n",
"\n",
"For the line to be taut as show on the figure, $\\alpha$ has to be really small i.e. close to zero. \n",
"This means that $sin(\\alpha)$ will also be close to zero, which means in turn that $m_{cw}$ will be very big.\n",
"Actually, **the more we want the line to be close to the horizon, the bigger $m_{cw}$ we will need!**\n",
"In fact, it is impossible to get the line taut so that it is absolutely straight...\n",
"\n",
" \n",
"\n",
"### Application\n",
"\n",
- "For a pair of wet jeans of $3 kg$ and an angle of $4^\\circ = \\frac{\\pi}{45}$, which is approximately like depicted on the figure, we need to put a counterweight of:"
+ "For a pair of wet jeans of $3 kg$ and an angle of $4^\\circ = \\frac{\\pi}{45}$ for instance, we need to put a counterweight of:"
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "21.503380539305514\n"
- ]
- }
- ],
+ "outputs": [],
"source": [
"mcw = 3 / (2 * np.sin(np.pi / 45))\n",
"print(mcw)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can **check that you get a similar result** with the virtual lab above!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" \n",
"\n",
"---\n",
"\n",
- "# How does the virtual demo work?\n",
+ "# How does the virtual lab work?\n",
"\n",
"If you wonder how the virtual lab works: \n",
- "* You can have a look at the code of the virtual demo by [opening this python file](lib/suspendedobjects.py).\n",
+ "* You can have a look at the code of the virtual lab by [opening this python file](lib/suspendedobjects.py).\n",
"* You can see the documentation by executing the cell below:"
]
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": null,
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "\u001b[0;31mInit signature:\u001b[0m\n",
- "\u001b[0mSuspendedObjectsLab\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mm_object\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mdistance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mheight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mx_origin\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0my_origin\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mget_angle_from_masses\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m<\u001b[0m\u001b[0mfunction\u001b[0m \u001b[0mget_angle_from_masses\u001b[0m \u001b[0mat\u001b[0m \u001b[0;36m0x7f3b430a4048\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m \u001b[0mget_object_coordinates\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m<\u001b[0m\u001b[0mfunction\u001b[0m \u001b[0mget_object_coordinates\u001b[0m \u001b[0mat\u001b[0m \u001b[0;36m0x7f3b430a40d0\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
- "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mDocstring:\u001b[0m This class embeds all the necessary code to create a virtual lab to study the static equilibrium of an object suspended on a clothesline with a counterweight.\n",
- "\u001b[0;31mInit docstring:\u001b[0m\n",
- "Initiates and displays the virtual lab on suspended objects.\n",
- "\n",
- ":m_object: mass of the suspended object\n",
- ":distance: horizontal distance between the two poles\n",
- ":height: height of the poles (same height for both)\n",
- ":x_origin: x coordinate of the bottom of the left pole (origin of the coordinate system)\n",
- ":y_origin: y coordinate of the bottom of the left pole (origin of the coordinate system)\n",
- "\n",
- ":get_angle_from_masses: function to compute the angle that the cable makes with the horizon, as a function of the respective masses of the object and the counterweight -- angle(m_object, m_counterweight, distance, height)\n",
- ":get_object_coordinates: function to compute the coordinates of the point at which the object is suspended on the cable -- coord(angle, x_origin, y_origin, distance, height)\n",
- "\u001b[0;31mFile:\u001b[0m ~/git/noto-poc-notebooks/TeachingExamples/lib/suspendedobjects.py\n",
- "\u001b[0;31mType:\u001b[0m type\n",
- "\u001b[0;31mSubclasses:\u001b[0m \n"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
+ "outputs": [],
"source": [
"SuspendedObjectsLab?"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
diff --git a/TeachingExamples/lib/suspendedobjects.py b/TeachingExamples/lib/suspendedobjects.py
index f691008..392ac70 100644
--- a/TeachingExamples/lib/suspendedobjects.py
+++ b/TeachingExamples/lib/suspendedobjects.py
@@ -1,252 +1,244 @@
import numpy as np
from ipywidgets import interact, interactive, fixed, interact_manual
from ipywidgets import HBox, VBox, Label, Layout
import ipywidgets as widgets
-from IPython.display import set_matplotlib_formats
+from IPython.display import set_matplotlib_formats, display, Math, Markdown, Latex
set_matplotlib_formats('svg')
import matplotlib.pyplot as plt
import matplotlib.patches as pat
plt.style.use('seaborn-whitegrid') # global style for plotting
-###--- Functions depending on the problem parameters
-def get_angle_from_masses(m_object, m_counterweight, distance, height):
- """
- Computes the angle that the cable makes with the horizon depending on the counterweight chosen:
- - if the counterweight is sufficient: angle = arcsin(1/2 * m_object / m_counterweight)
- - else (object on the ground): alpha = np.arctan(height / (distance / 2))
-
- :m_object: mass of the object
- :m_counterweight: mass of the counterweight (has to be > 0)
- :distance: horizontal distance between the two poles
- :height: height of the poles (same height for both)
-
- :returns: angle that the cable makes with the horizon (in rad)
- """
- # Default alpha value i.e. object is on the ground
- alpha_default = np.arctan(height / (distance / 2))
- alpha = alpha_default
-
- # Let's check that there is actually a counterweight
- if m_counterweight > 0:
-
- # Then we compute the ratio of masses
- ratio = 0.5 * m_object / m_counterweight
-
- # Check that the ratio of masses is in the domain of validity of arcsin ([-1;1])
- if abs(ratio) < 1:
- alpha = np.arcsin(ratio)
-
- return min(alpha_default, alpha)
-
-def get_object_coordinates(angle, x_origin, y_origin, distance, height):
- """
- Computes the position of the object on the cable taking into account the angle determined by the counterweight and the dimensions of the hanging system.
- By default:
- - the object is supposed to be suspended exactly in the middle of the cable
- - the object is on considered the ground for all values of the angle
-
- :angle: angle that the cable makes with the horizon
- :x_origin: x coordinate of the bottom of the left pole (origin of the coordinate system)
- :y_origin: y coordinate of the bottom of the left pole (origin of the coordinate system)
- :distance: horizontal distance between the two poles
- :height: height of the poles (same height for both)
-
- :returns: coordinates of the point at which the object are hanged
- """
- # the jean is midway between the poles
- x_object = x_origin + 0.5 * distance
-
- # default y value: the jean is on the ground
- y_object = y_origin
-
- # we check that the angle is comprised between horizontal (greater than 0) and vertical (smaller than pi/2)
- if angle > 0 and angle < (np.pi / 2):
- # we compute the delta between the horizon and the point given by the angle
- delta = (0.5 * distance * np.tan(angle))
- # we check that the delta is smaller than the height of the poles (otherwise it just means the jean is on the ground)
- if delta <= height:
- y_object = y_origin + height - delta
-
- return [x_object, y_object]
-
-
-
class SuspendedObjectsLab:
"""
This class embeds all the necessary code to create a virtual lab to study the static equilibrium of an object suspended on a clothesline with a counterweight.
"""
- def __init__(self, m_object = 3, distance = 5, height = 1, x_origin = 0, y_origin = 0,
- get_angle_from_masses = get_angle_from_masses, get_object_coordinates = get_object_coordinates):
+ def __init__(self, m_object = 3, distance = 5, height = 1, x_origin = 0, y_origin = 0):
'''
Initiates and displays the virtual lab on suspended objects.
:m_object: mass of the suspended object
:distance: horizontal distance between the two poles
:height: height of the poles (same height for both)
:x_origin: x coordinate of the bottom of the left pole (origin of the coordinate system)
:y_origin: y coordinate of the bottom of the left pole (origin of the coordinate system)
-
- :get_angle_from_masses: function to compute the angle that the cable makes with the horizon, as a function of the respective masses of the object and the counterweight -- angle(m_object, m_counterweight, distance, height)
- :get_object_coordinates: function to compute the coordinates of the point at which the object is suspended on the cable -- coord(angle, x_origin, y_origin, distance, height)
'''
###--- Parameters of the situation
self.m_object = m_object # mass of the wet object, in kg
self.distance = distance # distance between the poles, in m
self.height = height # height of the poles, in m
self.x_origin = x_origin # x coordinate of point of origin of the figure = x position of the left pole, in m
self.y_origin = y_origin # y coordinate of point of origin of the figure = y position of the lower point (ground), in m
-
- # Functions to compute equations
- self.get_angle_from_masses = get_angle_from_masses
- self.get_object_coordinates = get_object_coordinates
-
+
###--- Then we define the elements of the ihm:
# parameters for sliders
self.m_counterweight_min = 0
self.m_counterweight_max = 100
self.m_counterweight = self.m_counterweight_min # initial mass of the counterweight (0 by default, no counterweight at the beginning)
# IHM input elements
input_layout=Layout(margin='5px 10px')
self.m_counterweight_label = Label('Mass of the counterweight ($kg$):', layout=input_layout)
self.m_counterweight_widget = widgets.FloatSlider(min=self.m_counterweight_min,max=self.m_counterweight_max,step=1,value=self.m_counterweight, layout=input_layout)
self.m_counterweight_input = HBox([self.m_counterweight_label, self.m_counterweight_widget])
# IHM output elements
self.y_object_output = widgets.Output(layout=input_layout)
self.graph_output = widgets.Output(layout=input_layout)
# Linking widgets to handlers
self.m_counterweight_widget.observe(self.m_counterweight_event_handler, names='value')
# Organize layout
- self.ihm = VBox([self.m_counterweight_input, self. y_object_output, self.graph_output])
+ self.ihm = VBox([HBox([self.m_counterweight_input, self. y_object_output]), self.graph_output])
###--- Finally, we display the whole interface and we update it right away so that it plots the graph with current values
display(self.ihm);
self.update_lab()
# Event handlers
def m_counterweight_event_handler(self, change):
self.m_counterweight = change.new
self.update_lab()
+ # Utility functions
+ def get_angle(self, m_counterweight):
+ """
+ Computes the angle that the cable makes with the horizon depending on the counterweight chosen:
+ - if the counterweight is sufficient: angle = arcsin(1/2 * m_object / m_counterweight)
+ - else (object on the ground): alpha = np.arctan(height / (distance / 2))
+
+ :m_counterweight: mass of the chosen counterweight
+
+ :returns: angle that the cable makes with the horizon (in rad)
+ """
+ # Default alpha value i.e. object is on the ground
+ alpha_default = np.arctan(self.height / (self.distance / 2))
+ alpha = alpha_default
+
+ # Let's check that there is actually a counterweight
+ if m_counterweight > 0:
+
+ # Then we compute the ratio of masses
+ ratio = 0.5 * self.m_object / m_counterweight
+
+ # Check that the ratio of masses is in the domain of validity of arcsin ([-1;1])
+ if abs(ratio) < 1:
+ alpha = np.arcsin(ratio)
+
+ return min(alpha_default, alpha)
+
+
+ def get_object_coords(self, angle):
+ """
+ Computes the position of the object on the cable taking into account the angle determined by the counterweight and the dimensions of the hanging system.
+ By default:
+ - the object is supposed to be suspended exactly in the middle of the cable
+ - the object is on considered the ground for all values of the angle
+
+ :angle: angle that the cable makes with the horizon
+
+ :returns: coordinates of the point at which the object are hanged
+ """
+ # the jean is midway between the poles
+ x_object = self.x_origin + 0.5 * self.distance
+
+ # default y value: the jean is on the ground
+ y_object = self.y_origin
+
+ # we check that the angle is comprised between horizontal (greater than 0) and vertical (smaller than pi/2)
+ if angle > 0 and angle < (np.pi / 2):
+ # we compute the delta between the horizon and the point given by the angle
+ delta = (0.5 * self.distance * np.tan(angle))
+ # we check that the delta is smaller than the height of the poles (otherwise it just means the jean is on the ground)
+ if delta <= self.height:
+ y_object = self.y_origin + self.height - delta
+
+ return [x_object, y_object]
+
+
+
# Create visualisation
def update_lab(self):
# Clear outputs
self.graph_output.clear_output(wait=True)
self.y_object_output.clear_output(wait=True)
- alpha = self.get_angle_from_masses(self.m_object, self.m_counterweight, self.distance, self.height)
+ alpha = self.get_angle(self.m_counterweight)
alpha_degrees = alpha*180/np.pi
- coord_object = self.get_object_coordinates(alpha, self.x_origin, self.y_origin, self.distance, self.height)
+ coord_object = self.get_object_coords(alpha)
+ #alpha = self.get_angle_from_masses(self.m_object, self.m_counterweight, self.distance, self.height)
+ #coord_object = self.get_object_coordinates(alpha, self.x_origin, self.y_origin, self.distance, self.height)
# Create the figure
- fig = plt.figure(figsize=(14, 4))
+ fig = plt.figure(figsize=(16, 4))
ax1 = plt.subplot(131)
ax2 = plt.subplot(132)
ax3 = plt.subplot(133, sharex = ax2, sharey = ax1)
###--- First display the clothesline
ax1.set_title('Clothesline')
# Fix graph to problem boundaries
ax1.set_ylim(bottom = self.y_origin) # limit bottom of y axis to ground
ax1.set_ylim(top = self.y_origin + self.height + .1) # limit top of y axis to values just above height
# Customize graph style so that it doesn't look like a graph
- ax1.get_xaxis().set_visible(False) # hide the x axis
- ax1.set_ylabel("Height ($m$)") # add a label on the y axis
+ #ax1.get_xaxis().set_visible(False) # hide the x axis
ax1.grid(False) # hide the grid
+ ax1.set_ylabel("Height ($m$)") # add a label on the y axis
+ ax1.set_xlabel("Width ($m$)") # add a label on the x axis
ax1.spines['top'].set_visible(False) # hide the frame except bottom line
ax1.spines['right'].set_visible(False)
ax1.spines['left'].set_visible(False)
# Draw poles
x_pole1 = np.array([self.x_origin, self.x_origin])
y_pole1 = np.array([self.y_origin, self.y_origin+self.height])
ax1.plot(x_pole1, y_pole1, "k-", linewidth=7)
x_pole2 = np.array([self.x_origin+self.distance, self.x_origin+self.distance])
y_pole2 = np.array([self.y_origin, self.y_origin+self.height])
ax1.plot(x_pole2, y_pole2, "k-", linewidth=7)
# Draw the hanging cable
x = np.array([self.x_origin, coord_object[0], self.x_origin+self.distance])
y = np.array([self.y_origin+self.height, coord_object[1], self.y_origin+self.height])
ax1.plot(x, y, linewidth=3, linestyle = "-", color="green")
# Draw the horizon line
ax1.axhline(y=self.y_origin+self.height, color='gray', linestyle='-.', linewidth=1, zorder=1)
# Draw the angle between the hanging cable and horizonline
ellipse_radius = 0.2
fig_ratio = self.height / self.distance
ax1.add_patch(pat.Arc(xy = (self.x_origin, self.y_origin+self.height), width = ellipse_radius/fig_ratio, height = ellipse_radius, theta1 = -1*alpha_degrees, theta2 = 0, color="gray", linestyle='-.'))
ax1.annotate(r'$\alpha$', xy=(self.x_origin+(.15/fig_ratio), self.y_origin+self.height-.05))
# Draw the point at which the object is suspended
ax1.scatter(coord_object[0], coord_object[1], s=80, c="r", zorder=15)
ax1.annotate('m = {} kg'.format(self.m_object), xy=(coord_object[0], coord_object[1]), xytext=(coord_object[0]+0.1, coord_object[1]-0.1))
###--- Then display the angle and the height as functions from the mass of the counterweight
ax2.set_title(r'Angle $\alpha$ of the cable vs. horizon ($^\circ$)')
ax3.set_title(r'Height of the suspension point ($m$)')
# Create all possible values of the mass of the counterweight
m_cw = np.linspace(self.m_counterweight_min, self.m_counterweight_max, 100)
# Compute the angle (in degrees) and height for all these values
angle = []
height = []
for m in m_cw:
- a = self.get_angle_from_masses(self.m_object, m, self.distance, self.height)
+ a = self.get_angle(m)
+ #a = self.get_angle_from_masses(self.m_object, m, self.distance, self.height)
angle.append(a*180/np.pi)
- c = self.get_object_coordinates(a, self.x_origin, self.y_origin, self.distance, self.height)
+ c = self.get_object_coords(a)
+ #c = self.get_object_coordinates(a, self.x_origin, self.y_origin, self.distance, self.height)
height.append(c[1])
# Display the functions on the graphs
ax2.set_xlabel('Mass of the counterweight (kg)')
ax2.plot(m_cw, angle, "b")
ax3.set_xlabel('Mass of the counterweight (kg)')
ax3.plot(m_cw, height, "b")
# Draw the horizon lines
ax2.axhline(y=self.y_origin, color='gray', linestyle='-.', linewidth=1, zorder=1)
ax3.axhline(y=self.y_origin+self.height, color='gray', linestyle='-.', linewidth=1, zorder=1)
# Add the current angle from the counterweight selected by the user
ax2.scatter(self.m_counterweight, alpha_degrees, s=80, c="r", zorder=15)
# Add the current height from the counterweight selected by the user
ax3.scatter(self.m_counterweight, coord_object[1], s=80, c="r", zorder=15)
# Display height of object selected
with self.y_object_output:
- print("Height of the point at which the object is hanged: {:.4f} m".format(coord_object[1]))
+ display(Latex(r"Angle $\alpha$ that the cable makes with the horizon: {:.3f} $^\circ$".format(alpha_degrees)))
+ display(Latex(r"Height of the point at which the object is hanged: {:.3f} $m$".format(coord_object[1])))
# Display graph
with self.graph_output:
plt.show();
# EOF