Commit 957f11ca authored by Fredrik Bagge Carlson's avatar Fredrik Bagge Carlson
Browse files

add docs

parent 9b59712d
Pipeline #731 failed with stage
{ pdfauthor = { },
pdftitle={ },
Depth = 3
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{}{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 :)
\item[1. ] Start julia by typing \texttt{julia} in a terminal, make sure the printed info says it's
\texttt{v0.6+} running. If not, visit \href{}{} to get the latest release.
\item[2. ] Install LabProcesses.jl using command \texttt{Pkg.clone("")} 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.
\section{How to implement a new process}
Locate the file \href{}{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{}{/interface\_implementations/ballandbeam.jl} instead. Maybe it's easier to work from an existing implementaiton.)
Copy all function definitions.
Create a new file under \texttt{/interface\_implementations} where you paste all the copied definitions and implement them. See \href{}{/interface\_implementations/ballandbeam.jl} for an example.
Above all function implementations you must define the process type, e.g,
struct BallAndBeam <: PhysicalProcess
BallAndBeam() = BallAndBeam(0.01, 0.0) # Constructor with default value of sample time
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{}{Types in julia documentation} for additional info regarding user defined types and (constructors)[].
Documentation of all interface functions is available in the file \href{}{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}
\caption{block diagram}
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.
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])
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.
G1f = SysFilter(G1)
G4f = SysFilter(G4)
function calc_control(y,r)
rf = G4f(r)
e = rf-y
u = G1f(e)
\texttt{G1} and \texttt{G4} must here be represented by \href{}{\texttt{StateSpace}} types from \href{}{\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
control(p::BeamSimulator, u) = p.Gf(u)
measure(P) = vecdot(p.Gf.sys.C, p.Gf.state)
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)
function Gf(input)
sys = Gf.sys
Gf.state .= sys.A*Gf.state + sys.B*input
output = sys.C*Gf.state + sys.D*input
hence, it just performs one iteration of
x' = Ax + Bu
y = Cx + Du
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
struct BeamSimulator <: SimulatedProcess
BeamSimulator() = new(0.01, SysFilter(beam_system, 0.01))
BeamSimulator(h::Real) = new(Float64(h), SysFilter(beam_system, h))
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
\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{}{DifferentialEquations.jl} for discrete-time solving of ODEs (don't be discouraged, this is almost as simple as forward Euler above).
\section{Exported functions and types}
Modules = [LabProcesses]
Private = false
Pages = ["LabProcesses.jl", "controllers.jl", "reference_generators.jl", "utilities.jl"]
\section{Process interface specification}
All processes must implement the following interface. See the existing implementations in the folder \texttt{interface\_implementations} for guidance.
Modules = [LabProcesses]
Private = false
Pages = ["interface_documentation.jl"]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment