Theory vs. Practice in 3D Point Transformation
How Small Measurement Errors Cause Large Calculation Errors in Real World Applications
I had to implement a simple Horizontal coordinate(elevation,azimuth,distance) to cartesian cordinate(x,y,z) convertor . Which is a simple matrix multiplication. I implemented it and was working perfectly in most cases until it was not working in some cases. In further debugging you find series of problems on how a small error in some readings causes 10 times big error in the final output. This blog is a summary on how you can still remove these errors by putting some checks and conversion.
1. Introduction: Theory vs. Practice
Mathematical formulas work in clean environments. Perfect formulas assume perfect inputs. In theory, if you measure three points on room walls, pure geometry calculates exact 3D point transformations.
Real environments are not clean. Physical tools always have measurement noise. Human operators introduce small offsets. When real measurement errors go into theoretical formulas, the math amplifies these small errors into large calculation failures.
graph TD
subgraph Theoretical_Model [Theoretical Model]
A1[Perfect Point Measurements] --> B1[Pure Geometry Formula]
B1 --> C1[Exact Point Output - 0 cm Error]
end
subgraph Real_Practice [Real World Practice]
A2[Measurement Noise - 1 cm Height Offset] --> B2[Coupling in 3D Matrix]
B2 --> C2[Amplified Point Drift - 10 cm Horizontal Error]
end
style Theoretical_Model fill:#eef2f7,stroke:#1d3557,stroke-width:2px
style Real_Practice fill:#fdf2f2,stroke:#e63946,stroke-width:2px
style C1 fill:#1d3557,color:#ffffff
style C2 fill:#e63946,color:#ffffff
2. The Original Solution: Real-World Error Analysis
The original process converts spherical point coordinates \((r, \theta, \phi)\) to 3D Cartesian coordinates \((x, y, z)\). It uses three measurement points:
- Point A & Point B: Measured on Wall 1 to establish the baseline orientation.
- Point C: Measured on a perpendicular wall to establish the room alignment.
graph LR
subgraph Spherical_Input [Spherical Inputs]
S1[Radius: r]
S2[Azimuth Angle: θ]
S3[Zenith Angle: φ]
end
subgraph Cartesian_Convert [Cartesian Conversion]
C1["x = r * sin(φ) * cos(θ)"]
C2["y = r * sin(φ) * sin(θ)"]
C3["z = r * cos(φ)"]
end
subgraph Matrix_Transform [3D Frame Transformation]
M1["u_x = normalize(p2 - p1)"]
M2["u_y = normalize(global_z × u_x)"]
M3["Translation Vector = -dot(u, origin)"]
end
S1 & S2 & S3 --> Cartesian_Convert
Cartesian_Convert --> Matrix_Transform
style Spherical_Input fill:#f8f9fa,stroke:#457b9d
style Cartesian_Convert fill:#eef2f7,stroke:#1d3557
style Matrix_Transform fill:#fff3bf,stroke:#fab005
Here is the expanded Original Solution: Matrix Generation & Real-World Error Analysis section with detailed text and diagrams explaining how the 3D transformation matrix is constructed and why real-world measurement noise breaks it.
2. The Original Solution: Matrix Generation & Error Analysis
The original system converts spherical point measurements \((r, \text{azimuth}, \text{zenith})\) into Cartesian 3D coordinates \((x, y, z)\). It uses three reference targets:
Point A & Point B: Measured along Wall 1 to define the main horizontal orientation axis.
Point C: Measured on a perpendicular wall to locate the room origin.
Step-by-Step 3D Transformation Matrix Generation
graph TD
subgraph Step_1 [1. Spherical to 3D Cartesian Conversion]
A["Point Inputs (r, azimuth, zenith)"] --> B["x = r * sin(zenith) * cos(azimuth)"]
A --> C["y = r * sin(zenith) * sin(azimuth)"]
A --> D["z = r * cos(zenith)"]
end
subgraph Step_2 [2. Establish Basis Axis Vectors]
E["Primary Baseline Vector: p2 - p1"] --> F["X-Axis Unit Vector: u_x = normalize(p2 - p1)"]
F --> G["Y-Axis Unit Vector: u_y = normalize(global_z × u_x)"]
G --> H["Z-Axis Unit Vector: u_z = cross(u_x, u_y)"]
end
subgraph Step_3 [3. Calculate 3D Translation & Assemble Matrix]
H --> I["Intersection Point (x_int, y_int, -h_device)"]
I --> J["T_x = -dot(u_x, origin_new)"]
I --> K["T_y = -dot(u_y, origin_new)"]
J & K --> L["Assemble 4x4 Homogeneous Transformation Matrix"]
end
style Step_1 fill:#eef2f7,stroke:#457b9d
style Step_2 fill:#eef2f7,stroke:#457b9d
style Step_3 fill:#fff3bf,stroke:#fab005
style L fill:#1d3557,color:#ffffff
To align all measured points with the room geometry, the original math constructs a 4x4 Homogeneous Transformation Matrix using the following steps:
Vector Orientation (\(u_x, u_y, u_z\)): The primary axis \(u_x\) is derived directly by subtracting 3D Point A from 3D Point B. \(u_y\) is created using the cross product of the global Z vector \((0, 0, 1)\) and \(u_x\). \(u_z\) is the cross product of \(u_x\) and \(u_y\).
Intersection Point (\(x_{\text{int}}, y_{\text{int}}, -h_{\text{device}}\)): The math projects lines from \(p_1 \to p_2\) and from \(p_3\) perpendicularly to find where wall alignment lines intersect on the floor plane. The device height (\(h_{\text{device}}\)) is applied to set \(z_{\text{origin}} = -h_{\text{device}}\).
3D Dot Product Translation Matrix: Translations \(T_x\) and \(T_y\) are calculated using full 3D dot products between the direction unit vectors (\(u_x, u_y\)) and the origin vector
\[T_x = -(u_{x.x} \cdot x_{\text{int}} + u_{x.y} \cdot y_{\text{int}} + u_{x.z} \cdot z_{\text{int}})\]
\[T_y = -(u_{y.x} \cdot x_{\text{int}} + u_{y.y} \cdot y_{\text{int}} + u_{y.z} \cdot z_{\text{int}})\]
\[\text{Original Matrix} = \begin{bmatrix} u_{x.x} & u_{x.y} & u_{x.z} & T_x \\ u_{y.x} & u_{y.y} & u_{y.z} & T_y \\ 0 & 0 & 1 & h_{\text{device}} \\ 0 & 0 & 0 & 1 \end{bmatrix}\]
Problem 1: Height Offset Leakage into Horizontal Coordinates
The device height (\(h_{\text{device}}\)) sets the Z-axis origin position: \(z_{\text{origin}} = -h_{\text{device}}\). The original mathematical formula projects full 3D vector dot products into X and Y coordinate translations:
\[T_x = -(u_{x.x} \cdot x_{\text{int}} + u_{x.y} \cdot y_{\text{int}} + u_{x.z} \cdot z_{\text{int}})\]
\[T_y = -(u_{y.x} \cdot x_{\text{int}} + u_{y.y} \cdot y_{\text{int}} + u_{y.z} \cdot z_{\text{int}})\]
When Wall 1 points are not perfectly level, \(u_{x.z}\) is not zero. Therefore, \(z_{\text{origin}}\) directly changes the horizontal \(T_x\) and \(T_y\) position values.
graph TD
A[Device Height Offset: Δz = 1 cm] --> B[Z Origin Component: z_int = -h_device]
B --> C["Tilted Vector Axis: u_x.z ≠ 0"]
C --> D["Translation Calculation: T_x = -(u_x.x*x + u_x.y*y + u_x.z*z)"]
D --> E[Horizontal Shift: ΔX = 10 cm Error]
style A fill:#ffe3e3,stroke:#e63946
style C fill:#ffe3e3,stroke:#e63946
style E fill:#e63946,color:#ffffff
Problem 2: Angle Amplification over Distance
A measurement tool calculates points using radius distance \(r\) and zenith angle \(\phi\):
\[z = r \cdot \cos(\phi) \quad \text{and} \quad d_{\text{horizontal}} = r \cdot \sin(\phi)\]
When a target point is far from the device (for example, \(r = 10\text{ m}\)), a small vertical error changes the effective zenith angle. The long distance acts as a leverage arm, amplifying a 1 cm height error into a 10 cm horizontal error.
graph LR
P1[Measurement Device] -- "Distance r = 10 m" --> P2[True Target Location]
P1 -- "Height Error Δz = 1 cm" --> P3[Shifted Target Location]
P2 -- "Horizontal Drift ΔX = 10 cm" --> P3
style P1 fill:#1d3557,color:#ffffff
style P2 fill:#2b9348,color:#ffffff
style P3 fill:#e63946,color:#ffffff
3. Measurement Sensitivity Table
| Measurement Input | Real World Error | Primary Affected Matrix Axis | Final Output Error |
|---|---|---|---|
| Device Height (\(h_{\text{device}}\)) | \(\pm 1.0\text{ cm}\) offset | Z-axis coupled into X-Y Translation | \(10.0\text{ cm}\) point position drift |
| Point A / B Zenith Angle | \(\pm 0.25^\circ\) sensor tilt | \(u_{x.z}\) vertical vector component | \(4.5\text{ cm}\) tilt error over \(5\text{ m}\) distance |
| Point A to B Baseline Distance | Points closer than \(0.5\text{ m}\) | \(u_x\) orientation unit vector | Severe angular drift across entire room |
4. The Robust Updated Solution
The updated solution decouples vertical height calculations from horizontal calculations using a pure 2D planar projection before constructing the transformation matrix.
graph TD
subgraph Step_1 [Step 1: Flatten Points]
S1["Convert Spherical to 3D: (x, y, z)"] --> S2["Project to 2D Floor Plane: (x, y)"]
end
subgraph Step_2 [Step 2: Pure 2D Orientation]
S2 --> S3["Calculate 2D Basis Vectors: u_x2d, u_y2d"]
S3 --> S4["Set u_z Components to 0"]
end
subgraph Step_3 [Step 3: Isolated Height Application]
S4 --> S5["Apply h_device ONLY to Matrix Row 3"]
S5 --> S6["Final 4x4 Matrix with Zero Horizontal Leakage"]
end
style Step_1 fill:#eef2f7,stroke:#457b9d
style Step_2 fill:#eef2f7,stroke:#457b9d
style Step_3 fill:#d8f3dc,stroke:#2b9348
style S6 fill:#2b9348,color:#ffffff
How the Robust Solution Fixes the Problems
- Zero Horizontal Leakage: The rotation vectors \(u_{x2d}\) and \(u_{y2d}\) have explicit Z values of zero (\(u_z = 0\)). Device height offset only affects the output Z axis.
- Baseline Validation Guard: The system checks baseline distance: \(d = \sqrt{dx^2 + dy^2}\). If \(d < 0.5\text{ m}\), calculation stops to prevent extreme sensitivity.
- Singularity Protection: The code checks vertical conditions (\(dx \approx 0\)) and horizontal conditions (\(dy \approx 0\)) directly to prevent division by zero.
5. Mathematical Matrix Comparison
Original Matrix (Coupled Errors):
\[M_{\text{original}} = \begin{bmatrix} u_{x.x} & u_{x.y} & u_{x.z} & T_x(z) \\ u_{y.x} & u_{y.y} & u_{y.z} & T_y(z) \\ 0 & 0 & 1 & h_{\text{device}} \\ 0 & 0 & 0 & 1 \end{bmatrix}\]
Robust Matrix (Decoupled Height):
\[M_{\text{robust}} = \begin{bmatrix} u_{x2d.x} & u_{x2d.y} & 0 & T_{x2d} \\ u_{y2d.x} & u_{y2d.y} & 0 & T_{y2d} \\ 0 & 0 & 1 & h_{\text{device}} \\ 0 & 0 & 0 & 1 \end{bmatrix}\]