{ "cells": [ { "cell_type": "markdown", "source": [ "# Cyber Physical Systems Example" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Authors: Georgios Bakirtzis [https://bakirtzis.net/](https://bakirtzis.net) and Raul Gonzalez Garcia (raulg@iastate.edu)\n", "\n", "The following example is a mechanization from\n", "1. Compositional Cyber-Physical Systems Modeling - [http://dx.doi.org/10.4204/EPTCS.333.9](http://dx.doi.org/10.4204/EPTCS.333.9)\n", "2. Categorical Semantics of Cyber-Physical Systems Theory - [https://doi.org/10.1145/3461669](https://doi.org/10.1145/3461669)" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using AlgebraicDynamics\n", "using Catlab\n", "using ComponentArrays\n", "using DifferentialEquations\n", "using Plots" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "We use functorial semantics to model a cyper-physical system, namely an unmanned aerial vehicle (UAV).\n", "We define a diagram of systems (the composition syntax) that is the architecture of the composition.\n", "Then, we apply behaviors of the individual parts of the system to the architecture. This composition produces\n", "a complete UAV model." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "We first have to define our boxes and specify what the inports and outports are.\n", "For example, the sensor box has two inports `:e` and `:s` and one outport `s_prime`." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "s = Box(:sensor, [:s, :e], [:sโ€ฒ])\n", "c = Box(:controller, [:d, :sโ€ฒ], [:c])\n", "d = Box(:dynamics, [:c], [:s]);" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "A wiring diagram has outer inports and outports which define the interface of target system.\n", "Then we add the boxes and wires to the diagram and visualize the result." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "UAV = WiringDiagram([:e,:d], [:s])\n", "\n", "sensor = add_box!(UAV, s)\n", "controller = add_box!(UAV, c)\n", "dynamics = add_box!(UAV, d)\n", "\n", "add_wires!(UAV, [\n", " # net inputs\n", " (input_id(UAV), 1) => (sensor, 2),\n", " (input_id(UAV), 2) => (controller, 2),\n", "\n", " # connections\n", " (sensor, 1) => (controller, 1),\n", " (controller, 1) => (dynamics, 1),\n", " (dynamics, 1) => (sensor, 1),\n", "\n", " # net output\n", " (dynamics, 1) => (output_id(UAV), 1)\n", "]);" ], "metadata": {}, "execution_count": null }, { "outputs": [], "cell_type": "code", "source": [ "to_graphviz(UAV)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Then we assign behaviors to inhabit the boxes." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "function ๐—Ÿ(๐–)\n", " ๐ฟ(u, x, p, t) = [ -p.๐“l * (u[1] - x[1] - x[2]) ] # sc\n", " ๐ถ(u, x, p, t) = [ -p.๐“c * (u[1] + p.๐“‘c*x[1] - x[2]) ] # sl\n", " ๐ท(u, x, p, t) = ComponentArray(ฮฑ = -0.313*u[1] + 56.7*u[2] + 0.232*x[1],\n", " q = -0.013*u[1] - 0.426*u[2] + 0.0203*x[1],\n", " ฮธ = 56.7*u[2] )\n", "\n", " u_๐ฟ(u,p,t) = [ u[1] ] # outputs sl\n", " u_๐ถ(u,p,t) = [ u[1] ] # outputs sc\n", " u_๐ท(u,p,t) = [ u[3] ] # outputs ฮธ\n", "\n", " return oapply(๐–,\n", " Dict(:sensor => ContinuousMachine{Float64}(2, 1, 1, ๐ฟ, u_๐ฟ),\n", " :controller => ContinuousMachine{Float64}(2, 1, 1, ๐ถ, u_๐ถ),\n", " :dynamics => ContinuousMachine{Float64}(1, 3, 1, ๐ท, u_๐ท)))\n", "end\n", "\n", "๐‘ขแตคโ‚แตฅ = ๐—Ÿ(UAV)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Lastly, we compute and plot the solution." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "# initial values\n", "\n", "xโ‚€ = ComponentArray( e = 0.01, # [e, d] -> [ฮธ offset, ๐›ฟ control input]\n", " d = 0.05);\n", "\n", "uโ‚€ = [0.0, 0, 0, 0, 0]\n", "tspan = (0, 20.0)\n", "\n", "params = (๐“l = 100, # decay constant of sensor\n", " ๐“c = 100, # decay constant of controller\n", " ๐“‘c = 0) # ratio of velocity to reference velocity\n", "\n", "prob = ODEProblem(๐‘ขแตคโ‚แตฅ, uโ‚€, xโ‚€, tspan, params)\n", "sol = solve(prob, alg_hints=[:stiff]);" ], "metadata": {}, "execution_count": null }, { "outputs": [], "cell_type": "code", "source": [ "plot(sol, vars = [1,2, ((t,y) -> (t, y*1e2), 0, 4), 3, 5],\n", " label = [\"sl\" \"sc\" \"ฮฑ\" \"q\" \"ฮธ\"],\n", " lw = 2, title = \"Aircraft pitch behaviour\",\n", " xlabel = \"time\", ylabel = \"response\"\n", ")" ], "metadata": {}, "execution_count": null } ], "nbformat_minor": 3, "metadata": { "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.10.5" }, "kernelspec": { "name": "julia-1.10", "display_name": "Julia 1.10.5", "language": "julia" } }, "nbformat": 4 }