This is your resource to discuss support topics with your peers, and learn from each other.

turn on suggestions

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

- Developer Support
- :
- Application Platforms
- :
- Adobe AIR Development
- :
- Using the compass in the AIR SDK Beta 10

inside custom component

Topic Options

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic to the Top
- Bookmark
- Subscribe
- Printer Friendly Page

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-27-2012 07:57 AM - edited 06-27-2012 08:00 AM

As many of you know, I have done extensive research regarding using the magnetometer sensor in my astronomy app. I had fun implementing peter9477's "native driver" and more recently constructed my own ANE to get the job done.

I was looking forward to using the Magnetometer class in the Beta 10 SDK and was disappointed to learn that it only gives the raw output from the sensor, that is, the strength of the geomagnetic field along the x, y and z axes. In order to get an actual heading or azimuth, you need to combine the data from the magnetometer with gravitational strengths around the three axes as obtained from the accelelerometer sensor.

Fortunately, the new APIalso includes the RotationMatrix class that does the math of combining the outputs from the magnetometer and accelerometer. You should use this class instead of the Magnetometer class to get compass headings - documentation can be found here:

https://developer.blackberry.com/air/beta/apis/qnx

https://developer.blackberry.com/air/beta/apis/qnx

The rotation matrix obtained from the RotationMatrixEvent is a 9 item array of type Vector.<Number> that represents the current rotation matrix of the device. The rotation matrix takes the following form:

* / R[ 0] R[ 1] R[ 2] \

* | R[ 3] R[ 4] R[ 5] |

* \ R[ 6] R[ 7] R[ 8] /

To calculate values for azimuth, pitch and roll of the device, you need to transform the values in the matrix as follows:

* azimuth = rotation around the z axis = Math.atan2(R[1], R[4]);

* pitch = rotation around the x axis = Math.asin(-R[7]);

* roll = rotation around the y axis = Math.atan2(-R[6], R[8]);

Notes:

1. I have written my own ANE and have not actually implemented the solution presented above. I am trusting that the RotationMatrix is implemented in the SDK as described in the documentation - I welcome your feedback.

2.. The NDK has an APR event that gives you values for azimuth, pitch and roll directly. It is completely beyond me why RIM did not simply implement an ANE to send these events to the AS3 side without the need to transform the rotation matrix.

3. The above calculation will return valuse for azimuth in the range 180 degrees to -180 degrees. Negative values can be normalized to the range 0 to 360 by adding 360 degrees to the calculated value..

4. Azimuth values are relative to the "top" of the device. For example a value of 90 means that the PlayBook's media buttons are pointed due east. For the Alpha Device, "top" appears to be the short side where the camera lens is located. Your code will have to take these differences into account.

5. RIM has not yet implemented correction for magnetic declination in either the NDK or in the AIR SDK. Therefore azimuths are relative to magnetic north and not relative to true north. The difference can be several degrees depending where you are on the planet.

My Device: Playbook, Z10, Q10, Z30 with Files & Folders and Orbit of course

My Carrier: Vodafone

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-27-2012 09:11 AM

Good stuff Maurice!

MauriceRice wrote:

5. RIM has not yet implemented correction for magnetic declination in either the NDK or in the AIR SDK. Therefore azimuths are relative to magnetic north and not relative to true north. The difference can be several degrees depending where you are on the planet.

Doing this would require a GPS fix, which may not be desirable - increased power consumption, possible bad reception, delayed or failed readings etc. Better just to publish sample code of how to do the correction and let the developer decide how to handle it.

Files & Folders, the unified file & cloud manager for PlayBook and BB10 with SkyDrive, SugarSync, Box, Dropbox, Google Drive, Google Docs. Free 3-day trial! - Jon Webb - Innovatology - Utrecht, Netherlands

My Device: HTC One, PlayBook, LE Z10, DE Q10

My Carrier: Verizon

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-27-2012 09:28 AM

Since the latitude is the only thing you need to adjust the azimuth, you can have a calibrate mode, get the GPS location and store the latitude. A degree difference should not make that much of a difference while traveling.

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-27-2012 09:31 AM

Innovatology wrote:

Good stuff Maurice!

MauriceRice wrote:

5. RIM has not yet implemented correction for magnetic declination in either the NDK or in the AIR SDK. Therefore azimuths are relative to magnetic north and not relative to true north. The difference can be several degrees depending where you are on the planet.

Doing this would require a GPS fix, which may not be desirable - increased power consumption, possible bad reception, delayed or failed readings etc. Better just to publish sample code of how to do the correction and let the developer decide how to handle it.

For some apps like mine that need a geographic fix anyway, performance is a non-issue. Most civilized APIs (like RIM has provided for BBOS 7, for example) offer the programmer a choice between true bearings and magnetic. Since RIM hasn't published a complete API or even sample code, I will do my part to try to fill the void. The following code is a port of a Java class that i obtained from here:

http://www.ngdc.noaa.gov/geomag/WMM/soft.shtml

Just call the function getDeclination( lat, lon ) and you will be given the amount to add to the mag azimuth to get the true azimuth.

