Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Controller Demos

controller_demo.md.livemd

Controller Demos

Bang-bang controller

alias VegaLite, as: Vl
import ControlLoop.BangBangController, only: :macros
alias ControlLoop.BangBangController, as: BBC

c = bb_controller(setpoint: 1, output_off: 2, output_on: 3)

x = -100..100

y =
  Enum.map(x, fn i ->
    {val, _} = BBC.update(c, i)
    val
  end)

Vl.new(width: 400, height: 400)
|> Vl.data_from_series(x: x, y: y)
|> Vl.mark(:line)
|> Vl.encode_field(:x, "x", type: :quantitative)
|> Vl.encode_field(:y, "y", type: :quantitative)

Hysteretical Bang Bang Controller

alias VegaLite, as: Vl
import ControlLoop.HystereticBangBangController, only: :macros
alias ControlLoop.HystereticBangBangController, as: HBBC

c = hbb_controller(setpoint_start: -50, setpoint_end: 50, output_off: 2, output_on: 3)

x_forward = -100..100

y_forward =
  Enum.scan(x_forward, {0, c}, fn x, {_, c} ->
    HBBC.update(c, x)
  end)
  |> Enum.map(fn {x, _} -> x end)

x_reverse = x_forward |> Enum.reverse()

y_reverse =
  Enum.scan(x_reverse, {0, c}, fn x, {_, c} ->
    HBBC.update(c, x)
  end)
  |> Enum.map(fn {x, _} -> x end)

x = Enum.concat(x_forward, x_reverse)
y = Enum.concat(y_forward, y_reverse)

Vl.new(width: 400, height: 400)
|> Vl.data_from_series(x: x, y: y)
|> Vl.mark(:point)
|> Vl.encode_field(:x, "x", type: :quantitative)
|> Vl.encode_field(:y, "y", type: :quantitative)

PID Controller

alias VegaLite, as: Vl
import ControlLoop.PIDController, only: :macros
alias ControlLoop.PIDController, as: PIDC

c = pid_controller(k_i: 1, k_d: -0.1, k_p: 0.01)

t = 0..1000 |> Enum.map(&(&1 / 100.0))
x_new = t |> Enum.map(fn _ -> 0 end)

y =
  Enum.scan(t, {0, c}, fn x, {_, c} ->
    PIDC.update(c, 1 - x, x)
  end)
  |> Enum.map(fn {x_in, _} -> x_in end)

Vl.new(width: 800, height: 400)
|> Vl.data_from_series(x: t, y: y)
|> Vl.mark(:point)
|> Vl.encode_field(:x, "x", type: :quantitative)
|> Vl.encode_field(:y, "y", type: :quantitative)