Skip to content

Commit 5f75cae

Browse files
committed
✨ Add conversion between CRP and MRP
1 parent c9dca2b commit 5f75cae

File tree

7 files changed

+155
-1
lines changed

7 files changed

+155
-1
lines changed

src/ReferenceFrameRotations.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ include("./conversions/angleaxis_to_quat.jl")
7171
include("./conversions/crp_to_angle.jl")
7272
include("./conversions/crp_to_angleaxis.jl")
7373
include("./conversions/crp_to_dcm.jl")
74+
include("./conversions/crp_to_mrp.jl")
7475
include("./conversions/crp_to_quat.jl")
7576
include("./conversions/api.jl")
7677
include("./conversions/dcm_to_angle.jl")
@@ -80,6 +81,7 @@ include("./conversions/dcm_to_mrp.jl")
8081
include("./conversions/dcm_to_quat.jl")
8182
include("./conversions/mrp_to_angle.jl")
8283
include("./conversions/mrp_to_angleaxis.jl")
84+
include("./conversions/mrp_to_crp.jl")
8385
include("./conversions/mrp_to_dcm.jl")
8486
include("./conversions/mrp_to_quat.jl")
8587
include("./conversions/quat_to_angle.jl")

src/conversions/crp_to_mrp.jl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
## Description #############################################################################
2+
#
3+
# Functions related to the conversion from CRP to MRP.
4+
#
5+
############################################################################################
6+
7+
export crp_to_mrp
8+
9+
"""
10+
crp_to_mrp(c::CRP) -> MRP
11+
12+
Convert CRP `c` to MRP.
13+
14+
# Examples
15+
16+
```jldoctest
17+
julia> c = CRP(0.5, 0, 0)
18+
CRP{Float64}:
19+
X : + 0.5
20+
Y : + 0.0
21+
Z : + 0.0
22+
23+
julia> crp_to_mrp(c)
24+
MRP{Float64}:
25+
X : + 0.236068
26+
Y : + 0.0
27+
Z : + 0.0
28+
```
29+
"""
30+
function crp_to_mrp(c::CRP)
31+
# Equation:
32+
# c
33+
# MRP = ─────────────────
34+
# 1 + √(1 + |c|²)
35+
#
36+
37+
c₁ = c.q1
38+
c₂ = c.q2
39+
c₃ = c.q3
40+
41+
norm_q² = c₁^2 + c₂^2 + c₃^2
42+
43+
k = 1 / (1 + (1 + norm_q²))
44+
45+
return MRP(k * c₁, k * c₂, k * c₃)
46+
end
47+

src/conversions/mrp_to_crp.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## Description #############################################################################
2+
#
3+
# Functions related to the conversion from MRP to CRP.
4+
#
5+
############################################################################################
6+
7+
export mrp_to_crp
8+
9+
"""
10+
mrp_to_crp(m::MRP) -> CRP
11+
12+
Convert MRP `m` to CRP.
13+
14+
# Examples
15+
16+
```jldoctest
17+
```
18+
"""
19+
function mrp_to_crp(m::MRP)
20+
# Equation:
21+
# 2m
22+
# CRP = ──────────
23+
# 1 - |m|²
24+
#
25+
26+
m₁ = m.q1
27+
m₂ = m.q2
28+
m₃ = m.q3
29+
30+
norm_q² = m₁^2 + m₂^2 + m₃^2
31+
32+
if isapprox(norm_q², 1; atol = 1e-15)
33+
throw(ArgumentError("The MRP represents a rotation of 180 degrees, which is a singularity for CRP."))
34+
end
35+
36+
k = 2 / (1 - norm_q²)
37+
38+
return CRP(k * m₁, k * m₂, k * m₃)
39+
end

test/conversions/crp_to_angleaxis.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@
2424
eaa = crp_to_angleaxis(c)
2525
@test eaa isa EulerAngleAxis{T}
2626

