Skip to content

Commit 0120a1f

Browse files
committed
Update the code to convert DCM to quaternions
The previous version of the code, although more stable, had problems with small rotations. For example, if a DCM is constructed for small angles like: | 1 +a3 -a2 | DCM = | -a3 1 +a1 | , a1 ~ 0, a2 ~ 0, a3 ~ 0, | +a2 -a1 1 | then the old function was returning always the identity quaternion.
1 parent 5bd6b71 commit 0120a1f

File tree

1 file changed

+62
-7
lines changed

1 file changed

+62
-7
lines changed

src/DCM.jl

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,12 @@ This algorithm was obtained from:
243243
* q: (OUTPUT) Pre-allocated quaternion.
244244
* dcm: Direction Cosine Matrix that will be converted.
245245
246+
##### Remarks
247+
248+
By convention, the real part of the quaternion will always be positive.
249+
Moreover, the function does not check if `dcm` is a valid direction cosine
250+
matrix. This must be handle by the user.
251+
246252
##### Example
247253
248254
dcm = angle2dcm(pi/2,0.0,0.0,"XYZ")
@@ -254,14 +260,57 @@ This algorithm was obtained from:
254260
function dcm2quat!(q::Quaternion{T1},
255261
dcm::Array{T2,2}) where T1<:Real where T2<:Real
256262

257-
q.q0 = sqrt( max( zero(T1), one(T1) + dcm[1,1] + dcm[2,2] + dcm[3,3] ) )/2
258-
q.q1 = sqrt( max( zero(T1), one(T1) + dcm[1,1] - dcm[2,2] - dcm[3,3] ) )/2
259-
q.q2 = sqrt( max( zero(T1), one(T1) - dcm[1,1] + dcm[2,2] - dcm[3,3] ) )/2
260-
q.q3 = sqrt( max( zero(T1), one(T1) - dcm[1,1] - dcm[2,2] + dcm[3,3] ) )/2
263+
if trace(dcm) > 0
264+
# f = 4*q0
265+
f = sqrt(trace(dcm)+one(T2))*2
266+
267+
q.q0 = f/4
268+
q.q1 = (dcm[2,3]-dcm[3,2])/f
269+
q.q2 = (dcm[3,1]-dcm[1,3])/f
270+
q.q3 = (dcm[1,2]-dcm[2,1])/f
271+
elseif (dcm[1,1] > dcm[2,2]) && (dcm[1,1] > dcm[3,3])
272+
# f = 4*q1
273+
f = sqrt(one(T2) + dcm[1,1] - dcm[2,2] - dcm[3,3])*2
274+
275+
# Real part.
276+
q.q0 = (dcm[2,3]-dcm[3,2])/f
277+
278+
# Make sure that the real part is always positive.
279+
s = (q.q0 > 0) ? one(T2) : -one(T2)
280+
281+
q.q0 = s*q.q0
282+
q.q1 = s*f/4
283+
q.q2 = s*(dcm[1,2]+dcm[2,1])/f
284+
q.q3 = s*(dcm[3,1]+dcm[1,3])/f
285+
elseif (dcm[2,2] > dcm[3,3])
286+
# f = 4*q2
287+
f = sqrt(one(T2) + dcm[2,2] - dcm[1,1] - dcm[3,3])*2
288+
289+
# Real part.
290+
q.q0 = (dcm[3,1]-dcm[1,3])/f
291+
292+
# Make sure that the real part is always posiive.
293+
s = (q.q0 > 0) ? one(T2) : -one(T2)
294+
295+
q.q0 = s*q.q0
296+
q.q1 = s*(dcm[1,2]+dcm[2,1])/f
297+
q.q2 = s*f/4
298+
q.q3 = s*(dcm[3,2]+dcm[2,3])/f
299+
else
300+
# f = 4*q3
301+
f = sqrt(one(T2) + dcm[3,3] - dcm[1,1] - dcm[2,2])*2
302+
303+
# Real part.
304+
q.q0 = (dcm[1,2]-dcm[2,1])/f
261305

262-
q.q1 = copysign(q.q1, dcm[2,3] - dcm[3,2])
263-
q.q2 = copysign(q.q2, dcm[3,1] - dcm[1,3])
264-
q.q3 = copysign(q.q3, dcm[1,2] - dcm[2,1])
306+
# Make sure that the real part is always posiive.
307+
s = (q.q0 > 0) ? one(T2) : -one(T2)
308+
309+
q.q0 = s*q.q0
310+
q.q1 = s*(dcm[1,3]+dcm[3,1])/f
311+
q.q2 = s*(dcm[2,3]+dcm[3,2])/f
312+
q.q3 = s*f/4
313+
end
265314

266315
nothing
267316
end
@@ -283,6 +332,12 @@ This algorithm was obtained from:
283332
284333
* The quaternion that represents the same rotation of the `dcm`.
285334
335+
##### Remarks
336+
337+
By convention, the real part of the quaternion will always be positive.
338+
Moreover, the function does not check if `dcm` is a valid direction cosine
339+
matrix. This must be handle by the user.
340+
286341
##### Example
287342
288343
dcm = angle2dcm(pi/2,0.0,0.0,"XYZ")

0 commit comments

Comments
 (0)