diff --git a/docs/src/index.pdf b/docs/src/index.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f30b505634a4c127328230c7947590029df662a8 Binary files /dev/null and b/docs/src/index.pdf differ diff --git a/docs/src/index.tex b/docs/src/index.tex new file mode 100644 index 0000000000000000000000000000000000000000..93040e6cf41a258dfede2fcc6f7fcc51bcbe6bb4 --- /dev/null +++ b/docs/src/index.tex @@ -0,0 +1,272 @@ +\documentclass[12pt,a4paper]{article} + +\usepackage[a4paper,text={16.5cm,25.2cm},centering]{geometry} +\usepackage{lmodern} +\usepackage{amssymb,amsmath} +\usepackage{graphicx} +\usepackage{microtype} +\usepackage{hyperref} +\setlength{\parindent}{0pt} +\setlength{\parskip}{1.2ex} + +\hypersetup + { pdfauthor = { }, + pdftitle={ }, + colorlinks=TRUE, + linkcolor=black, + citecolor=blue, + urlcolor=blue + } + + + + +\usepackage[T1]{fontenc} +\usepackage{textcomp} +\usepackage{upquote} +\usepackage{listings} +\usepackage{xcolor} +\lstset{ + basicstyle=\ttfamily\footnotesize, + upquote=true, + breaklines=true, + keepspaces=true, + showspaces=false, + columns=fullflexible, + showtabs=false, + showstringspaces=false, + escapeinside={(*@}{@*)}, + extendedchars=true, +} +\newcommand{\HLJLt}[1]{#1} +\newcommand{\HLJLw}[1]{#1} +\newcommand{\HLJLe}[1]{#1} +\newcommand{\HLJLeB}[1]{#1} +\newcommand{\HLJLo}[1]{#1} +\newcommand{\HLJLk}[1]{\textcolor[RGB]{148,91,176}{\textbf{#1}}} +\newcommand{\HLJLkc}[1]{\textcolor[RGB]{59,151,46}{\textit{#1}}} +\newcommand{\HLJLkd}[1]{\textcolor[RGB]{214,102,97}{\textit{#1}}} +\newcommand{\HLJLkn}[1]{\textcolor[RGB]{148,91,176}{\textbf{#1}}} +\newcommand{\HLJLkp}[1]{\textcolor[RGB]{148,91,176}{\textbf{#1}}} +\newcommand{\HLJLkr}[1]{\textcolor[RGB]{148,91,176}{\textbf{#1}}} +\newcommand{\HLJLkt}[1]{\textcolor[RGB]{148,91,176}{\textbf{#1}}} +\newcommand{\HLJLn}[1]{#1} +\newcommand{\HLJLna}[1]{#1} +\newcommand{\HLJLnb}[1]{#1} +\newcommand{\HLJLnbp}[1]{#1} +\newcommand{\HLJLnc}[1]{#1} +\newcommand{\HLJLncB}[1]{#1} +\newcommand{\HLJLnd}[1]{\textcolor[RGB]{214,102,97}{#1}} +\newcommand{\HLJLne}[1]{#1} +\newcommand{\HLJLneB}[1]{#1} +\newcommand{\HLJLnf}[1]{\textcolor[RGB]{66,102,213}{#1}} +\newcommand{\HLJLnfm}[1]{\textcolor[RGB]{66,102,213}{#1}} +\newcommand{\HLJLnp}[1]{#1} +\newcommand{\HLJLnl}[1]{#1} +\newcommand{\HLJLnn}[1]{#1} +\newcommand{\HLJLno}[1]{#1} +\newcommand{\HLJLnt}[1]{#1} +\newcommand{\HLJLnv}[1]{#1} +\newcommand{\HLJLnvc}[1]{#1} +\newcommand{\HLJLnvg}[1]{#1} +\newcommand{\HLJLnvi}[1]{#1} +\newcommand{\HLJLnvm}[1]{#1} +\newcommand{\HLJLl}[1]{#1} +\newcommand{\HLJLld}[1]{\textcolor[RGB]{148,91,176}{\textit{#1}}} +\newcommand{\HLJLs}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsa}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsb}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsc}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsd}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsdB}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsdC}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLse}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLsh}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsi}[1]{#1} +\newcommand{\HLJLso}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLsr}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLss}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLssB}[1]{\textcolor[RGB]{201,61,57}{#1}} +\newcommand{\HLJLnB}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLnbB}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLnfB}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLnh}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLni}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLnil}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLnoB}[1]{\textcolor[RGB]{59,151,46}{#1}} +\newcommand{\HLJLoB}[1]{\textcolor[RGB]{102,102,102}{\textbf{#1}}} +\newcommand{\HLJLow}[1]{\textcolor[RGB]{102,102,102}{\textbf{#1}}} +\newcommand{\HLJLp}[1]{#1} +\newcommand{\HLJLc}[1]{\textcolor[RGB]{153,153,119}{\textit{#1}}} +\newcommand{\HLJLch}[1]{\textcolor[RGB]{153,153,119}{\textit{#1}}} +\newcommand{\HLJLcm}[1]{\textcolor[RGB]{153,153,119}{\textit{#1}}} +\newcommand{\HLJLcp}[1]{\textcolor[RGB]{153,153,119}{\textit{#1}}} +\newcommand{\HLJLcpB}[1]{\textcolor[RGB]{153,153,119}{\textit{#1}}} +\newcommand{\HLJLcs}[1]{\textcolor[RGB]{153,153,119}{\textit{#1}}} +\newcommand{\HLJLcsB}[1]{\textcolor[RGB]{153,153,119}{\textit{#1}}} +\newcommand{\HLJLg}[1]{#1} +\newcommand{\HLJLgd}[1]{#1} +\newcommand{\HLJLge}[1]{#1} +\newcommand{\HLJLgeB}[1]{#1} +\newcommand{\HLJLgh}[1]{#1} +\newcommand{\HLJLgi}[1]{#1} +\newcommand{\HLJLgo}[1]{#1} +\newcommand{\HLJLgp}[1]{#1} +\newcommand{\HLJLgs}[1]{#1} +\newcommand{\HLJLgsB}[1]{#1} +\newcommand{\HLJLgt}[1]{#1} + + +\begin{document} + + + +\section{LabProcesses} +\begin{verbatim} +Depth = 3 +\end{verbatim} +This package contains an (programming- as well as connection-) interface to serve as a base for the implementation of lab-process software. The first example of an implementaiton of this interface is for the ball-and-beam process, which is used in Lab1 FRTN35: frequency response analysis of the beam. The lab is implemented in \href{https://gitlab.control.lth.se/processes/BallAndBeam.jl}{BallAndBeam.jl}, a package that makes use of \texttt{LabProcesses.jl} to handle the communication with the lab process and/or a simulated version thereof. This way, the code written for frequency response analysis of the beam can be run on another process implementing the same interface (or a simulated version) by changeing a single line of code :) + +\subsection{Installation} +\begin{itemize} +\item[1. ] Start julia by typing \texttt{julia} in a terminal, make sure the printed info says it's + +\end{itemize} +\texttt{v0.6+} running. If not, visit \href{https://julialang.org/downloads/}{julialang.org} to get the latest release. + +\begin{itemize} +\item[2. ] Install LabProcesses.jl using command \texttt{Pkg.clone("https://gitlab.control.lth.se/processes/LabProcesses.jl.git")} Lots of packages will now be installed, this will take some time. If this is your first time using Julia, you might have to run \texttt{julia> Pkg.init()} before you install any packages. + +\end{itemize} +\section{How to implement a new process} +\subsubsection{1.} +Locate the file \href{https://gitlab.control.lth.se/processes/LabProcesses.jl/blob/master/src/interface.jl}{interface.jl}. When the package is installed, you find its directory under \texttt{{\sim}/.julia/v0.6/LabProcesses/}, if not, run \texttt{julia> Pkg.dir("LabProcesses")} to locate the directory. (Alternatively, you can copy all definitions from \href{https://gitlab.control.lth.se/processes/LabProcesses.jl/blob/master/src/interface_implementations/ballandbeam.jl}{/interface\_implementations/ballandbeam.jl} instead. Maybe it's easier to work from an existing implementaiton.) + +\subsubsection{2.} +Copy all function definitions. + +\subsubsection{3.} +Create a new file under \texttt{/interface\_implementations} where you paste all the copied definitions and implement them. See \href{https://gitlab.control.lth.se/processes/LabProcesses.jl/blob/master/src/interface_implementations/ballandbeam.jl}{/interface\_implementations/ballandbeam.jl} for an example. + +\subsubsection{4.} +Above all function implementations you must define the process type, e.g, + +\begin{verbatim} +struct BallAndBeam <: PhysicalProcess + h::Float64 + bias::Float64 +end +BallAndBeam() = BallAndBeam(0.01, 0.0) # Constructor with default value of sample time +\end{verbatim} +Make sure you inherit from \texttt{PhysicalProcess} or \texttt{SimulatedProcess} as appropriate. This type must contains fields that hold information about everything that is relevant to a particular instance of the process. Different ballandbeam-process have different biases, hence this must be stored. A simulated process would have to keep track of its state etc. in order to implement the measure and control methods. See \href{https://docs.julialang.org/en/stable/manual/types/#Composite-Types-1}{Types in julia documentation} for additional info regarding user defined types and (constructors)[https://docs.julialang.org/en/stable/manual/constructors/]. + +\subsubsection{5.} +Documentation of all interface functions is available in the file \href{https://gitlab.control.lth.se/processes/LabProcesses.jl/blob/master/src/interface_documentation.jl}{interface\_documentation.jl} + +\section{How to control a process} +The interface \texttt{AbstractProcess} defines the functions \texttt{control(P, u)} and \texttt{measure(P)}. These functions can be used to implement your own control loops. A common loop with a feedback controller and a feedforward filter on the reference is implemented in the function \href{@ref}{\texttt{run\_control\_2DOF}}, where the user can supply $G_1$ and $G_4$ in the diagram below, with the process $P=G_2$. \begin{figure} +\centering +\includegraphics{feedback4.png} +\caption{block diagram} +\end{figure} + + +The macro \texttt{@periodically} might come in handy if you want to implement your own loop. Consider the following example, in which the loop body will be run periodically with a sample time of \texttt{h} seconds. + +\begin{verbatim} +for (i,t) = enumerate(0:h:duration) + @periodically h begin + y[i] = measure(P) + r[i] = reference(t) + u[i] = calc_control(y,r) + control(P, u[i]) + end +end +\end{verbatim} +Often one finds the need to implement a stateful controller, i.e., a function that has a memory or state. To this end, the type \href{@ref}{\texttt{SysFilter}} is provided. This type is used to implement control loops where a signal is filtered through a dynamical system, i.e., \texttt{U(z) = G1(z)E(z)}. Usage is demonstrated below, which is a simplified implementation of the block diagram above (transfer function- and signal names corresponds to the figure). First two \texttt{SysFilter} objects are created, these objects can now be used as functions of an input, and return the filtered output. The \texttt{SysFilter} type takes care of updating and remembering the state of the system when called. + +\begin{verbatim} +G1f = SysFilter(G1) +G4f = SysFilter(G4) +function calc_control(y,r) + rf = G4f(r) + e = rf-y + u = G1f(e) +end +\end{verbatim} +\texttt{G1} and \texttt{G4} must here be represented by \href{http://juliacontrol.github.io/ControlSystems.jl/latest/lib/constructors/#ControlSystems.ss}{\texttt{StateSpace}} types from \href{https://github.com/JuliaControl/ControlSystems.jl}{\texttt{ControlSystems.jl}}, e.g., \texttt{G1 = ss(A,B,C,D)}. \texttt{TransferFunction} types can easily be converted to a \texttt{StateSpace} by \texttt{Gss = ss(Gtf)}. Continuous time systems can be discretized using \texttt{Gd = c2d(Gc, h)[1]}. (The sample time of a process is available through \texttt{h = sampletime(P)}.) + +\section{How to implement a Simulated Process} +\subsection{Linear process} +This is very easy, just get a discrete time \texttt{StateSpace} model of your process (if you have a transfer function, \texttt{Gss = ss(Gtf)} will do the trick, if you have continuous time, \texttt{Gd = c2d(Gc,h)[1]} is your friend). + +You now have to implement the methods \texttt{control} and \texttt{measure} for your simulated type. The implementation for \texttt{BeamSimulator} is shown below + +\begin{verbatim} +control(p::BeamSimulator, u) = p.Gf(u) +measure(P) = vecdot(p.Gf.sys.C, p.Gf.state) +\end{verbatim} +The \texttt{control} method accepts a control signal (\texttt{u}) and propagates the system state (\texttt{p.Gf.state}) forward using the statespace model (\texttt{p.Gf.sys}) of the beam. The object \texttt{Gf} (of type \href{@ref}{\texttt{SysFilter}}) is familiar from the "Control" section above. What it does is essentially (simplified) + +\begin{verbatim} +function Gf(input) + sys = Gf.sys + Gf.state .= sys.A*Gf.state + sys.B*input + output = sys.C*Gf.state + sys.D*input +end +\end{verbatim} +hence, it just performs one iteration of + + +\begin{align} +x' = Ax + Bu +\end{align} + +\begin{align} +y = Cx + Du +\end{align} +The \texttt{measure} method performs the computation \texttt{y = Cx}, the reason for the call to \texttt{vecdot} is that \texttt{vecdot} produces a scalar output, whereas \texttt{C*x} produces a 1-element \texttt{Matrix}. A scalar output is preferred in this case since the \texttt{Beam} is SISO. + +It should now be obvious which fields are required in the \texttt{BeamSimulator} type. It must know which sample time it has been discretized with, as well as its discrete-time system model. It must also remember the current state of the system. This is not needed in a physical process since it kind of remembers its own state. The system model and its state is conveniently covered by the type \href{@ref}{\texttt{SysFilter}}, which handles filtering of a signal through an LTI system. The full type specification for \texttt{BeamSimulator} is given below + +\begin{verbatim} +struct BeamSimulator <: SimulatedProcess + h::Float64 + Gf::SysFilter + BeamSimulator() = new(0.01, SysFilter(beam_system, 0.01)) + BeamSimulator(h::Real) = new(Float64(h), SysFilter(beam_system, h)) +end +\end{verbatim} +It contains three fields and two inner constructors. The constructors initializes the system filter by creating a \href{@ref}{\texttt{SysFilter}}. The variable \texttt{beam\_system} is already defined outside the type specification. One of the constructors provides a default value for the sample time, in case the user is unsure about a reasonable value. + +\subsection{Non-linear process} +Your first option is to linearize the process and proceed like above. Other options include + +\begin{itemize} +\item[1. ] Make \texttt{control} perform forward Euler, i.e., \texttt{x[t+1] = x[t] + f(x[t],u[t])*h} for a general system model $x' = f(x,u); y = g(x,u)$ and sample time $h$. + + +\item[2. ] Integrate the system model using some fancy method like Runge-Kutta. See \href{http://docs.juliadiffeq.org/stable/types/discrete_types.html}{DifferentialEquations.jl} for discrete-time solving of ODEs (don't be discouraged, this is almost as simple as forward Euler above). + +\end{itemize} +\section{Exported functions and types} +\begin{verbatim} +Modules = [LabProcesses] +Private = false +Pages = ["LabProcesses.jl", "controllers.jl", "reference_generators.jl", "utilities.jl"] +\end{verbatim} +\section{Process interface specification} +All processes must implement the following interface. See the existing implementations in the folder \texttt{interface\_implementations} for guidance. + +\begin{verbatim} +Modules = [LabProcesses] +Private = false +Pages = ["interface_documentation.jl"] +\end{verbatim} +\section{Index} +\begin{verbatim} + +\end{verbatim} + + +\end{document}