Skip to content

Commit 8ef11cb

Browse files
committed
Fix insane bug where @lift silently hid unitful errors
we have to use a very strange `map!` construction for observables that are supposed to hold a Union.
1 parent 9079d2a commit 8ef11cb

1 file changed

Lines changed: 68 additions & 35 deletions

File tree

bbooks/worst-case-fault-slope-pluto.jl

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
### A Pluto.jl notebook ###
2-
# v0.20.20
2+
# v0.20.21
33

44
using Markdown
55
using InteractiveUtils
@@ -28,7 +28,7 @@ begin
2828
using PlutoUI
2929
using IntervalSets
3030
using RunwayLib.StaticArrays
31-
import RunwayLib: compute_worst_case_fault_direction_and_slope
31+
import RunwayLib: compute_worst_case_fault_direction_and_slope, _uconvert
3232
end
3333

3434
# ╔═╡ 46af6473-88bf-49b9-8dc9-0a72e995f784
@@ -117,9 +117,6 @@ H0 = RunwayLib.compute_H(cam_pos, cam_rot, runway_corners)
117117
# ╔═╡ 36e1df5f-9cf1-43d1-a2a4-9e63c56ae7c8
118118
cycle(xs::AbstractVector) = xs[[eachindex(xs); first(eachindex(xs))]]
119119

120-
# ╔═╡ 59a0ab1e-0360-4d24-9320-fb3966062b9d
121-
aircraft_model = load(joinpath("assets", "A320NeoV2_lowpoly.stl"));
122-
123120
# ╔═╡ 120a3051-4909-4e65-a35d-82e76b706567
124121
function setup_corner_selections(figpos)
125122
gl = GridLayout(figpos, tellwidth = false)
@@ -197,10 +194,9 @@ lines(-100:1:100, ø->integrity_root_objective(ø, (; alphaidx, fi_indices, H=H0
197194

198195
# ╔═╡ 18ebe84e-5710-48b7-9849-130b5b55715c
199196
function get_analytic_max_error(alphaidx, fi_indices, H, px_std)
200-
@show alphaidx " FROM ANALYTIC"
201-
202-
slope_g = RunwayLib.compute_worst_case_fault_direction_and_slope(alphaidx, fi_indices, H, noise_cov)[2] * m
203-
g_wo_noise = RunwayLib.compute_worst_case_fault_direction_and_slope_wo_noise(alphaidx, fi_indices, H)[2] * m / px
197+
unit = (alphaidx <= 3 ? m : rad)
198+
slope_g = RunwayLib.compute_worst_case_fault_direction_and_slope(alphaidx, fi_indices, H, noise_cov)[2] * unit
199+
g_wo_noise = RunwayLib.compute_worst_case_fault_direction_and_slope_wo_noise(alphaidx, fi_indices, H)[2] * unit / px
204200

205201
# 2. Determine the Detection Threshold (T)
206202
# The monitor checks if SSE < T².
@@ -214,17 +210,23 @@ function get_analytic_max_error(alphaidx, fi_indices, H, px_std)
214210
sigma_val = px_std
215211
@assert isapprox(slope_g * sqrt(T_chisq), g_wo_noise * sigma_val * sqrt(T_chisq); rtol=1e-4)
216212
analytic_max_error = slope_g * sqrt(T_chisq)
213+
analytic_max_error
217214
end
218215

219216
# ╔═╡ 982214a6-fd01-4166-aefe-36f051067be2
220217
md"""
221218
## Get experimental error function
222219
"""
223220

221+
# ╔═╡ 99dc4716-4809-4581-9e62-08c95eba6885
222+
"Returns [roll, pitch, yaw] in degrees (unitful)."
223+
rpy(R::RotZYX) = uconvert.(°, reverse(params(R))*rad)
224+
225+
# ╔═╡ e7e2b951-391e-49e7-ab2b-58d5be1d22b3
226+
@assert all(rpy(RotZYX(roll=10°, pitch=5°, yaw=1°)) .== [10°, 5°, 1°])
227+
224228
# ╔═╡ 8a4de21a-acbc-4ce0-9315-6cc86376e3b1
225229
function get_experimental_max_error(alphaidx, fi_indices, H, noisy_observations, cam_pose_est)
226-
@show alphaidx
227-
@show sum(H)
228230
experimental_max_error_tpl = map([
229231
(0.0, 100.0),
230232
(-100.0, 0.0)
@@ -240,10 +242,11 @@ function get_experimental_max_error(alphaidx, fi_indices, H, noisy_observations,
240242
experimental_max_error = if alphaidx <= 3
241243
(cam_pose_est_faulty.pos - cam_pose_est.pos)[alphaidx]
242244
else
243-
reverse(params(cam_pose_est_faulty.rot) - params(cam_pose_est.rot))[alphaidx - 3]
245+
(rpy(cam_pose_est_faulty.rot) - rpy(cam_pose_est.rot))[alphaidx - 3] .|> _uconvert(rad)
244246
end
245247
experimental_max_error
246248
end |> sort
249+
experimental_max_error_tpl
247250
end
248251

249252
# ╔═╡ a5214c33-0e64-4ac2-8484-ca03bbf660ad
@@ -324,8 +327,7 @@ let
324327
analytic_max_error_3 = slope_3 * sqrt(T_chisq_3)
325328
new_sigma_val = 2.0*px
326329
@assert isapprox(analytic_max_error_3, slope_3_wo_noise * px_std * sqrt(T_chisq_3); rtol=1e-4)
327-
@show slope_3_wo_noise * new_sigma_val * sqrt(T_chisq_3), slope_3_wo_noise * old_sigma_val * sqrt(T_chisq_3)
328-
330+
329331
# 2. Calculate Experimental Max Error
330332
search_params = (;
331333
alphaidx=target_alphaidx,
@@ -483,13 +485,19 @@ function do_computations(ui, ctx)
483485
noise_cov
484486
).p_value > 0.05
485487

486-
@info "HELLO"
487-
on(alphaidx) do alphaidx
488-
@info "WORLD"
489-
@info "From the viz: $(alphaidx)"
490-
end
491-
analytic_worst_case = @lift get_analytic_max_error($alphaidx, $fi_indices, $H, ctx.px_std)
492-
experimental_worst_case = @lift get_experimental_max_error($alphaidx, $fi_indices, $H, ctx.noisy_observations, $cam_pose_est_noisy)
488+
# this is a tricky part. the result can either be of type meters, or of type radians.
489+
# however, when we create the `analytic_worst_case` observable, it tries to infer the type and drops the union,
490+
# leading to a silent error later.
491+
# We follow https://discourse.julialang.org/t/makie-observable-lift-functions/121202/6
492+
# and use `map!` to fix this.
493+
analytic_worst_case = Observable{Union{typeof(1.0m), typeof(1.0rad)}}()
494+
map!(analytic_worst_case, alphaidx, fi_indices, H) do alphaidx_, fi_indices_, H_
495+
get_analytic_max_error(alphaidx_, fi_indices_, H_, ctx.px_std)
496+
end
497+
experimental_worst_case = Observable{Union{Vector{typeof(1.0m)}, Vector{typeof(1.0rad)}}}()
498+
map!(experimental_worst_case, alphaidx, fi_indices, H, cam_pose_est_noisy) do alphaidx_, fi_indices_, H_, cam_pose_est_noisy_
499+
get_experimental_max_error(alphaidx_, fi_indices_, H_, ctx.noisy_observations, cam_pose_est_noisy_)
500+
end
493501

494502
return (; yobs_pts, yperturb_pts, yrand_pts, yfi_pts,
495503
perturbed_observations, cam_pose_est_pert,
@@ -499,7 +507,8 @@ end
499507

500508
# 3. Visualization
501509
function setup_plots(fig, ui, data, ctx)
502-
(; aircraft_model, runway_corners, true_observations) = ctx
510+
(; runway_corners, true_observations) = ctx
511+
aircraft_model = load(joinpath("assets", "A320NeoV2_lowpoly.stl"));
503512
colors = Makie.wong_colors()
504513
c1, c4, c7 = colors[1], colors[4], colors[7]
505514

@@ -512,7 +521,8 @@ function setup_plots(fig, ui, data, ctx)
512521

513522
Label(pose_delta_layout[1, 1], text=@lift(let
514523
diff = ($(data.cam_pos_est_pert) - cam_pos_est)
515-
s = repr("text/plain", round.([typeof(1.0m)], diff; digits=2))
524+
unit = (eltype(diff) <: Unitful.Length ? typeof(1.0m) : typeof(1.0°))
525+
s = repr("text/plain", round.(unit, diff; digits=2))
516526
split(s, '\n')[2:end] |> x->join(x, '\n')
517527
end), halign=:right)
518528

@@ -524,21 +534,23 @@ function setup_plots(fig, ui, data, ctx)
524534
Label(pose_delta_layout[1, 3], text="=\n=\n=", justification=:left)
525535

526536
Label(pose_delta_layout[1, 4], text=@lift(let
527-
diff = params($(data.cam_rot_est_pert)) - params($(data.cam_rot_est_noisy))
528-
s = repr("text/plain", round.([typeof(1.0°)], reverse(rad2deg.(diff.*rad)); digits=1))
537+
diff = rpy($(data.cam_rot_est_pert)) - rpy($(data.cam_rot_est_noisy))
538+
s = repr("text/plain", round.([typeof(1.0°)], diff; digits=1))
529539
split(s, '\n')[2:end] |> x->join(x, '\n')
530540
end), halign=:right)
531541

532542
## Worst case
533543
worst_case_layout = GridLayout(pose_delta_layout[0:1, 5])
534544
Label(worst_case_layout[1,1], text="Analytic Worst Case", font=:bold, halign=:left)
535-
Label(worst_case_layout[2,1], text=@lift(let
536-
worst_case_rnd = round(typeof(1.0m), $(data.analytic_worst_case); sigdigits=2)
537-
string(0m±worst_case_rnd)
538-
end), valign=:top, halign=:left)
545+
Label(worst_case_layout[2,1], text=@lift(let val = $(data.analytic_worst_case)
546+
unit = (val isa Unitful.Length ? m : °)
547+
worst_case_rnd = round(unit, val; sigdigits=2)
548+
string(0unit±worst_case_rnd)
549+
end), valign=:top, halign=:left)
539550
Label(worst_case_layout[3,1], text="Line Search Worst Case", font=:bold, halign=:left)
540-
Label(worst_case_layout[4,1], text=@lift(let
541-
worst_case_tpl = round.(typeof(1.0m), $(data.experimental_worst_case); sigdigits=2)
551+
Label(worst_case_layout[4,1], text=@lift(let vals = $(data.experimental_worst_case)
552+
unit = (first(vals) isa Unitful.Length ? m : °)
553+
worst_case_tpl = round.(unit, vals; sigdigits=2)
542554
string(worst_case_tpl[1] .. worst_case_tpl[2])
543555
end), valign=:top, halign=:left)
544556
rowgap!(worst_case_layout, 0)
@@ -589,11 +601,11 @@ function setup_plots(fig, ui, data, ctx)
589601
on(_ -> reset_limits!(ax), data.yrand_pts)
590602
on(_ -> reset_limits!(ax), data.yfi_pts)
591603
end
592-
context = (; true_observations, noisy_observations, runway_corners, cam_pos, cam_rot, aircraft_model, px_std)
604+
context = (; true_observations, noisy_observations, runway_corners, cam_pos, cam_rot, px_std)
593605
# 4. Main Orchestrator
594606
with_theme(theme_black()) do
595607
fig = Figure(; size=(1200, 600))
596-
608+
597609
ui = setup_ui(fig, context)
598610
data = do_computations(ui, context)
599611
setup_plots(fig, ui, data, context)
@@ -602,8 +614,25 @@ with_theme(theme_black()) do
602614
end
603615
end
604616

617+
# ╔═╡ f8f76174-cfd2-48a1-a8cb-3f9bc92d2d07
618+
params(RotZYX(roll=0.5, pitch=1, yaw=1.5))
619+
620+
# ╔═╡ 00d65922-f2db-4d2e-8082-4831207fbcf6
621+
let
622+
foo = Observable{Any}(1)
623+
bar::Observable{Union{Int, Float64}} = @lift (2*$(foo))
624+
foo[] = 1.5
625+
typeof(bar)
626+
end
627+
628+
# ╔═╡ 8f0d83c4-d841-4608-b42a-477f6c585da4
629+
let
630+
unit = rad
631+
0unit ± 1.5unit
632+
end
633+
605634
# ╔═╡ Cell order:
606-
# ╠═46af6473-88bf-49b9-8dc9-0a72e995f784
635+
# ╟─46af6473-88bf-49b9-8dc9-0a72e995f784
607636
# ╠═b5b8f3c8-c4dc-11f0-82e6-e3e1218a8fd8
608637
# ╟─64d2c0fd-2542-4b2c-80f6-134ed8434c3b
609638
# ╠═47423636-18d6-42cb-85e6-4a0909dc168d
@@ -619,7 +648,6 @@ end
619648
# ╠═c6a57e0f-50c7-461a-a6e8-9281991b9e44
620649
# ╠═b027b7ad-098e-4048-97d1-f4ce311c5ac4
621650
# ╠═36e1df5f-9cf1-43d1-a2a4-9e63c56ae7c8
622-
# ╠═59a0ab1e-0360-4d24-9320-fb3966062b9d
623651
# ╠═120a3051-4909-4e65-a35d-82e76b706567
624652
# ╠═b495605a-ffe7-4783-a490-1d635731da0a
625653
# ╠═58a21d5e-8a66-45b2-8202-aee966463df3
@@ -628,8 +656,13 @@ end
628656
# ╠═df5a6bf7-3f5b-4804-99de-291bdabeacdb
629657
# ╠═18ebe84e-5710-48b7-9849-130b5b55715c
630658
# ╟─982214a6-fd01-4166-aefe-36f051067be2
659+
# ╠═99dc4716-4809-4581-9e62-08c95eba6885
660+
# ╠═e7e2b951-391e-49e7-ab2b-58d5be1d22b3
631661
# ╠═8a4de21a-acbc-4ce0-9315-6cc86376e3b1
632662
# ╠═a5214c33-0e64-4ac2-8484-ca03bbf660ad
633663
# ╟─5c6760d3-7aed-4a17-a5e6-5dbf420fc6e1
634664
# ╟─76ad9899-7dd2-4795-b1b6-b44e34b747af
635665
# ╠═25348c41-f099-459c-9b19-250a66a01cab
666+
# ╠═f8f76174-cfd2-48a1-a8cb-3f9bc92d2d07
667+
# ╠═00d65922-f2db-4d2e-8082-4831207fbcf6
668+
# ╠═8f0d83c4-d841-4608-b42a-477f6c585da4

0 commit comments

Comments
 (0)