27-
@test isapprox(eaa, eaa_ref; atol = 100 * eps(T))
27+
@test isapprox(eaa, eaa_ref; atol = 1000 * eps(T))
2828
end
2929
end

test/conversions/crp_to_mrp.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## Desription ##############################################################################
2+
#
3+
# Tests related to conversion from CRP to MRP.
4+
#
5+
############################################################################################
6+
7+
# == File: ./src/conversions/crp_to_mrp.jl ================================================
8+
9+
# -- Functions: crp_to_mrp -----------------------------------------------------------------
10+
11+
@testset "CRP => MRP" begin
12+
for T in (Float32, Float64)
13+
# The conversion is tested by creating CRPs from DCMs and comparing the resulting
14+
# MRP against the one obtained directly from the same DCM.
15+
a₁ = _rand_ang(T)
16+
a₂ = _rand_ang2(T)
17+
a₃ = _rand_ang(T)
18+
19+
D = angle_to_dcm(a₃, :X) * angle_to_dcm(a₂, :Y) * angle_to_dcm(a₁, :Z)
20+
c = dcm_to_crp(D)
21+
m_ref = dcm_to_mrp(D)
22+
23+
# Convert CRP to MRP.
24+
m = crp_to_mrp(c)
25+
@test m isa MRP{T}
26+
27+
@test isapprox(m, m_ref; atol = 100 * eps(T))
28+
end
29+
end

test/conversions/mrp_to_crp.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## Desription ##############################################################################
2+
#
3+
# Tests related to conversion from MRP to CRP.
4+
#
5+
############################################################################################
6+
7+
# == File: ./src/conversions/mrp_to_crp.jl ================================================
8+
9+
# -- Functions: mrp_to_crp -----------------------------------------------------------------
10+
11+
@testset "MRP => CRP" begin
12+
for T in (Float32, Float64)
13+
# The conversion is tested by creating MRPs from DCMs and comparing the resulting
14+
# CRP against the one obtained directly from the same DCM.
15+
a₁ = _rand_ang(T)
16+
a₂ = _rand_ang2(T)
17+
a₃ = _rand_ang(T)
18+
19+
D = angle_to_dcm(a₃, :X) * angle_to_dcm(a₂, :Y) * angle_to_dcm(a₁, :Z)
20+
m = dcm_to_mrp(D)
21+
c_ref = dcm_to_crp(D)
22+
23+
# Convert MRP to CRP.
24+
c = mrp_to_crp(m)
25+
@test c isa CRP{T}
26+
27+
@test isapprox(c, c_ref; atol = 100 * eps(T), rtol = 100 * eps(T))
28+
end
29+
end
30+
31+
@testset "MRP => CRP (Singularity)" begin
32+
# A 180° rotation is a singularity for the CRP (MRP with |m| = 1).
33+
m = MRP(1.0, 0.0, 0.0)
34+
@test_throws ArgumentError mrp_to_crp(m)
35+
end

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ println("")
128128
include("./conversions/crp_to_angle.jl")
129129
include("./conversions/crp_to_angleaxis.jl")
130130
include("./conversions/crp_to_dcm.jl")
131+
include("./conversions/crp_to_mrp.jl")
131132
include("./conversions/crp_to_quat.jl")
132133
include("./conversions/dcm_to_angleaxis.jl")
133134
include("./conversions/dcm_to_angle.jl")
@@ -136,6 +137,7 @@ println("")
136137
include("./conversions/dcm_to_quaternion.jl")
137138
include("./conversions/mrp_to_angle.jl")
138139
include("./conversions/mrp_to_angleaxis.jl")
140+
include("./conversions/mrp_to_crp.jl")
139141
include("./conversions/mrp_to_dcm.jl")
140142
include("./conversions/mrp_to_quat.jl")
141143
include("./conversions/quaternion_to_angle.jl")

0 commit comments

Comments
 (0)