129129Construct an orthogonal collocation on finite elements [`TranscriptionMethod`](@ref).
130130
131131Also known as pseudo-spectral method. It supports continuous-time [`NonLinModel`](@ref)s
132- only. The `h` argument is the hold order for ``\m athbf{u}``, and `no` argument, the number
133- of collocation points ``n_o``. Only zero-order hold is currently implemented, so `h` must
134- be `0`. The decision variable is similar to [`MultipleShooting`](@ref), but it also includes
135- the collocation points:
132+ only. The `h` argument is the hold order for ``\m athbf{u}``, and the `no` argument, the
133+ number of collocation points ``n_o``. The decision variable is similar to [`MultipleShooting`](@ref),
134+ but it also includes the collocation points:
136135```math
137136\m athbf{Z} = \b egin{bmatrix} \m athbf{ΔU} \\ \m athbf{X̂_0} \\ \m athbf{K} \e nd{bmatrix}
138137```
@@ -187,9 +186,6 @@ struct OrthogonalCollocation <: CollocationMethod
187186 function OrthogonalCollocation (
188187 h:: Int = 0 , no:: Int = 3 ; f_threads= false , h_threads= false , roots= :gaussradau
189188 )
190- if ! (h == 0 )
191- throw (ArgumentError (" Only the zero-order hold (h=0) is currently implemented." ))
192- end
193189 if roots== :gaussradau
194190 x, _ = FastGaussQuadrature. gaussradau (no, COLLOCATION_NODE_TYPE)
195191 # we reverse the nodes to include the τ=1.0 node:
@@ -1378,6 +1374,11 @@ function con_nonlinprogeq!(
13781374 nk = get_nk (model, transcription)
13791375 D̂0 = mpc. D̂0
13801376 X̂0_Z̃ = @views Z̃[(nΔU+ 1 ): (nΔU+ nX̂)]
1377+ for j= 0 : Hp- 1 # prefilling Û0 to avoid race-condition (both û0 and û0next are needed):
1378+ x̂0_Z̃ = @views j < 1 ? mpc. estim. x̂0[1 : nx̂] : X̂0_Z̃[(1 + nx̂* (j- 1 )): (nx̂* j)]
1379+ u0, û0 = @views U0[(1 + nu* j): (nu* (j+ 1 ))], Û0[(1 + nu* j): (nu* (j+ 1 ))]
1380+ f̂_input! (û0, mpc. estim, model, x̂0_Z̃, u0)
1381+ end
13811382 @threadsif f_threads for j= 1 : Hp
13821383 if j < 2
13831384 x̂0_Z̃ = @views mpc. estim. x̂0[1 : nx̂]
@@ -1401,25 +1402,21 @@ function con_nonlinprogeq!(
14011402 fs! (x̂0next, mpc. estim, model, x̂0_Z̃)
14021403 ssnext .= @. xsnext - xsnext_Z̃
14031404 # ----------------- deterministic defects: trapezoidal collocation -------------
1404- u0 = @views U0[(1 + nu* (j- 1 )): (nu* j)]
14051405 û0 = @views Û0[(1 + nu* (j- 1 )): (nu* j)]
1406- f̂_input! (û0, mpc. estim, model, x̂0_Z̃, u0)
14071406 if f_threads || h < 1 || j < 2
14081407 # we need to recompute k1 with multi-threading, even with h==1, since the
14091408 # last iteration (j-1) may not be executed (iterations are re-orderable)
14101409 model. f! (k̇1, x0_Z̃, û0, d̂0, p)
14111410 else
14121411 k̇1 .= @views K̇[(1 + nk* (j- 1 )- nx): (nk* (j- 1 ))] # k2 of of the last iter. j-1
14131412 end
1414- if h < 1 || j ≥ Hp
1415- # j = Hp special case: u(k+Hp-1) = u(k+Hp) since Hc ≤ Hp implies Δu(k+Hp) = 0
1416- û0next = û0
1413+ if h < 1
1414+ model. f! (k̇2, x0next_Z̃, û0, d̂0next, p)
14171415 else
1418- u0next = @views U0[( 1 + nu * j) : (nu * (j + 1 ))]
1419- û0next = @views Û0[(1 + nu* j): (nu* (j+ 1 ))]
1420- f̂_input! (û0next, mpc . estim, model, x̂0next_Z̃, u0next )
1416+ # j = Hp special case: u(k+Hp-1) = u(k+Hp) since Hc≤Hp implies Δu(k+Hp) = 0:
1417+ û0next = @views j ≥ Hp ? û0 : Û0[(1 + nu* j): (nu* (j+ 1 ))]
1418+ model . f! (k̇2, x0next_Z̃, û0next, d̂0next, p )
14211419 end
1422- model. f! (k̇2, x0next_Z̃, û0next, d̂0next, p)
14231420 sdnext .= @. x0_Z̃ - x0next_Z̃ + 0.5 * Ts* (k̇1 + k̇2)
14241421 end
14251422 return geq
@@ -1456,16 +1453,21 @@ extracted from the decision variable `Z̃`. The ``\mathbf{x_0}`` vectors are the
14561453deterministic state extracted from `Z̃`. The ``\m athbf{k̇}_i`` derivative for the ``i``th
14571454collocation point is computed from the continuous-time function `model.f!` and:
14581455```math
1459- \m athbf{k̇}_i(k+j) = \m athbf{f}\B ig(\m athbf{k}_i(k+j), \m athbf{û_0 }(k+j), \m athbf{d̂}_i(k+j), \m athbf{p}\B ig)
1456+ \m athbf{k̇}_i(k+j) = \m athbf{f}\B ig(\m athbf{k}_i(k+j), \m athbf{û_i }(k+j), \m athbf{d̂}_i(k+j), \m athbf{p}\B ig)
14601457```
1461- The disturbed input `` \m athbf{û_0}(k+j) `` is defined in [`f̂_input!`](@ref). Based on the
1462- normalized time ``τ_i ∈ [0, 1]``, measured disturbances are linearly interpolated :
1458+ Based on the normalized time ``τ_i ∈ [0, 1] `` and hold order `transcription.h`, the inputs
1459+ and disturbances are piecewise constant or linear :
14631460```math
1464- \m athbf{d̂}_i(k+j) = (1-τ_i)\m athbf{d̂_0}(k+j) + τ_i\m athbf{d̂_0}(k+j+1)
1461+ \b egin{aligned}
1462+ \m athbf{û}_i(k+j) &= \b egin{cases}
1463+ \m athbf{û_0}(k+1) & h = 0 \\
1464+ (1-τ_i)\m athbf{û_0}(k+j) + τ_i\m athbf{û_0}(k+j+1) & h = 1 \e nd{cases} \\
1465+ \m athbf{d̂}_i(k+j) &= (1-τ_i)\m athbf{d̂_0}(k+j) + τ_i\m athbf{d̂_0}(k+j+1)
1466+ \e nd{aligned}
14651467```
1466- The defects for the stochastic states ``\m athbf{s_s} `` are computed as in the
1467- [`TrapezoidalCollocation`](@ref) method, and the ones for the continuity constraint of the
1468- deterministic state trajectories are given by :
1468+ The disturbed input ``\m athbf{û_0}(k+j) `` is defined in [`f̂_input!`](@ref). The defects for
1469+ the stochastic states `` \m athbf{s_s}`` are computed as the [`TrapezoidalCollocation`](@ref)
1470+ method, and the ones for the continuity constraint of the deterministic states are :
14691471```math
14701472\m athbf{s_c}(k+j+1)
14711473 = \m athbf{C_o} \b egin{bmatrix}
@@ -1483,7 +1485,7 @@ function con_nonlinprogeq!(
14831485 mpc:: PredictiveController , model:: NonLinModel , transcription:: OrthogonalCollocation ,
14841486 U0, Z̃
14851487)
1486- nu, nx̂, nd, nx = model. nu, mpc. estim. nx̂, model. nd, model. nx
1488+ nu, nx̂, nd, nx, h = model. nu, mpc. estim. nx̂, model. nd, model. nx, transcription . h
14871489 Hp, Hc = mpc. Hp, mpc. Hc
14881490 nΔU, nX̂ = nu* Hc, nx̂* Hp
14891491 f_threads = transcription. f_threads
@@ -1494,8 +1496,12 @@ function con_nonlinprogeq!(
14941496 nx̂_nk = nx̂ + nk
14951497 D̂0 = mpc. D̂0
14961498 X̂0_Z̃, K_Z̃ = @views Z̃[(nΔU+ 1 ): (nΔU+ nX̂)], Z̃[(nΔU+ nX̂+ 1 ): (nΔU+ nX̂+ nk* Hp)]
1497- di = mpc. estim. buffer. d
1498- ΔK = similar (K̇) # TODO : remove this allocation
1499+ D̂temp = mpc. buffer. D̂
1500+ for j= 0 : Hp- 1 # prefilling Û0 to avoid race-condition (both û0 and û0next are needed):
1501+ x̂0_Z̃ = @views j < 1 ? mpc. estim. x̂0[1 : nx̂] : X̂0_Z̃[(1 + nx̂* (j- 1 )): (nx̂* j)]
1502+ u0, û0 = @views U0[(1 + nu* j): (nu* (j+ 1 ))], Û0[(1 + nu* j): (nu* (j+ 1 ))]
1503+ f̂_input! (û0, mpc. estim, model, x̂0_Z̃, u0)
1504+ end
14991505 @threadsif f_threads for j= 1 : Hp
15001506 if j < 2
15011507 x̂0_Z̃ = @views mpc. estim. x̂0[1 : nx̂]
@@ -1505,7 +1511,6 @@ function con_nonlinprogeq!(
15051511 d̂0 = @views D̂0[(1 + nd* (j- 2 )): (nd* (j- 1 ))]
15061512 end
15071513 k̇ = @views K̇[(1 + nk* (j- 1 )): (nk* j)]
1508- Δk = @views ΔK[(1 + nk* (j- 1 )): (nk* j)]
15091514 k_Z̃ = @views K_Z̃[(1 + nk* (j- 1 )): (nk* j)]
15101515 d̂0next = @views D̂0[(1 + nd* (j- 1 )): (nd* j)]
15111516 x̂0next = @views X̂0[(1 + nx̂* (j- 1 )): (nx̂* j)]
@@ -1521,18 +1526,30 @@ function con_nonlinprogeq!(
15211526 fs! (x̂0next, mpc. estim, model, x̂0_Z̃)
15221527 ssnext .= @. xsnext - xsnext_Z̃
15231528 # ----------------- collocation constraint defects -----------------------------
1524- u0 = @views U0[(1 + nu* (j- 1 )): (nu* j)]
15251529 û0 = @views Û0[(1 + nu* (j- 1 )): (nu* j)]
1526- f̂_input! (û0, mpc. estim, model, x̂0_Z̃, u0)
1530+ Δk = k̇
1531+ for i= 1 : no
1532+ Δk[(1 + (i- 1 )* nx): (i* nx)] = @views k_Z̃[(1 + (i- 1 )* nx): (i* nx)] .- x0_Z̃
1533+ end
1534+ mul! (sk, Mo, Δk)
1535+ d̂i = @views D̂temp[(1 + nd* (j- 1 )): (nd* j)]
1536+ if h > 0
1537+ ûi = similar (û0) # TODO : remove this allocation
1538+ end
15271539 for i= 1 : no
15281540 k̇i = @views k̇[(1 + (i- 1 )* nx): (i* nx)]
1529- Δki = @views Δk[(1 + (i- 1 )* nx): (i* nx)]
15301541 ki_Z̃ = @views k_Z̃[(1 + (i- 1 )* nx): (i* nx)]
1531- Δki .= @. ki_Z̃ - x0_Z̃
1532- di .= (1 - τ[i]). * d̂0 .+ τ[i]. * d̂0next
1533- model. f! (k̇i, ki_Z̃, û0, d̂0, p)
1542+ d̂i .= (1 - τ[i]). * d̂0 .+ τ[i]. * d̂0next
1543+ if h < 1
1544+ model. f! (k̇i, ki_Z̃, û0, d̂i, p)
1545+ else
1546+ # j = Hp special case: u(k+Hp-1) = u(k+Hp) since Hc≤Hp implies Δu(k+Hp) = 0:
1547+ û0next = @views j ≥ Hp ? û0 : Û0[(1 + nu* j): (nu* (j+ 1 ))]
1548+ ûi .= (1 - τ[i]). * û0 .+ τ[i]. * û0next
1549+ model. f! (k̇i, ki_Z̃, ûi, d̂i, p)
1550+ end
15341551 end
1535- sk .= mul! (sk, Mo, Δk) .- k̇
1552+ sk .- = k̇
15361553 # ----------------- continuity constraint defects ------------------------------
15371554 scnext .= mul! (scnext, Co, k_Z̃) .+ (λo.* x0_Z̃) .- x0next_Z̃
15381555 end
0 commit comments