diff --git a/jupyter_notebooks/02_BangBang.ipynb b/jupyter_notebooks/02_BangBang.ipynb index c6cdb3bf84d68fbc126aed4be8a867aa96f88def..05189e109ac23879924702afd4069b6df9211930 100644 --- a/jupyter_notebooks/02_BangBang.ipynb +++ b/jupyter_notebooks/02_BangBang.ipynb @@ -19,7 +19,8 @@ "from tuto_control_lib.plot import plot_u_y\n", "\n", "import matplotlib.pyplot as plt\n", - "import numpy as np" + "import numpy as np\n", + "from statistics import mean" ] }, { @@ -29,13 +30,14 @@ "tags": [] }, "source": [ - "One way to do this would be to have two bounds for the system output:\n", + "One way to do regulate the output of a system would be to have two bounds for the system sensor:\n", "\n", "- one upper bound\n", "- one lower bound\n", "\n", "When the system output is greater than the upper bound, we decrease the input.\n", - "And when the system output is lower than the lower bound, we increse the input." + "And when the system output is lower than the lower bound, we increase the input.\n", + "Else, we keep the previous input." ] }, { @@ -45,7 +47,14 @@ "tags": [] }, "source": [ - "Say that we want to regulate our system around the value 6.\n", + "Say that we want to regulate our system around the value 1.\n", + "\n", + "We now have to chose the values of the bounds.\n", + "\n", + "The issue is that there is no protocol to find the values of the bounds and the incremental part.\n", + "\n", + "So, we have to proceed by try-and-error.\n", + "\n", "\n", "We can say take as lower bound 5 and as upper bound 7." ] @@ -62,17 +71,18 @@ "system, u, y_values, u_values, max_iter = IntroSystem(), 0, [], [], 100\n", "\n", "reference_value = 1\n", - "upper_bound = 0.75\n", - "lower_bound = 1.25\n", + "upper_bound = 0.5\n", + "lower_bound = 1.5\n", + "increment = 0.5\n", "\n", "for i in range(max_iter):\n", " y = system.sense()\n", " y_values.append(y)\n", " \n", " if y < lower_bound:\n", - " u += 0.25\n", + " u += increment\n", " elif y > upper_bound:\n", - " u -= 0.25\n", + " u -= increment\n", " else:\n", " pass\n", " system.apply(u)\n", @@ -88,7 +98,31 @@ "tags": [] }, "source": [ - "As we can see, the system converges, but not to the reference value..." + "As we can see, the system is somewhat under control, but oscillate a lot." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecdc7121-d253-477d-92dc-4485abd97d29", + "metadata": {}, + "outputs": [], + "source": [ + "mean_error = mean(map(lambda x: abs(reference_value - x), y_values))\n", + "max_overshoot = (max(y_values) - reference_value) / reference_value\n", + "\n", + "print(f\"Mean Error: {mean_error}\")\n", + "print(f\"Max. Overshoot: {max_overshoot}\")" + ] + }, + { + "cell_type": "markdown", + "id": "2b58c216-0ef8-4d17-8b35-514974b47570", + "metadata": {}, + "source": [ + "<div class=\"alert alert-info\">\n", + "Try changing the values of the bounds and the increment to see the behaviour of the system.\n", + "</div>" ] }, { diff --git a/jupyter_notebooks/03_PController.ipynb b/jupyter_notebooks/03_PController.ipynb index 8c48125743dfcb1399716ac5dd7c56549266d6c0..485503f4d994ccdb6185c92ef9ad27f018017fe3 100644 --- a/jupyter_notebooks/03_PController.ipynb +++ b/jupyter_notebooks/03_PController.ipynb @@ -25,12 +25,32 @@ }, { "cell_type": "markdown", - "id": "125b3cfd-1f55-4202-8f50-97d0cafb5b87", + "id": "028756f1-641f-4c33-9879-cbb53ee0f256", "metadata": {}, "source": [ + "We have seen that a Bang-Bang solution manages to roughly get the system in the desired state.\n", + "\n", + "However, the lack of protocol and guarentees of this solution limits its adoption on production systems.\n", + "\n", + "In this section, we introduce the most basic controller from Control Theory: the *Proportional Controller*.\n", + "\n", "The idea of the proportional controller is to have a response proportional to the control error.\n", "\n", - "The control error is the distance between the desired behaviour and the current state of the system." + "The control error is the distance between the desired behaviour and the current state of the system.\n", + "\n", + "The equation of a P Controller is the following:\n", + "\n", + "$$\n", + "u(k) = K_p \\times e(k) = K_p \\times \\left(y_{ref} - y(k)\\right)\n", + "$$\n", + "\n", + "where:\n", + "\n", + "- $K_p$ is the propotional gain of the controller\n", + "- $y_{ref}$ is the reference value for our system (i.e. the desired value of the system output)\n", + "- $y(k)$ is the system output at iteration $k$\n", + "- $e(k)$ is the control error at iteration $k$\n", + "- $u(k)$ is the input at iteration $k$" ] }, { @@ -40,13 +60,10 @@ "metadata": {}, "outputs": [], "source": [ - "max_iter = 100\n", - "system = IntroSystem()\n", + "system, u_values, y_values, u, max_iter = IntroSystem(), [], [], 0, 100\n", + "\n", "reference_value = 1\n", "kp = 3.3\n", - "y_values = []\n", - "u_values = []\n", - "u = 0\n", "\n", "for i in range(max_iter):\n", " y = system.sense()\n", @@ -61,6 +78,15 @@ "plot_u_y(u_values, y_values, reference_value)" ] }, + { + "cell_type": "markdown", + "id": "63203ee3-be90-4e9a-92d4-57a08d042631", + "metadata": {}, + "source": [ + "As we can see, the system converges, but to a values different than the reference value.\n", + "The controller introduces oscillations before converging." + ] + }, { "cell_type": "code", "execution_count": null, @@ -68,7 +94,17 @@ "metadata": {}, "outputs": [], "source": [ - "y_values[-1]" + "print(f\"Steady state value: {y_values[-1]}\\nReference value: {reference_value}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f664e07a-5ea6-4d0f-b826-beb0caeb6c90", + "metadata": {}, + "source": [ + "<div class=\"alert alert-info\">\n", + "Try changing the values of the proportional gain $K_p$ and the reference value.\n", + "</div>" ] }, { @@ -79,6 +115,39 @@ "# Design of a Proportional Controller" ] }, + { + "cell_type": "markdown", + "id": "49936477-c739-476b-a351-c59ec23f9d68", + "metadata": {}, + "source": [ + "To design a Proportional Controller with guarentees, we must have a model of our system.\n", + "\n", + "A model, in the sense of Control Theory, is a relation between the inputs and the outputs.\n", + "\n", + "The general form of a model is the following:\n", + "\n", + "$$\n", + "y(k + 1) = \\sum_{i = 0}^k a_i y(k - i) + \\sum_{i = 0}^k b_i u(k - i)\n", + "$$\n", + "\n", + "where:\n", + "\n", + "- $y(k + 1)$ is the next value of the output\n", + "- $y(k-i)$ and $u(k-i)$ are previous values of the output and the input\n", + "- $a_i$ and $b_i$ are the coefficients of the model ($\\forall i, (a_i, b_i) \\in (\\mathbb{R}, \\mathbb{R})$)\n", + "\n", + "Usually, and to simplify this introduction, we consider *first order models*.\n", + "\n", + "This means that the model only considers the last values of $y$ and $u$ to get the next value of $y$.\n", + "\n", + "$$\n", + "y(k + 1) = a y(k) + b u(k)\n", + "$$\n", + "\n", + "In this section, we will suppose that we have a first order model which we know the coefficients.\n", + "In a [future section](./05_Identification.ipynb), we will look at how to find these coefficients." + ] + }, { "cell_type": "code", "execution_count": null, @@ -86,7 +155,9 @@ "metadata": {}, "outputs": [], "source": [ + "# Our system\n", "system = IntroSystem()\n", + "# The coefficients\n", "a = 0.8\n", "b = 0.5" ] @@ -139,31 +210,25 @@ }, { "cell_type": "markdown", - "id": "ff825fc1-825d-4d0f-9172-cc3d25edb83b", + "id": "35f5b723-9eb7-4314-8fe1-7989b612e1fe", "metadata": {}, "source": [ "Proportional Controllers are inheritly imprecise.\n", - "But we can tune their precision based on the reference value.\n", + "But we can tune their precision ($e_{ss}$) based on the reference value ($r_{ss}$).\n", "\n", "$$\n", "\\begin{aligned}\n", "e_{ss} &= r_{ss} ( 1 - F_R(1)) \\\\\n", - " &= r_{ss} \\left(1 - \\frac{b K_p}{1 - (a - b K_p)}\\right)\n", + " &= r_{ss} \\left(1 - \\frac{b K_p}{1 - (a - b K_p)}\\right) < e_{ss}^*\n", "\\end{aligned}\n", - "$$" - ] - }, - { - "cell_type": "markdown", - "id": "f86f5dcd-564c-4f73-8156-cc0a5b2c685c", - "metadata": {}, - "source": [ - "Say we want the steady state error to be less that $e_{target}$.\n", + "$$\n", + "\n", + "Say we want the steady state error to be less that $e_{ss}^*$.\n", "\n", "Then,\n", "\n", "$$\n", - "K_p > \\frac{\\left(1 - \\frac{e_t}{r_{ss}}\\right)\\left(1 - a\\right)}{b\\frac{e_t}{r_{ss}}}\n", + "K_p > \\frac{\\left(1 - \\frac{e_{ss}^*}{r_{ss}}\\right)\\left(1 - a\\right)}{b\\frac{e_{ss}^*}{r_{ss}}}\n", "$$\n", "\n", "In our case:" @@ -177,9 +242,9 @@ "outputs": [], "source": [ "r_ss = 1\n", - "e_t = 0.15\n", + "e_star = 0.15\n", "\n", - "precision_lower_bound = (1 - e_t/r_ss) * (1 - a)/(b * (e_t/r_ss))\n", + "precision_lower_bound = (1 - e_star/r_ss) * (1 - a)/(b * (e_star/r_ss))\n", "\n", "print(f\"K_p > {precision_lower_bound}\")" ] @@ -197,6 +262,8 @@ "id": "320e2695-9a0b-4a8d-909b-4385dbebf6af", "metadata": {}, "source": [ + "The settling time, or the time to reach the steady state value is defined as follows:\n", + "\n", "$$\n", "k_s \\simeq \\frac{-4}{\\log | a - b K_p| }\n", "$$\n", @@ -219,9 +286,9 @@ "metadata": {}, "outputs": [], "source": [ - "k_s = 10\n", - "settling_time_lower_bound = (a - exp(-4/k_s)) / b\n", - "settling_time_upper_bound = (a + exp(-4/k_s)) / b\n", + "ks_star = 10\n", + "settling_time_lower_bound = (a - exp(-4/ks_star)) / b\n", + "settling_time_upper_bound = (a + exp(-4/ks_star)) / b\n", "\n", "print(f\"{settling_time_lower_bound} < K_p < {settling_time_upper_bound}\")" ] @@ -239,6 +306,9 @@ "id": "a04de440-6087-4f45-a302-02c0f3bfdd20", "metadata": {}, "source": [ + "The maximum overshoot is the maximum error above the reference value.\n", + "It is defined as:\n", + "\n", "$$\n", "M_p = | a - b K_p|\n", "$$\n", @@ -249,6 +319,8 @@ "\\frac{a - M_p^*}{b} < K_p < \\frac{a + M_p^*}{b}\n", "$$\n", "\n", + "But we really are only interested in the upper bound.\n", + "\n", "In our case:" ] }, @@ -259,8 +331,8 @@ "metadata": {}, "outputs": [], "source": [ - "mp = 0.1\n", - "max_overshoot_upper_bound = (a + mp) / b\n", + "mp_star = 0.1\n", + "max_overshoot_upper_bound = (a + mp_star) / b\n", "print(f\"K_p < {max_overshoot_upper_bound}\")" ] }, @@ -294,9 +366,9 @@ "source": [ "As we can see, there is no value of $K_p$ that satisfies all the properties.\n", "\n", - "You can play with the different values defining the desired behavior to find a $K_p$ value that satisfies them.\n", - "\n", - "The key point is that implementing a Proportional controller requires some **trade-off**!\n", + "<div class=\"alert alert-danger\" role=\"alert\">\n", + " The key point is that implementing a Proportional controller requires some <b>trade-off</b>!\n", + "</div>\n", "\n", "In the example above, the value $K_p = 2.5$ seems to statisfy most of the properties." ] @@ -308,10 +380,9 @@ "metadata": {}, "outputs": [], "source": [ - "max_iter = 20\n", "reference_value = 1\n", "kp = 2.5\n", - "y_values, u_values, u, system = [], [], 0, IntroSystem()\n", + "y_values, u_values, u, system, max_iter = [], [], 0, IntroSystem(), 20\n", "\n", "for i in range(max_iter):\n", " y = system.sense()\n", @@ -342,12 +413,12 @@ "outputs": [], "source": [ "e_ss = reference_value - y_values[-1]\n", - "max_overshoot = (max(y_values) - reference_value) / reference_value\n", + "max_overshoot = (max(y_values) - y_values[-1]) / y_values[-1]\n", "settling_time = len([x for x in y_values if abs(x - y_values[-1]) > 0.05])\n", "\n", - "print(f\"Precision: {e_ss} -> desired: < {e_t}\")\n", - "print(f\"Settling Time: {settling_time} -> desired: < {k_s}\")\n", - "print(f\"Max. Overshoot: {max_overshoot} -> desired: < {mp}\")" + "print(f\"Precision: {e_ss} -> desired: < {e_star}\")\n", + "print(f\"Settling Time: {settling_time} -> desired: < {ks_star}\")\n", + "print(f\"Max. Overshoot: {max_overshoot} -> desired: < {mp_star}\")" ] }, { @@ -358,6 +429,16 @@ "As expected, the closed loop system overshoots too much, but the other properties are respected." ] }, + { + "cell_type": "markdown", + "id": "01c36250-4482-47d9-a1ab-6451f7470ca7", + "metadata": {}, + "source": [ + "<div class=\"alert alert-info\" role=\"alert\">\n", + " Try to change the requirements on the closed-loop properties to find different values of $K_p$ and plot the system.\n", + "</div>" + ] + }, { "cell_type": "markdown", "id": "09a14ea2-b496-4d8a-b5d7-155a5b4d60c9", diff --git a/jupyter_notebooks/04_PIController.ipynb b/jupyter_notebooks/04_PIController.ipynb index 9ab06292c42a62d184de7fba3080ac43627db886..6c82620c52c7692a37288fe5992ae01d83056c0b 100644 --- a/jupyter_notebooks/04_PIController.ipynb +++ b/jupyter_notebooks/04_PIController.ipynb @@ -30,8 +30,10 @@ "metadata": {}, "source": [ "As we have seen before, a Proportional controller is inheritly imprecise.\n", + "\n", "One way to improve the precision of the closed loop system is to add an integral term to the controller.\n", - "The integral term aims at cancel the steady state error.\n", + "\n", + "The integral term aims at canceling the steady state error.\n", "\n", "The form of the controller (in discrete time) is the following:\n", "\n", @@ -55,7 +57,7 @@ "ki = 1.5\n", "y_values, u_values, u, system, integral = [], [], 0, IntroSystem(), 0\n", "\n", - "for i in range(max_iter):\n", + "for _ in range(max_iter):\n", " y = system.sense()\n", " y_values.append(y)\n", " \n", @@ -78,6 +80,16 @@ "However, there are some oscillations and overshooting..." ] }, + { + "cell_type": "markdown", + "id": "cb414899-941e-4652-93c1-df6ab939c6f8", + "metadata": {}, + "source": [ + "<div class=\"alert alert-info\" role=\"alert\">\n", + " Try to change the values of $K_p$ and $K_i$ to observe the change of behavior.\n", + "</div>" + ] + }, { "cell_type": "markdown", "id": "dc185bc1-7b31-41df-8dd3-b260aca6097b", @@ -92,7 +104,14 @@ "metadata": {}, "source": [ "As for the P Controller, we have to chose the desired closed loop behavior.\n", - "In the case of a PI Controller, we have the precision by the integral term.\n", + "\n", + "In the case of a PI Controller, we have the precision by the integral term, and the precision as for the P Controller.\n", + "\n", + "There are several methods to find gains for a PI Controller.\n", + "In the following we use the *pole placement method*.\n", + "The idea is to chose the poles of the closed-loop system to fit the desired behavior.\n", + "\n", + "Without too much details to avoid being too \"mathy\", we give the equations leading to the gains.\n", "\n", "Given the desired values for $k_s$ (settling time) and $M_p$ (max. overshoot), we get:\n", "\n", @@ -118,11 +137,13 @@ "metadata": {}, "outputs": [], "source": [ + "# The coefficients of our system\n", "a = 0.8\n", "b = 0.5\n", "\n", - "k_s = 10\n", - "mp = 0.05\n", + "# Our desired properties\n", + "ks = 10\n", + "mp = 0.01\n", "\n", "r = exp(-4/k_s)\n", "theta = pi * log(r) / log(mp)\n", @@ -142,15 +163,15 @@ "source": [ "max_iter = 50\n", "reference_value = 1\n", - "y_values, u_values, u, system, integral = [], [], 0, IntroSystem(), 0\n", + "y_values, u_values, u, system, integral_error = [], [], 0, IntroSystem(), 0\n", "\n", "for i in range(max_iter):\n", " y = system.sense()\n", " y_values.append(y)\n", " \n", " error = reference_value - y\n", - " integral += error\n", - " u = kp * error + ki * integral\n", + " integral_error += error\n", + " u = kp * error + ki * integral_error\n", " \n", " system.apply(u)\n", " u_values.append(u)\n", @@ -166,14 +187,24 @@ "outputs": [], "source": [ "e_ss = reference_value - y_values[-1]\n", - "max_overshoot = (max(y_values) - reference_value) / reference_value\n", + "max_overshoot = (max(y_values) - y_values[-1]) / y_values[-1]\n", "settling_time = len([x for x in y_values if abs(x - y_values[-1]) > 0.05])\n", "\n", "print(f\"Precision: {e_ss}\")\n", - "print(f\"Settling Time: {settling_time} -> desired: < {k_s}\")\n", + "print(f\"Settling Time: {settling_time} -> desired: < {ks}\")\n", "print(f\"Max. Overshoot: {max_overshoot} -> desired: < {mp}\")" ] }, + { + "cell_type": "markdown", + "id": "41159696-e75e-4ae5-8b69-44799bf482d9", + "metadata": {}, + "source": [ + "<div class=\"alert alert-info\" role=\"alert\">\n", + " Try to change the requirements on the closed-loop properties to find different values of $K_p$ and $K_i$ and plot the system.\n", + "</div>" + ] + }, { "cell_type": "markdown", "id": "e8e31f05-7d99-4793-801e-51c292c7c8ec", diff --git a/jupyter_notebooks/05_Identification.ipynb b/jupyter_notebooks/05_Identification.ipynb index 803378de86de49fb4dead7b2018b5b788dee4e2b..92e3fde4a56252eba005a6329263bbf047202c87 100644 --- a/jupyter_notebooks/05_Identification.ipynb +++ b/jupyter_notebooks/05_Identification.ipynb @@ -30,15 +30,15 @@ "metadata": {}, "source": [ "For moment, we supposed the model of the system known (i.e. the coeficients $a$ and $b$).\n", - "But in practice, we do not know.\n", + "But in practice, we do not know them.\n", "\n", - "In this Section, we will perform what is called the *identification* to get the model of the system.\n", + "In this Section, we will perform what is called the *Identification* to get the coefficient of the system model.\n", "\n", "The idea of the identification phase is simple: \"Get the relation between the input and output\".\n", "\n", "To do this, the most basic way is to perform a serie of step inputs and observe the output.\n", "\n", - "In this Section, we will use the `UnknownSystem`." + "In this Section, we will use the `UnknownSystem` and try to find its coefficients." ] }, { @@ -48,20 +48,18 @@ "metadata": {}, "outputs": [], "source": [ - "max_iter = 200\n", "system = UnknownSystem()\n", - "y_values, u_values, u, system, integral = [], [], 0, UnknownSystem(), 0\n", - "#y_values, u_values, u, system, integral = [], [], 0, System(0.314, 0.628), 0\n", + "y_values_ident, u_values_ident, u, system, max_iter = [], [], 0, UnknownSystem(), 200\n", "for i in range(max_iter):\n", " y = system.sense()\n", - " y_values.append(y)\n", + " y_values_ident.append(y)\n", " \n", " u = (i + 20) // 20\n", " \n", " system.apply(u)\n", - " u_values.append(u)\n", + " u_values_ident.append(u)\n", "\n", - "plot_u_y(u_values, y_values)" + "plot_u_y(u_values_ident, y_values_ident)" ] }, { @@ -69,9 +67,7 @@ "id": "161a6257-f786-4437-b264-678feadd1863", "metadata": {}, "source": [ - "Let us first look at the steady state.\n", - "\n", - "We are looking for an expression of the following form:\n", + "We are looking for an expression for a first order system of the following form:\n", "\n", "$$\n", "y(k+1) = a y(k) + b u(k)\n", @@ -97,12 +93,13 @@ "source": [ "previous_u = 1\n", "gain_ss = None\n", - "for (u, y) in zip(u_values, y_values):\n", + "for (u, y) in zip(u_values_ident, y_values_ident):\n", " if u != previous_u:\n", " print(f\"u: {previous_u} -> {gain_ss}\")\n", " previous_u = u\n", " else:\n", - " gain_ss = y / u" + " gain_ss = y / u\n", + "print(f\"u: {previous_u} -> {gain_ss}\")" ] }, { @@ -118,7 +115,7 @@ "id": "3e9f8daf-b9c4-476b-b6f1-c5ea97b74574", "metadata": {}, "source": [ - "We can try to perform a Least Mean Square to get an estimation of the model:" + "We will perform a Least Mean Square to get an estimation of the model:" ] }, { @@ -128,8 +125,8 @@ "metadata": {}, "outputs": [], "source": [ - "u_values_identification = u_values\n", - "y_values_identification = y_values\n", + "u_values_identification = u_values_ident\n", + "y_values_identification = y_values_ident\n", "\n", "s1 = sum(y * y for y in y_values_identification)\n", "s2 = sum(u * y for (u, y) in zip(u_values_identification, y_values_identification))\n", @@ -186,7 +183,7 @@ "metadata": {}, "outputs": [], "source": [ - "ks = 20\n", + "ks = 10\n", "mp = 0.05\n", "\n", "r = exp(-4/ks)\n", @@ -205,17 +202,16 @@ "metadata": {}, "outputs": [], "source": [ - "max_iter = 100\n", "reference_value = 1\n", - "y_values, u_values, u, system, integral = [], [], 0, UnknownSystem(), 0\n", + "y_values, u_values, u, system, integral_error, max_iter = [], [], 0, UnknownSystem(), 0, 50\n", "\n", "for i in range(max_iter):\n", " y = system.sense()\n", " y_values.append(y)\n", " \n", " error = reference_value - y\n", - " integral += error\n", - " u = kp * error + ki * integral\n", + " integral_error += error\n", + " u = kp * error + ki * integral_error\n", " \n", " system.apply(u)\n", " u_values.append(u)\n", @@ -223,6 +219,22 @@ "plot_u_y(u_values, y_values, reference_value)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "2759322c-239d-4376-a70a-e9fc6346f0e8", + "metadata": {}, + "outputs": [], + "source": [ + "e_ss = reference_value - y_values[-1]\n", + "max_overshoot = (max(y_values) - y_values[-1]) / y_values[-1]\n", + "settling_time = len([x for x in y_values if abs(x - y_values[-1]) > 0.05])\n", + "\n", + "print(f\"Precision: {e_ss}\")\n", + "print(f\"Settling Time: {settling_time} -> desired: < {ks}\")\n", + "print(f\"Max. Overshoot: {max_overshoot} -> desired: < {mp}\")" + ] + }, { "cell_type": "markdown", "id": "d916d270-f6c7-4f0c-9f19-869a9c1aac84", diff --git a/jupyter_notebooks/06_RealSystem.ipynb b/jupyter_notebooks/06_RealSystem.ipynb index 8deeddd1e1fd9224d399e05b28c542c0ce97932c..4400929a65964484d67b86dec5f99f76f1cb5655 100644 --- a/jupyter_notebooks/06_RealSystem.ipynb +++ b/jupyter_notebooks/06_RealSystem.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "markdown", - "id": "ed9286f1-96d4-4713-8c63-d9c735c8ed63", + "id": "e38ada7d-aae2-4ff0-bd34-20d4c1bed366", "metadata": {}, "source": [ "We provide a semi-real system.\n", @@ -20,19 +20,41 @@ "We want to compute an estimation of $\\pi$.\n", "One way to do this is to use Monte-Carlo simulations.\n", "\n", - "The idea of Monte-Carlo simulations is to execute *a lot* of small **independant** simulations and compute the final result based on the results of the simulations." + "The idea of Monte-Carlo simulations is to execute **a lot of small and independant simulations** and compute the final result based on the results of the simulations.\n", + "\n", + "In our case, each simulation we draw a random number $x$ in $[-1, 1]$, and then compute (in a very inefficient way) $\\sqrt{1 - x^2}$.\n", + "\n", + "The final result is the sum of each simulation, which is an approximation of $\\int_{-1}^1 \\sqrt{1-x^2}dx = \\frac{\\pi}{2}$\n", + "\n", + "Our sensor is the `loadavg` of the machine. The `loadavg` is a metric representing the CPU utilization.\n", + "\n", + "Our actuator is the number of threads excuting simulations in parallel (between 0 and 8).\n", + "\n", + "> **Our control objective is to control the `loadavg` metric around a given value by adapting the number of threads executing simulations.**\n", + "\n", + "You can run the system with the following `docker` command:\n", + "\n", + "```sh\n", + "docker run --privileged -it -v $(pwd):/data registry.gitlab.inria.fr/control-for-computing/tutorial/system:v0.0 tuto-ctrl main.lua 1000000\n", + "```\n", + "\n", + "The `main.lua` file is the file containing the controller code, and the last parameter is the total number of iterations to do." ] }, { "cell_type": "markdown", - "id": "6d42e211-c4d6-4426-a811-2727a47d5db8", + "id": "8a1ea320-905c-4784-94ca-71c622046559", "metadata": {}, "source": [ - "You can run the system with the following `docker` command:\n", - "\n", - "```sh\n", - "docker run --privileged -it -v $(pwd):/data guilloteauq/tuto-ctrl-docker:july2022 tuto-ctrl main.lua 1000000\n", - "```" + "<div class=\"alert alert-info\" role=\"alert\">\n", + " Your tasks:\n", + " <ol>\n", + " <li>Play with the system: Try different constant inputs and see the output</li>\n", + " <li>Assuming the underlying model is a first order model: Perform the identification</li>\n", + " <li>Design a PI Controller for this systems</li>\n", + " <li>Introduce pertubations: At some point in your experiment, run `yes` in another terminal to act as a disturbance, and see how your controller reacts.\n", + " </ol> \n", + "</div>" ] }, { @@ -40,12 +62,12 @@ "id": "629824b3-eeb5-40c2-a55b-922def8fdfbd", "metadata": {}, "source": [ - "The `main.lua` file is the file containing the controller code.\n", - "\n", - "Why `lua`?\n", + "## Why `lua`?\n", "\n", "Because it is a simple, small language that integrate with `C` easily!\n", - "Instead of giving you the source code and asking you to write `C` code to implement the controller, we can just write the controller in `lua` and pass the `lua` file as an argument of the `C` binary to be loaded." + "Instead of giving you the source code and asking you to write `C` code to implement the controller, we can just write the controller in `lua` and pass the `lua` file as an argument of the `C` binary to be loaded.\n", + "\n", + "You can find a `lua` cheat sheet [here](https://devhints.io/lua)." ] }, {