/*Changes by Maurice Rice Jan 15, 2012 ** Converted to AS3 ** Updated default data array to reflect WMM2010 model. ** Original notices included unchanged below */ /* class Magfield.java */ /* Module to calculate magnetic variation and field given position, ** altitude, and date ** Implements the NIMA (formerly DMA) WMM and IGRF models ** ** http://www.nima.mil/GandG/ngdc-wmm2000.html ** For WMM2000 coefficients: ** ftp://ftp.ngdc.noaa.gov/Solid_Earth/Mainfld_Mag/DoD_Model/wmm.cof ** For IGRF/DGRF coefficients: ** http://swdcdb.kugi.kyoto-u.ac.jp/igrf/coef/igrfall.d ** ** Copyright (C) 2000 Edward A Williams <Ed_Williams@compuserve.com> ** ** The routine uses a spherical harmonic expansion of the magnetic ** potential up to twelfth order, together with its time variation, as ** described in Chapter 4 of "Geomagnetism, Vol 1, Ed. J.A.Jacobs, ** Academic Press (London 1987)". The program first converts geodetic ** coordinates (lat/long on elliptic earth and altitude) to spherical ** geocentric (spherical lat/long and radius) coordinates. Using this, ** the spherical (B_r, B_theta, B_phi) magnetic field components are ** computed from the model. These are finally referred to surface (X, Y, ** Z) coordinates. ** ** Fields are accurate to better than 200nT, variation and dip to ** better than 0.5 degrees, with the exception of the declination near ** the magnetic poles (where it is ill-defined) where the error may reach ** 4 degrees or more. ** ** Variation is undefined at both the geographic and ** magnetic poles, even though the field itself is well-behaved. To ** avoid the routine blowing up, latitude entries corresponding to ** the geographic poles are slightly offset. At the magnetic poles, ** the routine returns zero variation. ** ** HISTORY ** Adapted from EAW Excel 3.0 version 3/27/94 EAW ** Recoded in C++ by Starry Chan ** WMM95 added and rearranged in ANSI-C EAW 7/9/95 ** Put shell around program and made Borland & GCC compatible EAW 11/22/95 ** IGRF95 added 2/96 EAW ** WMM2000 IGR2000 added 2/00 EAW ** Released under GPL 3/26/00 EAW ** Adaptions and modifications for the SimGear project 3/27/2000 CLO ** Removed all pow() calls and made static roots[][] arrays to ** save many sqrt() calls on subsequent invocations ** 3/28/2000 Norman Vine -- nhv@yahoo.com ** Put in some bullet-proofing to handle magnetic and geographic poles. ** 3/28/2000 EAW ** Converted to Java class ** 12/6/2000 Reece Robinson ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as ** published by the Free Software Foundation; either version 2 of the ** License, or (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, but ** WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** */ package tools { public class GeoMagField { public function GeoMagField() { loadInput(); } private static var input:Array = [ "WMM2010 2010.00 12 12 0 2010.00 2015.00 -1.0 600.0 WMM2010 0 ", "1 0 -29496.6 0.0 11.6 0.0 WMM2010 1", "1 1 -1586.3 4944.4 16.5 -25.9 WMM2010 2", "2 0 -2396.6 0.0 -12.1 0.0 WMM2010 3", "2 1 3026.1 -2707.7 -4.4 -22.5 WMM2010 4", "2 2 1668.6 -576.1 1.9 -11.8 WMM2010 5", "3 0 1340.1 0.0 0.4 0.0 WMM2010 6", "3 1 -2326.2 -160.2 -4.1 7.3 WMM2010 7", "3 2 1231.9 251.9 -2.9 -3.9 WMM2010 8", "3 3 634.0 -536.6 -7.7 -2.6 WMM2010 9", "4 0 912.6 0.0 -1.8 0.0 WMM2010 10", "4 1 808.9 286.4 2.3 1.1 WMM2010 11", "4 2 166.7 -211.2 -8.7 2.7 WMM2010 12", "4 3 -357.1 164.3 4.6 3.9 WMM2010 13", "4 4 89.4 -309.1 -2.1 -0.8 WMM2010 14", "5 0 -230.9 0.0 -1.0 0.0 WMM2010 15", "5 1 357.2 44.6 0.6 0.4 WMM2010 16", "5 2 200.3 188.9 -1.8 1.8 WMM2010 17", "5 3 -141.1 -118.2 -1.0 1.2 WMM2010 18", "5 4 -163.0 0.0 0.9 4.0 WMM2010 19", "5 5 -7.8 100.9 1.0 -0.6 WMM2010 20", "6 0 72.8 0.0 -0.2 0.0 WMM2010 21", "6 1 68.6 -20.8 -0.2 -0.2 WMM2010 22", "6 2 76.0 44.1 -0.1 -2.1 WMM2010 23", "6 3 -141.4 61.5 2.0 -0.4 WMM2010 24", "6 4 -22.8 -66.3 -1.7 -0.6 WMM2010 25", "6 5 13.2 3.1 -0.3 0.5 WMM2010 26", "6 6 -77.9 55.0 1.7 0.9 WMM2010 27", "7 0 80.5 0.0 0.1 0.0 WMM2010 28", "7 1 -75.1 -57.9 -0.1 0.7 WMM2010 29", "7 2 -4.7 -21.1 -0.6 0.3 WMM2010 30", "7 3 45.3 6.5 1.3 -0.1 WMM2010 31", "7 4 13.9 24.9 0.4 -0.1 WMM2010 32", "7 5 10.4 7.0 0.3 -0.8 WMM2010 33", "7 6 1.7 -27.7 -0.7 -0.3 WMM2010 34", "7 7 4.9 -3.3 0.6 0.3 WMM2010 35", "8 0 24.4 0.0 -0.1 0.0 WMM2010 36", "8 1 8.1 11.0 0.1 -0.1 WMM2010 37", "8 2 -14.5 -20.0 -0.6 0.2 WMM2010 38", "8 3 -5.6 11.9 0.2 0.4 WMM2010 39", "8 4 -19.3 -17.4 -0.2 0.4 WMM2010 40", "8 5 11.5 16.7 0.3 0.1 WMM2010 41", "8 6 10.9 7.0 0.3 -0.1 WMM2010 42", "8 7 -14.1 -10.8 -0.6 0.4 WMM2010 43", "8 8 -3.7 1.7 0.2 0.3 WMM2010 44", "9 0 5.4 0.0 -0.0 0.0 WMM2010 45", "9 1 9.4 -20.5 -0.1 -0.0 WMM2010 46", "9 2 3.4 11.5 0.0 -0.2 WMM2010 47", "9 3 -5.2 12.8 0.3 0.0 WMM2010 48", "9 4 3.1 -7.2 -0.4 -0.1 WMM2010 49", "9 5 -12.4 -7.4 -0.3 0.1 WMM2010 50", "9 6 -0.7 8.0 0.1 -0.0 WMM2010 51", "9 7 8.4 2.1 -0.1 -0.2 WMM2010 52", "9 8 -8.5 -6.1 -0.4 0.3 WMM2010 53", "9 9 -10.1 7.0 -0.2 0.2 WMM2010 54", "10 0 -2.0 0.0 0.0 0.0 WMM2010 55", "10 1 -6.3 2.8 -0.0 0.1 WMM2010 56", "10 2 0.9 -0.1 -0.1 -0.1 WMM2010 57", "10 3 -1.1 4.7 0.2 0.0 WMM2010 58", "10 4 -0.2 4.4 -0.0 -0.1 WMM2010 59", "10 5 2.5 -7.2 -0.1 -0.1 WMM2010 60", "10 6 -0.3 -1.0 -0.2 -0.0 WMM2010 61", "10 7 2.2 -3.9 0.0 -0.1 WMM2010 62", "10 8 3.1 -2.0 -0.1 -0.2 WMM2010 63", "10 9 -1.0 -2.0 -0.2 0.0 WMM2010 64", "10 10 -2.8 -8.3 -0.2 -0.1 WMM2010 65", "11 0 3.0 0.0 0.0 0.0 WMM2010 66", "11 1 -1.5 0.2 0.0 -0.0 WMM2010 67", "11 2 -2.1 1.7 -0.0 0.1 WMM2010 68", "11 3 1.7 -0.6 0.1 0.0 WMM2010 69", "11 4 -0.5 -1.8 -0.0 0.1 WMM2010 70", "11 5 0.5 0.9 0.0 0.0 WMM2010 71", "11 6 -0.8 -0.4 -0.0 0.1 WMM2010 72", "11 7 0.4 -2.5 -0.0 0.0 WMM2010 73", "11 8 1.8 -1.3 -0.0 -0.1 WMM2010 74", "11 9 0.1 -2.1 0.0 -0.1 WMM2010 75", "11 10 0.7 -1.9 -0.1 -0.0 WMM2010 76", "11 11 3.8 -1.8 -0.0 -0.1 WMM2010 77", "12 0 -2.2 0.0 -0.0 0.0 WMM2010 78", "12 1 -0.2 -0.9 0.0 -0.0 WMM2010 79", "12 2 0.3 0.3 0.1 0.0 WMM2010 80", "12 3 1.0 2.1 0.1 -0.0 WMM2010 81", "12 4 -0.6 -2.5 -0.1 0.0 WMM2010 82", "12 5 0.9 0.5 -0.0 -0.0 WMM2010 83", "12 6 -0.1 0.6 0.0 0.1 WMM2010 84", "12 7 0.5 -0.0 0.0 0.0 WMM2010 85", "12 8 -0.4 0.1 -0.0 0.0 WMM2010 86", "12 9 -0.4 0.3 0.0 -0.0 WMM2010 87", "12 10 0.2 -0.9 0.0 -0.0 WMM2010 88", "12 11 -0.8 -0.2 -0.1 0.0 WMM2010 89", "12 12 0.0 0.9 0.1 0.0 WMM2010 90" ]; /** * http://www.ngdc.noaa.gov/geomag/WMM/soft.shtml * Coefficient file (WMM.COF) being used **/ public var strModel:String = ""; /** * Geodetic altitude in km. An input, * but set to zero in this class. Changed * back to an input in version 5. If not specified, * then is 0. */ private var alt:Number = 0; /** * Geodetic latitude in deg. An input. */ private var glat:Number = 0; /** * Geodetic longitude in deg. An input. */ private var glon:Number = 0; /** * Time is decimal years. An input */ private var time:Number = 0; /** * Geomagnetic declination in deg. * East is positive, West is negative. * (The negative of variation.) */ private var dec:Number = 0; /** * Geomagnetic inclination in deg. * Down is positive, up is negative. */ private var dip:Number = 0; /** * Geomagnetic total intensity, in nano Teslas. */ private var ti:Number = 0; /** * Geomagnetic grid variation, referenced to * grid North. Not calculated or output in version 5.0. */ //private double gv = 0; /** * The maximum number of degrees of the spherical harmonic model. */ private var maxdeg:int = 12; /** * The maximum order of spherical harmonic model. */ private var maxord:int; private var n:int,m:int,j:int,D1:int,D2:int,D3:int,D4:int; //icomp,i, //private boolean bOutDated = false; /** * An error flag to set whether the input file with the fit * coefficients was found, and read OK. If the input file is not found, * or the data wasn't read, * it is true, and the declination, etc. is always returned as 0.0. * In version 5, this is always false, so that a calculation is always * performed. */ private var inputError:Boolean = false; /** Added in version 5. In earlier versions the date for the calculation was held as a * constant. In version 5, if no date is specified in the calulation, this date is used * by default. */ private var currentFixedDate:Number = 2011; /** Added in version 5. In earlier versions the altitude for the calculation was held as a * constant at 0. In version 5, if no altitude is specified in the calculation, this * altitude is used by default. */ private var currentFixedAltitude:Number = 0; /** * The gauss coefficients of main geomagnetic model (nt). */ //private double c[][] = new double[13][13]; private var c:Vector.<Vector.<Number>> = initVector(13,13); /** * The gauss coefficients of secular geomagnetic model (nt/yr). */ //private double cd[][] = new double[13][13]; private var cd:Vector.<Vector.<Number>> = initVector(13,13); /** * The time adjusted geomagnetic gauss coefficients (nt). */ //private double tc[][] = new double[13][13]; private var tc:Vector.<Vector.<Number>> = initVector(13,13); /** * The theta derivative of p(n,m) (unnormalized). */ //private double dp[][] = new double[13][13]; private var dp:Vector.<Vector.<Number>> = initVector(13,13); /** * The Schmidt normalization factors. */ //private double snorm[] = new double[169]; private var snorm:Vector.<Number> = new Vector.<Number>(169); /** * The sine of (m*spherical coord. longitude). */ //private double sp[] = new double[13]; private var sp:Vector.<Number> = new Vector.<Number>(13); /** * The cosine of (m*spherical coord. longitude). */ //private double cp[] = new double[13]; //private double fn[] = new double[13]; //private double fm[] = new double[13]; private var cp:Vector.<Number> = new Vector.<Number>(13); private var fn:Vector.<Number> = new Vector.<Number>(13); private var fm:Vector.<Number> = new Vector.<Number>(13); /** * The associated legendre polynomials for m=1 (unnormalized). */ //private double pp[] = new double[13]; //private double k[][] = new double[13][13]; private var pp:Vector.<Number> = new Vector.<Number>(13); private var k:Vector.<Vector.<Number>> = initVector(13,13); public var validUntil:String = ""; public var epoch:Number = 0; private var pi:Number,dtr:Number,gnm:Number,hnm:Number,dgnm:Number,dhnm:Number,flnmj:Number,otime:Number,oalt:Nu mber, olat:Number,olon:Number,d:Number,rlon:Number,rlat: Number,srlon:Number,srlat:Number,crlon:Number,crla t:Number,srlat2:Number, crlat2:Number,q:Number,q1:Number,q2:Number,ct:Numb er,st:Number,r2:Number,r:Number,dt:Number,ca:Numbe r,sa:Number,aor:Number,ar:Number,br:Number,bt:Numb er,bp:Number,bpp:Number, par:Number,temp1:Number,temp2:Number,parp:Number,b x:Number,by:Number,bz:Number,bh:Number, a:Number,b:Number,re:Number ,a2:Number,b2:Number,c2:Number,a4:Number,b4:Number , c4:Number; //Number private function initVector( size:int, col:int ): Vector.<Vector.<Number>> { var ret:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(); var n:int; var i:int; for ( n=0; n<size;n++ ){ ret[n] = new Vector.<Number>(); for (i=0; i<col; i++) { ret[n][i]=0.0; } } return ret; } private function loadInput():void{ glat = 0; glon = 0; //bOutDated = false; //String strModel = new String(); //String strFile = new String("WMM.COF"); // String strFile = new String("wmm-95.dat"); // INITIALIZE CONSTANTS maxord = maxdeg; sp[0] = 0.0; cp[0] = snorm[0] = pp[0] = 1.0; dp[0][0] = 0.0; /** * Semi-major axis of WGS-84 ellipsoid, in km. */ a = 6378.137; /** * Semi-minor axis of WGS-84 ellipsoid, in km. */ b = 6356.7523142; /** * Mean radius of IAU-66 ellipsoid, in km. */ re = 6371.2; a2 = a * a; b2 = b * b; c2 = a2 - b2; a4 = a2 * a2; b4 = b2 * b2; c4 = a4 - b4; var i:int = 0; var line:Array = String(input[0]).split( / +/ );; c[0][0] = 0.0; cd[0][0] = 0.0; epoch = line[1]; //trace("Epoch is: " + epoch); strModel = line[0]; //trace("Model is: " + strModel); //trace("Valid to: " + line[6]); validUntil = line[6]; for( i=1; i<input.length; i++) { line = String(input[i]).split( / +/ ); n = line[0]; m = line[1]; gnm = line[2]; hnm = line[3]; dgnm = line[4]; dhnm = line[5]; if (m <= n) { c[m][n] = gnm; cd[m][n] = dgnm; if (m != 0) { c[n][m-1] = hnm; cd[n][m-1] = dhnm; } } } // CONVERT SCHMIDT NORMALIZED GAUSS COEFFICIENTS TO UNNORMALIZED snorm[0] = 1.0; for (n = 1; n <= maxord; n++){ snorm[n] = snorm[n - 1] * (2 * n - 1) / n; j = 2; for(m = 0,D1 = 1,D2 = (n - m + D1) / D1; D2 > 0; D2--, m += D1){ k[m][n] = (((n - 1) * (n - 1))-(m * m))/ ((2 * n-1)*(2*n-3)); if(m > 0){ flnmj = ((n - m + 1) * j) / (n + m); snorm[n + m * 13] = snorm[n + (m -1 ) * 13] * Math.sqrt(flnmj); j = 1; c[n][m-1] = snorm[n + m * 13] * c[n][m-1]; cd[n][m-1] = snorm[n + m * 13] * cd[n][m-1]; } c[m][n] = snorm[n + m * 13] * c[m][n]; cd[m][n] = snorm[n + m * 13] * cd[m][n]; } //for(m...) fn[n] = (n+1); fm[n] = n; } //for(n...) k[1][1] = 0.0; otime = oalt = olat = olon = -1000.0; } /** PURPOSE: THIS ROUTINE COMPUTES THE DECLINATION (DEC), * INCLINATION (DIP), TOTAL INTENSITY (TI) AND * GRID VARIATION (GV - POLAR REGIONS ONLY, REFERENCED * TO GRID NORTH OF POLAR STEREOGRAPHIC PROJECTION) OF * THE EARTH'S MAGNETIC FIELD IN GEODETIC COORDINATES * FROM THE COEFFICIENTS OF THE CURRENT OFFICIAL * DEPARTMENT OF DEFENSE (DOD) SPHERICAL HARMONIC WORLD * MAGNETIC MODEL (WMM-2000). THE WMM SERIES OF MODELS IS * UPDATED EVERY 5 YEARS ON JANUARY 1'ST OF THOSE YEARS * WHICH ARE DIVISIBLE BY 5 (I.E. 1980, 1985, 1990 ETC.) * BY THE NAVAL OCEANOGRAPHIC OFFICE IN COOPERATION * WITH THE BRITISH GEOLOGICAL SURVEY (BGS). THE MODEL * IS BASED ON GEOMAGNETIC SURVEY MEASUREMENTS FROM * AIRCRAFT, SATELLITE AND GEOMAGNETIC OBSERVATORIES. * * * * ACCURACY: IN OCEAN AREAS AT THE EARTH'S SURFACE OVER THE * ENTIRE 5 YEAR LIFE OF A DEGREE AND ORDER 12 * SPHERICAL HARMONIC MODEL SUCH AS WMM-95, THE ESTIMATED * RMS ERRORS FOR THE VARIOUS MAGENTIC COMPONENTS ARE: * * DEC - 0.5 Degrees * DIP - 0.5 Degrees * TI - 280.0 nanoTeslas (nT) * GV - 0.5 Degrees * * OTHER MAGNETIC COMPONENTS THAT CAN BE DERIVED FROM * THESE FOUR BY SIMPLE TRIGONOMETRIC RELATIONS WILL * HAVE THE FOLLOWING APPROXIMATE ERRORS OVER OCEAN AREAS: * * X - 140 nT (North) * Y - 140 nT (East) * Z - 200 nT (Vertical) Positive is down * H - 200 nT (Horizontal) * * OVER LAND THE RMS ERRORS ARE EXPECTED TO BE SOMEWHAT * HIGHER, ALTHOUGH THE RMS ERRORS FOR DEC, DIP AND GV * ARE STILL ESTIMATED TO BE LESS THAN 0.5 DEGREE, FOR * THE ENTIRE 5-YEAR LIFE OF THE MODEL AT THE EARTH's * SURFACE. THE OTHER COMPONENT ERRORS OVER LAND ARE * MORE DIFFICULT TO ESTIMATE AND SO ARE NOT GIVEN. * * THE ACCURACY AT ANY GIVEN TIME OF ALL FOUR * GEOMAGNETIC PARAMETERS DEPENDS ON THE GEOMAGNETIC * LATITUDE. THE ERRORS ARE LEAST AT THE EQUATOR AND * GREATEST AT THE MAGNETIC POLES. * * IT IS VERY IMPORTANT TO NOTE THAT A DEGREE AND * ORDER 12 MODEL, SUCH AS WMM-2000 DESCRIBES ONLY * THE LONG WAVELENGTH SPATIAL MAGNETIC FLUCTUATIONS * DUE TO EARTH'S CORE. NOT INCLUDED IN THE WMM SERIES * MODELS ARE INTERMEDIATE AND SHORT WAVELENGTH * SPATIAL FLUCTUATIONS OF THE GEOMAGNETIC FIELD * WHICH ORIGINATE IN THE EARTH'S MANTLE AND CRUST. * CONSEQUENTLY, ISOLATED ANGULAR ERRORS AT VARIOUS * POSITIONS ON THE SURFACE (PRIMARILY OVER LAND, IN * CONTINENTAL MARGINS AND OVER OCEANIC SEAMOUNTS, * RIDGES AND TRENCHES) OF SEVERAL DEGREES MAY BE * EXPECTED. ALSO NOT INCLUDED IN THE MODEL ARE * NONSECULAR TEMPORAL FLUCTUATIONS OF THE GEOMAGNETIC * FIELD OF MAGNETOSPHERIC AND IONOSPHERIC ORIGIN. * DURING MAGNETIC STORMS, TEMPORAL FLUCTUATIONS CAN * CAUSE SUBSTANTIAL DEVIATIONS OF THE GEOMAGNETIC * FIELD FROM MODEL VALUES. IN ARCTIC AND ANTARCTIC * REGIONS, AS WELL AS IN EQUATORIAL REGIONS, DEVIATIONS * FROM MODEL VALUES ARE BOTH FREQUENT AND PERSISTENT. * * IF THE REQUIRED DECLINATION ACCURACY IS MORE * STRINGENT THAN THE WMM SERIES OF MODELS PROVIDE, THEN * THE USER IS ADVISED TO REQUEST SPECIAL (REGIONAL OR * LOCAL) SURVEYS BE PERFORMED AND MODELS PREPARED BY * THE USGS, WHICH OPERATES THE US GEOMAGNETIC * OBSERVATORIES. REQUESTS OF THIS NATURE SHOULD * BE MADE THROUGH NIMA AT THE ADDRESS ABOVE. * * * * NOTE: THIS VERSION OF GEOMAG USES THE WMM-2005 GEOMAGNETIC * MODEL REFERENCED TO THE WGS-84 GRAVITY MODEL ELLIPSOID * * @param fLat The latitude in decimal degrees. * @param fLon The longitude in decimal degrees. * @param year The date as a decimal year. * @param altitude The altitude in kilometers. */ // void CalcGeoMag(double fLat, double fLon, double fAlt, double fTime, boolean bCurrent) private function calcGeoMag( fLat:Number, fLon:Number, year:Number, altitude:Number):void { glat = fLat; glon = fLon; //alt = fAlt; alt = altitude; //time = fTime; /** * The date in decimal years for calculating the magnetic field components. */ time = year; dt = time - epoch; //if (otime < 0.0 && (dt < 0.0 || dt > 5.0)) // if(bCurrent){ // if (dt < 0.0 || dt > 5.0) // bOutDated = true; // else // bOutDated = false; // } pi = 3.14159265359; // could be replaced by Math.PI dtr = (pi/180.0); rlon = glon * dtr; rlat = glat * dtr; srlon = Math.sin(rlon); srlat = Math.sin(rlat); crlon = Math.cos(rlon); crlat = Math.cos(rlat); srlat2 = srlat * srlat; crlat2 = crlat * crlat; sp[1] = srlon; cp[1] = crlon; // CONVERT FROM GEODETIC COORDS. TO SPHERICAL COORDS. if (alt != oalt || glat != olat){ q = Math.sqrt(a2 - c2 * srlat2); q1 = alt * q; q2 = ((q1 + a2) / (q1 + b2)) * ((q1 + a2) / (q1 + b2)); ct = srlat / Math.sqrt(q2 * crlat2 + srlat2); st = Math.sqrt(1.0 - (ct * ct)); r2 = ((alt*alt) + 2.0 * q1 + (a4 - c4 * srlat2) / (q * q)); r = Math.sqrt(r2); d = Math.sqrt(a2 * crlat2 + b2 * srlat2); ca = (alt + d) / r; sa = c2 * crlat * srlat / (r * d); } if (glon != olon){ for (m = 2; m <= maxord; m++){ sp[m] = sp[1] * cp[m-1] + cp[1] * sp[m-1]; cp[m] = cp[1] * cp[m-1] - sp[1] * sp[m-1]; } } aor = re / r; ar = aor * aor; br = bt = bp = bpp = 0.0; for(n = 1; n <= maxord; n++){ ar = ar * aor; for (m = 0,D3 = 1,D4 = (n + m + D3) / D3; D4 > 0; D4--,m += D3){ //COMPUTE UNNORMALIZED ASSOCIATED LEGENDRE POLYNOMIALS //AND DERIVATIVES VIA RECURSION RELATIONS if(alt != oalt || glat != olat){ if(n == m){ snorm[n + m * 13] = st * snorm[n - 1 + (m - 1) * 13]; dp[m][n] = st * dp[m-1][n-1]+ ct* snorm[n - 1 + (m - 1) * 13]; } if(n == 1 && m == 0){ snorm[n + m * 13] = ct * snorm[n - 1 + m * 13]; dp[m][n] = ct * dp[m][n - 1] - st * snorm[n - 1 + m * 13]; } if(n > 1 && n != m){ if(m > n - 2) snorm[n - 2 + m * 13] = 0.0; if(m > n - 2) dp[m][n - 2] = 0.0; snorm[n + m * 13] = ct * snorm[n - 1 + m * 13] - k[m][n] * snorm[n - 2 + m * 13]; dp[m][n] = ct * dp[m][n - 1] - st * snorm[n - 1 + m * 13] - k[m][n] * dp[m][n - 2]; } } //TIME ADJUST THE GAUSS COEFFICIENTS if(time != otime){ tc[m][n] = c[m][n] + dt * cd[m][n]; if(m != 0) tc[n][m - 1] = c[n][m - 1]+ dt * cd[n][m - 1]; } //ACCUMULATE TERMS OF THE SPHERICAL HARMONIC EXPANSIONS par = ar * snorm[ n + m * 13]; if(m == 0){ temp1 = tc[m][n] * cp[m]; temp2 = tc[m][n] * sp[m]; } else{ temp1 = tc[m][n] * cp[m] + tc[n][m - 1] * sp[m]; temp2 = tc[m][n] * sp[m] - tc[n][m - 1] * cp[m]; } bt = bt - ar * temp1 * dp[m][n]; bp += (fm[m] * temp2 * par); br += (fn[n] * temp1 * par); //SPECIAL CASE: NORTH/SOUTH GEOGRAPHIC POLES if(st == 0.0 && m == 1){ if(n == 1) pp[n] = pp[n - 1]; else pp[n] = ct * pp[n - 1] - k[m][n] * pp[n - 2]; parp = ar * pp[n]; bpp += (fm[m] * temp2 * parp); } } //for(m...) } //for(n...) if(st == 0.0) bp = bpp; else bp /= st; //ROTATE MAGNETIC VECTOR COMPONENTS FROM SPHERICAL TO //GEODETIC COORDINATES // bx must be the east-west field component // by must be the north-south field component // bx must be the vertical field component. bx = -bt * ca - br * sa; by = bp; bz = bt * sa - br * ca; //COMPUTE DECLINATION (DEC), INCLINATION (DIP) AND //TOTAL INTENSITY (TI) bh = Math.sqrt((bx * bx)+(by * by)); ti = Math.sqrt((bh * bh)+(bz * bz)); // Calculate the declination. dec = (Math.atan2(by, bx) / dtr); //System.out.println( "Dec is: " + dec ); dip = (Math.atan2(bz, bh) / dtr); // This is the variation for grid navigation. // Not used at this time. See St. Ledger for explanation. //COMPUTE MAGNETIC GRID VARIATION IF THE CURRENT //GEODETIC POSITION IS IN THE ARCTIC OR ANTARCTIC //(I.E. GLAT > +55 DEGREES OR GLAT < -55 DEGREES) // Grid North is referenced to the 0 Meridian of a polar // stereographic projection. //OTHERWISE, SET MAGNETIC GRID VARIATION TO -999.0 /* gv = -999.0; if (Math.abs(glat) >= 55.){ if (glat > 0.0 && glon >= 0.0) gv = dec-glon; if (glat > 0.0 && glon < 0.0) gv = dec + Math.abs(glon); if (glat < 0.0 && glon >= 0.0) gv = dec+glon; if (glat < 0.0 && glon < 0.0) gv = dec - Math.abs(glon); if (gv > +180.0) gv -= 360.0; if (gv < -180.0) gv += 360.0; } */ otime = time; oalt = alt; olat = glat; olon = glon; } /** * Returns the declination from the 2005 Department of * Defense geomagnetic model and data, in degrees. The * magnetic heading + declination = true heading. * (True heading + variation = magnetic heading.) * * @param dlat Latitude in decimal degrees. * @param dlong Longitude in decimal degrees. */ public function getDeclination( dlat:Number, dlong:Number ):Number { if( inputError) { return 0.0; } else { calcGeoMag( dlat, dlong, currentFixedDate, currentFixedAltitude ); return dec; } } } }

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-27-2012 09:44 AM - edited 06-27-2012 09:55 AM

jtegen wrote:

Since the latitude is the only thing you need to adjust the azimuth, you can have a calibrate mode, get the GPS location and store the latitude. A degree difference should not make that much of a difference while traveling.

This is not quite correct. You need both latitude and longitude to calculate the value of the correction and it can vary drastically from one location to another if you are flying around the world. You may be confusing declination with inclination which is a different thing entirely.

I posted the required code here but I perhaps shouldn't have due to the length. However, I can't find time to get a github account and post it there. Please fell free to do so soif you feel so inclined.

My Device: HTC One, PlayBook, LE Z10, DE Q10

My Carrier: Verizon

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-27-2012 09:53 AM

Thanks for the info. Still not there yet in getting all the values correct. Appreciate the code. The rotation matrix in BB10 attitude works great with the sample decoding that you provided. Onto the next step....

My Device: BlackBerry Z10, BlackBerry Dev Alpha C, BlackBerry PlayBook

My Carrier: Bell

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-28-2012 10:22 AM

Great stuff Maurice!!

Follow me on Twitter: @dustinmalik

-----------------------------------------------------------------------------------------------------

Keep up to date on BlackBerry development: http://devblog.blackberry.com/

-----------------------------------------------------------------------------------------------------

Keep up to date on BlackBerry development: http://devblog.blackberry.com/

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-28-2012 12:30 PM - edited 06-28-2012 12:41 PM

dmalik wrote:

Great stuff Maurice!!

I have a couple of additional questions/observations:

First, is there any plan to complete the official sensor ANE so that it dispatches events analogous to the SENSOR_TYPE_AZIMUTH_PITCH_ROLL event in nDK 2.0.? Or perhaps a "getAPR()" method could be added to the RotationMatrixEvent.UPDATE event. (The new method would simply apply the math that I supplied in the OP.).

Second, I have loaded my app (current 2.0 version) onto the Dev Alpha device and it runs very well. I will have to rebuild using tthe BB10 SDK to take advantage of the Fuse controls but this isn't going to be too much of a problem.

A bigger problem is magnetometer in the alpha device is pointing in apparently random directions. It never seems to settle down completely and never points in the same direction as my PB's magnetometer. My first thought was that the driver on the alpha is broken but it could be anything. Before I do a lot of work, I would appreciate it if you could confirm a couple of things:

1. I would prefer to keep on using my custom ANE so I don't have to modify existing interfaces. Is there any reason to recompile it using the BB10 ND?. It is currently compiled using NDK 2.0.1.but there appears to be some changes in the NDK sensor packages.For example the name of the constant that points to the APR event is different. Do I have to rewrite my ANE to conform?

2. Currently, I get an azimuth of zero (north) when the PB's media buttons are pointing north. However it looks like the Dev Alpha's reference point on the device is the short side where the camera lens is located (a 90 degree shift). I would prefer not to have to write device-specific versions of my magnetometer function. It would be better if I could determine programatically which edge is considered to be "top" so that the code could adapt to whatever divice is being used. Is there any way to do this?

My Device: BlackBerry Z10, BlackBerry Dev Alpha C, BlackBerry PlayBook

My Carrier: Bell

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-28-2012 01:13 PM

MauriceRice wrote:

First, is there any plan to complete the official sensor ANE so that it dispatches events analogous to the SENSOR_TYPE_AZIMUTH_PITCH_ROLL event in nDK 2.0.? Or perhaps a "getAPR()" method could be added to the RotationMatrixEvent.UPDATE event. (The new method would simply apply the math that I supplied in the OP.).

The only reason we have the APR sensor is for Android. We could add utility methods to get the various things though. No plans for it yet but we could add it in the future.

MauriceRice wrote:

1. I would prefer to keep on using my custom ANE so I don't have to modify existing interfaces. Is there any reason to recompile it using the BB10 ND?. It is currently compiled using NDK 2.0.1.but there appears to be some changes in the NDK sensor packages.For example the name of the constant that points to the APR event is different. Do I have to rewrite my ANE to conform?

2. Currently, I get an azimuth of zero (north) when the PB's media buttons are pointing north. However it looks like the Dev Alpha's reference point on the device is the short side where the camera lens is located (a 90 degree shift). I would prefer not to have to write device-specific versions of my magnetometer function. It would be better if I could determine programatically which edge is considered to be "top" so that the code could adapt to whatever divice is being used. Is there any way to do this?

1. I'm not a native expert so you may have better luck in the native forum.

2. I am pretty sure you have to use the orientation of the app and not that of the sensor. So you want to re-map the values based on stage.orientation.

As Tim mentions in this blog post - http://devblog.blackberry.com/2012/06/blackberry-1

Cheers,

Dustin

Follow me on Twitter: @dustinmalik

-----------------------------------------------------------------------------------------------------

Keep up to date on BlackBerry development: http://devblog.blackberry.com/

-----------------------------------------------------------------------------------------------------

Keep up to date on BlackBerry development: http://devblog.blackberry.com/

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

06-28-2012 01:35 PM

dmalik wrote:2. I am pretty sure you have to use the orientation of the app and not that of the sensor. So you want to re-map the values based on stage.orientation.

Thanks for your reply. I will wait a bit for refinements as you suggest. With respect to azimuth readings, they are aways dependent on the orientation of the device. The x, y, and z axes are fixed in relation to the device. Which ever side is deemed to be "top" for the device becomes the reference point for the azimuth readings. The screen orientation does not come into play at all, although this would save me a lot of work if it was all I needed to take into account.

Copyright © 2014 BlackBerry, unless otherwise noted.