I agree linear error propagation can be counterintuitive, but that’s how it works.
In particular, “seeing” the partial derivatives may not be easy. Especially if you get wrong what the partial derivative is computed with respect to, as I did above. Measurements.jl
provides tools to inspect uncertainty components and derivatives (Measurements.jl
basically implements its own layman autodiff engine). For example, with
julia> Measurements.uncertainty_components.(traj)
1001-element Vector{Dict{Tuple{Float64, Float64, UInt64}, Float64}}:
Dict((1.0, 0.1, 0x0000000000000002) => 0.1)
Dict((1.0, 0.1, 0x0000000000000002) => 0.099995)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09998000025)
Dict((1.0, 0.1, 0x0000000000000002) => 0.0999550017499875)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09992000649987501)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09987501749935002)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09982003874762506)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09975507524308774)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09968013298285092)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09959521896220278)
⋮
Dict((1.0, 0.1, 0x0000000000000002) => 0.0905619112857766)
Dict((1.0, 0.1, 0x0000000000000002) => 0.09007938066876964)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08958781798716495)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08908727194562746)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08857779214959333)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08805942910035446)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08753223419005307)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08699625969658717)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08645155877842693)
Dict((1.0, 0.1, 0x0000000000000002) => 0.08589818546934296)
you can see that all elements of traj
have non-zero derivative only with respect to traj[1]
(which is the input x
to the function trajectory
, the only quantity with non-zero uncertainty, you can verify it by checking the value of the tag of traj[1]
with traj[1].tag
). Then you can compute the derivative of traj
with respect to traj[1]
with
julia> Measurements.derivative.(traj, traj[1])
1001-element Vector{Float64}:
1.0
0.99995
0.9998000025
0.999550017499875
0.99920006499875
0.9987501749935
0.9982003874762505
0.9975507524308774
0.9968013298285091
0.9959521896220277
⋮
-0.905619112857766
-0.9007938066876964
-0.8958781798716494
-0.8908727194562746
-0.8857779214959333
-0.8805942910035445
-0.8753223419005306
-0.8699625969658716
-0.8645155877842693
-0.8589818546934295
and now this makes completely sense: the error is small when the derivative with respect to traj[1]
is small, not the derivative with respect to time (the x-axis in your plot above) as I assumed above.