{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "*This notebook contains material from [cbe30338-2021](https://jckantor.github.io/cbe30338-2021);\n", "content is available [on Github](https://github.com/jckantor/cbe30338-2021.git).*\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "< [6.0 Predictive Control](https://jckantor.github.io/cbe30338-2021/06.00-Predictive-Control.html) | [Contents](toc.html) | [Tag Index](tag_index.html) | [6.2 Simulation and Open-Loop Optimal Control](https://jckantor.github.io/cbe30338-2021/06.02-Simulation-and-Open-Loop-Optimal-Control.html) >
"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 1,
"link": "[6.1 Static Operability](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1-Static-Operability)",
"section": "6.1 Static Operability"
}
},
"source": [
"# 6.1 Static Operability\n",
"\n",
"**Static operability** refers to the ability to operate a system under steady-state conditions. We are primarily interested in determining values for the manipulable inputs that acheive a desired process target, subject to all relevant operating constraints."
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.1 State Space Model](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.1-State-Space-Model)",
"section": "6.1.1 State Space Model"
}
},
"source": [
"### 6.1.1 State Space Model"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.1 State Space Model](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.1-State-Space-Model)",
"section": "6.1.1 State Space Model"
}
},
"source": [
"The state-space model for the Temperature Control Laboratory is given by\n",
"\n",
"\\begin{align}\n",
"\\frac{dx}{dt} & = A x + B_u u + B_d d \\\\\n",
"y & = C x\n",
"\\end{align}\n",
"\n",
"where the structure of the matrix parameters and vector variables is given by\n",
"\n",
"\\begin{align}\n",
"\\frac{d}{dt}\\underbrace{\\left[\\begin{array}{c} T_{H,1} \\\\ T_{S,1} \\\\ T_{H,2} \\\\ T_{S,2} \\end{array}\\right]}_x\n",
"& = \n",
"\\underbrace{\\left[\\begin{array}{cccc}\n",
"-(\\frac{U_a+U_b+U_c}{C^H_p}) & \\frac{U_b}{C^H_p} & \\frac{U_c}{C^H_p} & 0 \\\\\n",
"\\frac{U_b}{C^S_p} & -\\frac{U_b}{C^S_p} & 0 & 0 \\\\\n",
"\\frac{U_c}{C^H_p} & 0 & -(\\frac{U_a+U_b+U_c}{C^H_p}) & \\frac{U_b}{C^H_p} \\\\\n",
"0 & 0 & \\frac{U_b}{C^S_p} & -\\frac{U_b}{C^S_p}\n",
"\\end{array}\\right]}_A\n",
"\\underbrace{\\left[\\begin{array}{c}T_{H,1} \\\\ T_{S,1} \\\\ T_{H,2} \\\\ T_{S,2}\\end{array}\\right]}_x\n",
"+\n",
"\\underbrace{\\left[\\begin{array}{cc}\\frac{\\alpha P_1}{C_p} & 0 \\\\ 0 & 0 \\\\ 0 & \\frac{\\alpha P_2}{C_p} \\\\ 0 & 0 \\end{array}\\right]}_{B_u}\n",
"\\underbrace{\\left[\\begin{array}{c}u_1 \\\\ u_2\\end{array}\\right]}_u\n",
"+\n",
"\\underbrace{\\left[\\begin{array}{c}\\frac{U_a}{C^H_p} \\\\ 0 \\\\ \\frac{U_a}{C^H_p} \\\\ 0 \\end{array}\\right]}_{B_d}\n",
"\\underbrace{\\left[\\begin{array}{c}T_{amb}\\end{array}\\right]}_{d}\n",
"\\end{align}\n",
"\n",
"\\begin{align}\n",
"\\underbrace{\\left[\\begin{array}{c} T_1 \\\\ T_2 \\end{array}\\right]}_y\n",
"& = \n",
"\\underbrace{\\left[\\begin{array}{cccc} 0 & 1 & 0 & 0 \\\\ 0 & 0 & 0 & 1 \\end{array}\\right]}_C\n",
"\\underbrace{\\left[\\begin{array}{c}T_{H,1} \\\\ T_{S,1} \\\\ T_{H,2} \\\\ T_{S,2}\\end{array}\\right]}_x\n",
"\\end{align}"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.1.1 Steady State Operability](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.1-Steady-State-Operability)",
"section": "6.1.1 Steady State Operability"
}
},
"source": [
"## 6.1.1 Steady State Operability"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.1.2 Steady State Model](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.2-Steady-State-Model)",
"section": "6.1.2 Steady State Model"
}
},
"source": [
"## 6.1.2 Steady State Model\n",
"\n",
"At steady-state our becomes\n",
"\n",
"\\begin{align}\n",
"0 & = A \\bar{x} + B_u\\bar{u} + B_d\\bar{d} \\\\\n",
"\\bar{y} & = C \\bar{x} \\\\\n",
"\\end{align}\n",
"\n",
"where the overbar $\\bar{u}$, $\\bar{x}$, and $\\bar{y}$ denote the steady-state value of $u$, $x$, and $y$, respectively. We assume $\\bar{d}$ is known."
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.2.1 Steady-State input constraints](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.2.1-Steady-State-input-constraints)",
"section": "6.1.2.1 Steady-State input constraints"
}
},
"source": [
"### 6.1.2.1 Steady-State input constraints\n",
"\n",
"The constraints on $\\bar{u}$ are given by upper and lower bounds\n",
"\n",
"\\begin{align}\n",
"0 & \\leq \\bar{u}_1 \\leq 100 \\\\\n",
"0 & \\leq \\bar{u}_2 \\leq 100 \n",
"\\end{align}\n",
"\n",
"when the values of $u_1$ and $u_2$ correspond to percentage of maximum power. "
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.2.2 Steady-State output constraints](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.2.2-Steady-State-output-constraints)",
"section": "6.1.2.2 Steady-State output constraints"
}
},
"source": [
"### 6.1.2.2 Steady-State output constraints\n",
"\n",
"We will assume there are upper limits for each of the temperature outputs\n",
"\n",
"\\begin{align}\n",
"\\bar{y}_1 & \\leq \\bar{y}_1^{max} \\\\\n",
"\\bar{y}_2 & \\leq \\bar{y}_2^{max}\n",
"\\end{align}\n",
"\n",
"when the values of $u_1$ and $u_2$ correspond to percentage of maximum power. "
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.2.3 Steady-State setpoint targets or ranges](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.2.3-Steady-State-setpoint-targets-or-ranges)",
"section": "6.1.2.3 Steady-State setpoint targets or ranges"
}
},
"source": [
"### 6.1.2.3 Steady-State setpoint targets or ranges\n",
"\n",
"The purpose of control is to find inputs $\\bar{u}_1$ and $\\bar{u}_2$ that cause the outputs to take on desired values. Those values could be specified as specific setpoints $\\bar{r}_1^{SP}$ and $\\bar{r}_2^{SP}$ in the form\n",
"\n",
"\\begin{align}\n",
"\\bar{y}_1 & = \\bar{r}_1^{SP} \\\\\n",
"\\bar{y}_2 & = \\bar{r}_2^{SP}\n",
"\\end{align}\n",
"\n",
"Alternatively, the desired operation could be specified by a range of values\n",
"\n",
"\\begin{align}\n",
"\\bar{r}_1^{min} & \\leq \\bar{y}_1 \\leq \\bar{r}_1^{max} \\\\\n",
"\\bar{r}_2^{min} & \\leq \\bar{y}_2 \\leq \\bar{r}_2^{max}\n",
"\\end{align}"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.1.3 CVXPY Solution](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.3-CVXPY-Solution)",
"section": "6.1.3 CVXPY Solution"
}
},
"source": [
"## 6.1.3 CVXPY Solution"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.3.1 Imports](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.3.1-Imports)",
"section": "6.1.3.1 Imports"
}
},
"source": [
"### 6.1.3.1 Imports"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.3.1 Imports](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.3.1-Imports)",
"section": "6.1.3.1 Imports"
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"import cvxpy as cp"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.3.2 Model Parameters](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.3.2-Model-Parameters)",
"section": "6.1.3.2 Model Parameters"
}
},
"source": [
"### 6.1.3.2 Model Parameters"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.3.2 Model Parameters](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.3.2-Model-Parameters)",
"section": "6.1.3.2 Model Parameters"
}
},
"outputs": [],
"source": [
"# parameter estimates.\n",
"alpha = 0.00016 # watts / (units P * percent U1)\n",
"P1 = 200 # P units\n",
"P2 = 100 # P units\n",
"CpH = 4.46 # heat capacity of the heater (J/deg C)\n",
"CpS = 0.819 # heat capacity of the sensor (J/deg C)\n",
"Ua = 0.050 # heat transfer coefficient from heater to environment\n",
"Ub = 0.021 # heat transfer coefficient from heater to sensor\n",
"Uc = 0.0335 # heat transfer coefficient between heaters\n",
"Tamb = 21 # ambient room temperature\n",
"\n",
"# state space model\n",
"A = np.array([[-(Ua + Ub + Uc)/CpH, Ub/CpH, Uc/CpH, 0], \n",
" [Ub/CpS, -Ub/CpS, 0, 0],\n",
" [Uc/CpH, 0, -(Ua + Ub + Uc)/CpH, Ub/CpH],\n",
" [0, 0, Ub/CpS, -Ub/CpS]])\n",
"\n",
"Bu = np.array([[alpha*P1/CpH, 0], [0, 0], [0, alpha*P2/CpH], [0, 0]])\n",
"\n",
"Bd = np.array([[Ua/CpH], [0], [Ua/CpH], [0]])\n",
"\n",
"C = np.array([[0, 1, 0, 0], [0, 0, 0, 1]])\n",
"\n",
"# initial values for states and inputs\n",
"u_initial = np.array([0, 0])\n",
"d_initial = np.array([Tamb])\n",
"x_initial = np.array([Tamb, Tamb, Tamb, Tamb])"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.3.3 CVXPY Model](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.3.3-CVXPY-Model)",
"section": "6.1.3.3 CVXPY Model"
}
},
"source": [
"### 6.1.3.3 CVXPY Model\n",
"\n",
"The following cell implements some, but not all, elements of the steady state analysis as a CVXPY optimization model."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.3.3 CVXPY Model](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.3.3-CVXPY-Model)",
"section": "6.1.3.3 CVXPY Model"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"u = [1.00000000e+02 6.51901705e-08]\n",
"x = [66.67521368 66.67521368 39.32478634 39.32478634]\n",
"y = [66.67521368 39.32478634]\n"
]
}
],
"source": [
"# knowns\n",
"d = d_initial # disturbance\n",
"r = np.array([30, 40]) # setpoints\n",
"\n",
"# unknowns to be computed\n",
"u = cp.Variable(2)\n",
"x = cp.Variable(4)\n",
"y = cp.Variable(2)\n",
"\n",
"# objective\n",
"objective = cp.Minimize(0)\n",
"\n",
"# model constraints\n",
"model_constraints = [\n",
" 0 == A@x + Bu@u + Bd@d,\n",
" y == C@x]\n",
"\n",
"# input constraints\n",
"\n",
"input_constraints = [\n",
" 0 <= u, \n",
" u <= 100]\n",
"\n",
"# output constraints\n",
"output_constraints = []\n",
"\n",
"# setpoints\n",
"r = np.array([70, 40])\n",
"setpoints = []\n",
"objective = cp.Minimize(0)\n",
"\n",
"# solve problem\n",
"constraints = model_constraints + input_constraints + output_constraints + setpoints\n",
"problem = cp.Problem(objective, constraints)\n",
"problem.solve()\n",
"\n",
"# display solution\n",
"print(f\"u = {u.value}\")\n",
"print(f\"x = {x.value}\")\n",
"print(f\"y = {y.value}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.1.4 Lab Assigment 7](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.4-Lab-Assigment-7)",
"section": "6.1.4 Lab Assigment 7"
}
},
"source": [
"## 6.1.4 Lab Assigment 7"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.4.1 Exercise 1.](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.4.1-Exercise-1.)",
"section": "6.1.4.1 Exercise 1."
}
},
"source": [
"### 6.1.4.1 Exercise 1.\n",
"\n",
"1. In the cells below, cut and paste the parameter values for matriix coefficients $A$, $B_d$, $B_u$ and $C$ to match those you previously identified for your copy of the Temperature Control Lab.\n",
"\n",
"2. Using the CVXPY outline provided above, write a Python function named `feedforward` that accepts an estimate of $T_{amb}$, and setpoints for $T1$ and $T2$, and returns values for inputs $U1$ and $U2$. The function should constrain inputs U1 and U2 to values between 0 and 100%, constrain all temperatures to values no greater than 60 deg C. Use the the power settings required to set $T1 = 45$ and $T2 = 40$. Then create a simple event loop, and test these values on your hardware. How close was your result to the predicted value?\n",
"\n",
"3. Write an optimization model to find the greatest temperature differential between $T1$ and $T2$ while limiting both to temperatures less than 60 deg C. Verify this prediction using your hardware."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.4.1 Exercise 1.](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.4.1-Exercise-1.)",
"section": "6.1.4.1 Exercise 1."
}
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"nbpages": {
"level": 3,
"link": "[6.1.4.1 Exercise 1.](https://jckantor.github.io/cbe30338-2021/06.01-Static-Operability.html#6.1.4.1-Exercise-1.)",
"section": "6.1.4.1 Exercise 1."
}
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"< [6.0 Predictive Control](https://jckantor.github.io/cbe30338-2021/06.00-Predictive-Control.html) | [Contents](toc.html) | [Tag Index](tag_index.html) | [6.2 Simulation and Open-Loop Optimal Control](https://jckantor.github.io/cbe30338-2021/06.02-Simulation-and-Open-Loop-Optimal-Control.html) >
"
]
}
],
"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.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}