Search code examples
androidandroid-sensorssensormanager

How does Android's SensorManager.getRotation work (i.e. the math)?


I generally understand what it's intended to do ("Computes the inclination matrix I as well as the rotation matrix R transforming a vector from the device coordinate system to the world's coordinate system") but I don't get it how it works.

The javadoc is well written and the source is available here but I don't understand the math (for example, what is the mathematica/physical meaning of the values Hx, Hy and Hz? For example: Hx = Ey*Az - Ez*Ay). Also, what happens later in the method.

I've pasted the code from the GrepCode link above, leaving the source line numbers for easy reference. Thank you.

971     public static boolean More ...getRotationMatrix(float[] R, float[] I,
972             float[] gravity, float[] geomagnetic) {
973         // TODO: move this to native code for efficiency
974         float Ax = gravity[0];
975         float Ay = gravity[1];
976         float Az = gravity[2];
977         final float Ex = geomagnetic[0];
978         final float Ey = geomagnetic[1];
979         final float Ez = geomagnetic[2];
980         float Hx = Ey*Az - Ez*Ay;
981         float Hy = Ez*Ax - Ex*Az;
982         float Hz = Ex*Ay - Ey*Ax;
983         final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
984         if (normH < 0.1f) {
985             // device is close to free fall (or in space?), or close to
986             // magnetic north pole. Typical values are  > 100.
987             return false;
988         }
989         final float invH = 1.0f / normH;
990         Hx *= invH;
991         Hy *= invH;
992         Hz *= invH;
993         final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
994         Ax *= invA;
995         Ay *= invA;
996         Az *= invA;
997         final float Mx = Ay*Hz - Az*Hy;
998         final float My = Az*Hx - Ax*Hz;
999         final float Mz = Ax*Hy - Ay*Hx;
1000        if (R != null) {
1001            if (R.length == 9) {
1002                R[0] = Hx;     R[1] = Hy;     R[2] = Hz;
1003                R[3] = Mx;     R[4] = My;     R[5] = Mz;
1004                R[6] = Ax;     R[7] = Ay;     R[8] = Az;
1005            } else if (R.length == 16) {
1006                R[0]  = Hx;    R[1]  = Hy;    R[2]  = Hz;   R[3]  = 0;
1007                R[4]  = Mx;    R[5]  = My;    R[6]  = Mz;   R[7]  = 0;
1008                R[8]  = Ax;    R[9]  = Ay;    R[10] = Az;   R[11] = 0;
1009                R[12] = 0;     R[13] = 0;     R[14] = 0;    R[15] = 1;
1010            }
1011        }
1012        if (I != null) {
1013            // compute the inclination matrix by projecting the geomagnetic
1014            // vector onto the Z (gravity) and X (horizontal component
1015            // of geomagnetic vector) axes.
1016            final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
1017            final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
1018            final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
1019            if (I.length == 9) {
1020                I[0] = 1;     I[1] = 0;     I[2] = 0;
1021                I[3] = 0;     I[4] = c;     I[5] = s;
1022                I[6] = 0;     I[7] =-s;     I[8] = c;
1023            } else if (I.length == 16) {
1024                I[0] = 1;     I[1] = 0;     I[2] = 0;
1025                I[4] = 0;     I[5] = c;     I[6] = s;
1026                I[8] = 0;     I[9] =-s;     I[10]= c;
1027                I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
1028                I[15] = 1;
1029            }
1030        }
1031        return true;
1032    }

Solution

  • They are the cross product. The assumption is one of the param passed in the method is gravity thus is the Sky axis. The other assumption is that the magnetic param passed in lies in the North-Sky plane. Thus the cross product of these two vectors is a vector orthogonal to the North-Sky plane which is East. Now the cross product of Sky and East is a vector orthogonal to both of these which is North. Normalize all of these will give a orthonormal basis for the World coordinate.
    In the calculation above, H is East and M is North.