JuliaPhysics / Measurements.jl

Error propagation calculator and library for physical measurements. It supports real and complex numbers with uncertainty, arbitrary precision calculations, operations with arrays, and numerical integration.

Home Page:https://juliaphysics.github.io/Measurements.jl/stable/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Weird results when combined with Quaternions.jl

dronir opened this issue · comments

I was testing out Measurements together with some orientation quaternions using Quaternions.jl. Starts out ok, but then something happens with the derivatives.

I have a function to create an orientation quaternion given an axis (a unit vector) and an angle:

using Quaternions, Measurements, LinearAlgebra

orientation(v, angle) = Quaternion(cos(0.5 * angle), sin(0.5 * angle) .* v)

Then I have a function to apply an orientation quaternion to perform a vector rotation (3-vectors are represented as quaternions with zero real part):

vec_quaternion(v) =  Quaternion(0.0, v)
rotate(q, v) = Quaternions.imag(q * vec_quaternion(v) * inv(q))

(Above, Quaternions.imag returns a 3-element Array{Float64,1} with the three imaginary components of the given quaternion.)

Using Measurements, I create an orientation that represents a 45° rotation around the Z axis, with a 1% error in the angle. Looks ok so far:

julia> q = orientation([0.0, 0.0, 1.0], π/4 * (1 ± 0.01))
Quaternion{Measurement{Float64}}(0.9239 ± 0.0015, 0.0 ± 0.0, 0.0 ± 0.0, 0.3827 ± 0.0036, false)

I apply this quaternion to rotate the X-axis unit vector. The printout also looks ok:

julia> u = rotate(q, [1.0, 0.0, 0.0])
3-element Array{Measurement{Float64},1}:
 0.7071 ± 0.0056
 0.7071 ± 0.0056
    0.0 ± 0.0   

But this resulting vector does not behave like expected:

julia> norm(u)
1.0 ± 1.1e-18
julia> u[1]^2 + u[2]^2
1.0 ± 2.2e-18
julia> u[1] + u[2]
1.414213562373095 ± 0.0

I'm not familiar with Quaternions, so I don't know what you expect.

I tried to run your code with a plain number 1 instead of 1 \pm 0.01 and I got the following:

julia> q = orientation([0.0, 0.0, 1.0], π/4 * (1))
Quaternion{Float64}(0.9238795325112867, 0.0, 0.0, 0.3826834323650898, false)

julia> u = rotate(q, [1.0, 0.0, 0.0])
3-element Array{Float64,1}:
 0.7071067811865475
 0.7071067811865476
 0.0               

julia> norm(u)
1.0

julia> u[1]^2 + u[2]^2
1.0

julia> u[1] + u[2]
1.414213562373095

so I don't really know what's wrong with what you get when using a Measurement, the nominal values are just the same. Were you expecting different uncertainties?

Wait, never mind. Now that you said that, I thought about it more, and looked at it from another angle, and those are reasonable. I was thrown off by the fact that if I do it "manually", the results are quite different, but that's of course due to the history and correlations. I blame a flu I'm currently suffering… Sorry about that.

v = [0.7071 ± 0.0056, 0.7071 ± 0.0056, 0.0 ± 0.0]
3-element Array{Measurement{Float64},1}:
 0.7071 ± 0.0056
 0.7071 ± 0.0056
    0.0 ± 0.0   

julia> norm(v)
1.0 ± 0.0056

julia> v[1]^2 + v[2]^2
1.0 ± 0.011

julia> v[1] + v[2]
1.4142 ± 0.0079

No problem, I'm glad you're finding this package useful 🙂 It's always amazing to see how easy it's in Julia to plug different packages together!

Yes, now I'm actually rather impressed by how well it works. For what it's worth, what I'm working on is a simple code that lets me integrate orientation and angular velocity using quaternions, similar to a leapfrog integrator for position and velocity. It's technically complete but I have not thoroughly tested it against analytical solutions or other codes, so I haven't really announced it anywhere, https://github.com/dronir/QuaternionIntegrator.jl