GPSView
GPSView
Recently, we created GPSView, a free Android application to show a user the location of GPS satellites they can detect. The following post is an explanation into how the math works and provides some Java code examples of how to calculate this.
In regards to GPS, it turns out Android will provide some information that you cannot get on the iPhone. On both platforms you are provided with your current location. But on Android you can also gain access to the satellite data. The data looks a little like this (Azimuth [326.0], Elevation [7.0], PRN [2], SNR [21.0]). Azimuth and elevation are two navigational terms that tell you where an object is relative to your current position. The azimuth is the compass bearing, relative to true (geographic) north, of a point on the horizon directly beneath an observed object. The elevation, also called the altitude, of an observed object is determined by first finding the compass bearing on the horizon relative to true north, and then measuring the angle between that point and the object, from the reference frame of the observer.
The problem
Knowing this, the problem breaks down into 2 steps. First, given the elevation (E) what is the distance (D) to the point directly between the satellite and the reference point? Second, now that you know the distance, bearing, and location, what will the new position be?
Step 1
The following diagram illustrates the problem.
The variables are
 E = elevation angle
 R = the earths radius
 H = the satellite orbit
 D = the distance we are solving for
 The angles; Theta, Alpha, and Beta
 Solve for Theta
theta = 90 (degrees) + E

Use the law of sines to solve for Alpha
(Sin(Theta)/(R + H)) = (Sin(Alpha)/R)

Use Theta and Alpha now to solve for Beta
Beta = 180  Alpha  Theta

Convert the angle into radians and multiply by the radius of the earth to get the distance
D = R * ((Beta * 2 Pi)/360)
Step 2
Now that we have a distance and a bearing we can use standard navigational formulas to find a position on the earth. I used Aviation Formulary V1.30  Ed Williams
lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc)) IF (cos(lat)=0) lon=lon1 // endpoint a pole ELSE lon=mod(lon1asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)pi ENDIF
Into Java
Now to actually use this math, the following code snippet was pulled out of the application.
public static final int LAT_LON_CONVERT = 1000000;
public static final double EARTH_CIRCUMFRENCE = 40075;
public static final double EARTH_RADIUS = 6360;
public static final double GPS_SAT_ORBIT = 20200;
public static final double SAT_HEIGHT_FROM_CENTER = EARTH_RADIUS + GPS_SAT_ORBIT;
public static double findDistance(float elevation) {
//These equations are based on the law of sins
if(elevation == 90) return 0;
double theta = Math.toRadians(elevation) + Math.PI/2; //Add on for the 90 degree tangent
double alpha = Math.asin(EARTH_RADIUS * (Math.sin(theta)) / SAT_HEIGHT_FROM_CENTER);
double beta = Math.PI  theta  alpha;
double distance = beta * EARTH_RADIUS;
return distance;
}
public static GeoPoint findPosition(double distance, double lat1, double lon1, double azimuth) {
double lat2 = 0;
double lon2 = 0;
//Switch to radians
lat1 = Math.toRadians(lat1);
lon1 = Math.toRadians(lon1);
azimuth = Math.toRadians(azimuth);
distance = (distance/EARTH_CIRCUMFRENCE)* 2* Math.PI;
lat2 = Math.asin(Math.sin(lat1)*Math.cos(distance) + Math.cos(lat1) * Math.sin(distance) * Math.cos(azimuth));
if(Math.cos(lat1) == 0) {
lon2 = lon1; // endpoint a pole
} else {
lon2 = Math.asin(Math.sin(azimuth)*Math.sin(distance)/Math.cos(lat1));
lon2 = lon1  lon2 + Math.PI;
lon2 =(lon2 % (2*Math.PI));
lon2 = lon2  Math.PI;
}
//Convert back to degrees
lat2 = Math.toDegrees(lat2);
lon2 = Math.toDegrees(lon2);
GeoPoint pt = new GeoPoint((int)(lat2 * LAT_LON_CONVERT), (int)(lon2 * LAT_LON_CONVERT));
return pt;
}
Conclusion
Once we have this point its trivial to project that onto a map in Android. The end result is what you are seeing on GPSView.
Enjoy!
References:
For more information please check these sites