[1]:
import sympy
Notes on PCi_j Formalism for Overlappograms#
From the PCi_j formalism, the conversion between intermediate world coordinates and pixel coordinates is given by (from Greisen and Calabretta, 2002),
or in more explicit matrix notation,
In other words, we transform our pixel coordinates \(P\) to our intermediate world coordinates \(Q\) through the transformation \(M\). This matrix \(M\) is typically referred to as the PCi_j matrix, where \(i\) indexes the world coordinates and \(j\) the pixel coordinates. \(s\) is a scalar that represents the CDELT conversion factor between pixel units and world units.
The resulting PC_ij matrix for our overlappogram assuming that the dispersion and latitude world axes are aligned with the y-like pixel axis, :math:`p_2`,
where \(\mu\) is the order of the dispersion.
In general, the dispersion axis may be oriented at some angle \(\gamma\) relative to \(p_2\). Thus, before applying \(D\), we rotate \(P\) by \(\gamma\) into \(P^\prime\) such that \(P^\prime=R(\gamma)P\) where \(R\) is the usual rotation matrix,
Lastly, we apply a rotation to align \(P^\prime\) with the intermediate world axes \(Q\) such that \(Q=R(\beta)P^\prime\). Note that this angle \(\beta\) is the relative orientation between \(P^\prime\) and \(Q\). However, we will typically be measuring the satellite roll angle relative to the original pixel axes \(P\). Thus, \(\beta=\alpha-\gamma\) where \(\alpha\) is the orientation of solar north relative to \(p_1\).
The full PC matrix can thus be written as,
which can be written explicitly as,
We can evaluate this matrix product with sympy and look at a few example cases.
[2]:
mu = sympy.symbols('mu')
gamma = sympy.symbols('gamma')
alpha = sympy.symbols('alpha')
theta = sympy.symbols('theta')
phi = sympy.symbols('phi')
rotation = sympy.Matrix([
[sympy.cos(theta), -sympy.sin(theta), 0],
[sympy.sin(theta), sympy.cos(theta), 0],
[0, 0, 1]
])
dispersion = sympy.Matrix([
[1, 0, -mu],
[0, 1, 0],
[0 ,0, 1],
])
[18]:
PC_matrix = rotation.subs(theta, (alpha-gamma)) * dispersion * rotation.subs(theta, gamma)
PC_matrix.simplify()
sympy.printing.pprint(PC_matrix)
⎡cos(α) -sin(α) -μ⋅cos(α - γ)⎤
⎢ ⎥
⎢sin(α) cos(α) -μ⋅sin(α - γ)⎥
⎢ ⎥
⎣ 0 0 1 ⎦
We can evaluate the PCi_j matrix at a few different combinations of \(\alpha,\gamma,\mu\).
[4]:
for a,g,m in [(0,0,0),
(0,0,1),
(sympy.pi/2,0,1),
(0,sympy.pi/2,1),
(sympy.pi/2,sympy.pi/2,1),
(sympy.pi/4,0,1),
(0,sympy.pi/4,1),
(sympy.pi/4,sympy.pi/4,1)]:
print(f'alpha={a}, gamma={g}, mu={m}')
print('-----------------------------')
sympy.printing.pprint(PC_matrix.subs([(alpha, a),(gamma, g),(mu, m)]))
alpha=0, gamma=0, mu=0
-----------------------------
⎡1 0 0⎤
⎢ ⎥
⎢0 1 0⎥
⎢ ⎥
⎣0 0 1⎦
alpha=0, gamma=0, mu=1
-----------------------------
⎡1 0 -1⎤
⎢ ⎥
⎢0 1 0 ⎥
⎢ ⎥
⎣0 0 1 ⎦
alpha=pi/2, gamma=0, mu=1
-----------------------------
⎡0 -1 0 ⎤
⎢ ⎥
⎢1 0 -1⎥
⎢ ⎥
⎣0 0 1 ⎦
alpha=0, gamma=pi/2, mu=1
-----------------------------
⎡1 0 0⎤
⎢ ⎥
⎢0 1 1⎥
⎢ ⎥
⎣0 0 1⎦
alpha=pi/2, gamma=pi/2, mu=1
-----------------------------
⎡0 -1 -1⎤
⎢ ⎥
⎢1 0 0 ⎥
⎢ ⎥
⎣0 0 1 ⎦
alpha=pi/4, gamma=0, mu=1
-----------------------------
⎡√2 -√2 -√2 ⎤
⎢── ──── ────⎥
⎢2 2 2 ⎥
⎢ ⎥
⎢√2 √2 -√2 ⎥
⎢── ── ────⎥
⎢2 2 2 ⎥
⎢ ⎥
⎣0 0 1 ⎦
alpha=0, gamma=pi/4, mu=1
-----------------------------
⎡ -√2 ⎤
⎢1 0 ────⎥
⎢ 2 ⎥
⎢ ⎥
⎢ √2 ⎥
⎢0 1 ── ⎥
⎢ 2 ⎥
⎢ ⎥
⎣0 0 1 ⎦
alpha=pi/4, gamma=pi/4, mu=1
-----------------------------
⎡√2 -√2 ⎤
⎢── ──── -1⎥
⎢2 2 ⎥
⎢ ⎥
⎢√2 √2 ⎥
⎢── ── 0 ⎥
⎢2 2 ⎥
⎢ ⎥
⎣0 0 1 ⎦
We can do some simple computations that shows how this transforms
[19]:
p = sympy.symarray('p', 3)
r = sympy.symarray('r', 3)
pix_coord = sympy.Matrix([
p[0] - r[0],
p[1] - r[1],
p[2] - r[2],
])
[20]:
sympy.printing.pprint(pix_coord)
⎡p₀ - r₀⎤
⎢ ⎥
⎢p₁ - r₁⎥
⎢ ⎥
⎣p₂ - r₂⎦
[21]:
world_coord = PC_matrix * pix_coord
[22]:
sympy.printing.pprint(world_coord)
⎡-μ⋅(p₂ - r₂)⋅cos(α - γ) + (p₀ - r₀)⋅cos(α) - (p₁ - r₁)⋅sin(α)⎤
⎢ ⎥
⎢-μ⋅(p₂ - r₂)⋅sin(α - γ) + (p₀ - r₀)⋅sin(α) + (p₁ - r₁)⋅cos(α)⎥
⎢ ⎥
⎣ p₂ - r₂ ⎦
[10]:
data_shape = (1073, 2000, 750)
[25]:
Q = world_coord.subs([
(alpha, 0),
(gamma, 0),
(mu, 1),
(r[0], (data_shape[2] + 1)/2),
(r[1], (data_shape[1] + 1)/2),
(r[2], 1),#(data_shape[0] + 1)/2),
])
sympy.printing.pprint(Q)
⎡p₀ - p₂ - 374.5⎤
⎢ ⎥
⎢ p₁ - 1000.5 ⎥
⎢ ⎥
⎣ p₂ - 1 ⎦
[36]:
sympy.printing.pprint(Q.subs([
(p[0], (data_shape[2] + 1)/2),
(p[1], (data_shape[1] + 1)/2),
(p[2], 100),
]))
⎡-99.0⎤
⎢ ⎥
⎢ 0 ⎥
⎢ ⎥
⎣ 99 ⎦
[ ]: