Search code examples
javamathtrigonometryastronomy

Getting wrong distances when entering coordinates and parallaxes for celestial objects in Java


I'm working on an astronomical database program that allows users to create and enter their own stars and brown dwarfs, among other things, for an entry-level programming course at university. Each object has xyz coordinates that determine its position in space, with the Sun being at 0, 0, 0 light years.

However, since a lot of star databases (e.g. SIMBAD), Wikipedia, etc., give astronomical objects' positions in terms of parallax angles and right ascension/declination coordinates, I've given users the option to add objects using those parameters, in case they don't have xyz coordinates. I'm having problems with getting it to provide accurate values though.

Here's the code for entering parallax angle, with options for entering in both arcseconds/as and milliarcseconds/mas:

/**
 * Notes:
 * scReadIntMM(n1, n2); reads and returns user-entered ints within the range n1 to n2, via Scanner
 * scReadDoubleMM(n1, n2); is the same, only for doubles.
 */

//user chooses units for entering parallax
System.out.println("Entering parallax and RA/Dec coordinates.");
System.out.println();
System.out.println("Which units do you wish to use?");
System.out.println("(1) Arcseconds (1 as = 1/3600 degrees)");
System.out.println("(2) Milliarcseconds (1 mas = 1/1000 arcseconds)");
userChoice = scReadIntMM(1, 2);  //stores user choice
System.out.println();

//user enters angle, converts to distance and stores
if (userChoice == 1){
    //if user chose to enter in arcseconds
    System.out.println("Set object's parallax angle, in arcseconds.");
    System.out.println("Maximum: 3.26167 (corresponding to a distance of exactly 1 light year)");
    System.out.println("Minimum: 0.006523266 (corresponding to a distance of about 500 light years)");
    dist = (3.26167 / (scReadDoubleMM(0.006523266, 3.26167)));
    System.out.println();

} else if (userChoice == 2){
    //if user chose to enter in milliarcseconds
    System.out.println("Set object's parallax angle, in milliarcseconds.");
    System.out.println("Maximum: 3261.67 (corresponding to a distance of exactly 1 light year)");
    System.out.println("Minimum: 6.523266 (corresponding to a distance of about 500 light years)");
    dist = (3.26167 / ((scReadDoubleMM(6.523266, 3261.67)) / 1000));
    System.out.println();
}

Both of these give the correct result (i.e. 3.26167 / (angle in as)), when I add an extra println statement to check dist's value after the calculation. For example, entering Sirius' parallax (0.37921 as, 379.21 mas gives a value of 8.60 light years, which is exactly what I'd expect to see after looking at its Wikipedia page.

The next stage seems to be where everything is going wrong though. This part is where the user enters the coordinates, which get converted to degrees using the procedure listed on this site, and then get changed to radians once everything's been entered:

//user enters right ascension
System.out.println("Enter hours of right ascension. (Must be between 0 and 23, whole");
System.out.println("numbers only.)");
ra = (((double)scReadIntMM(0, 23)) * 15.0);  //enters hours
System.out.println();
System.out.println("Enter minutes of right ascension. (Must be between 0 and 59, whole");
System.out.println("numbers only.)");
ra = ra + (((double)scReadIntMM(0, 59) / 60.0) * 15.0);  //enters mins
System.out.println();
System.out.println("Enter seconds of right ascension. (Must be between 0 and 59.999999.)");
ra = ra + ((scReadDoubleMM(0, 59.999999) / 3600.0) * 15.0);  //enters secs
ra = Math.toRadians(ra);  //converts from degrees to radians
System.out.println();

//user enters sign for declination (+ or -)
System.out.println("Is the object's declination positive or negative? (Enter a number.)");
System.out.println("(1) Positive");
System.out.println("(2) Negative");
userChoice = scReadIntMM(1, 2);  //stores dec sign
System.out.println();

//user enters declination
System.out.println("Enter degrees of declination, without positive or negative signs. (Must be");
System.out.println("between 0 and 90, whole numbers only.)");
dec = ((double)scReadIntMM(0, 90));  //enter degrees
System.out.println();
System.out.println("Enter minutes of declination. (Must be between 0 and 59, whole");
System.out.println("numbers only.)");
dec = dec + (((double)scReadIntMM(0, 59)) / 60.0);  //enter mins
System.out.println();
System.out.println("Enter seconds of declination. (Must be between 0 and 59.999999.)");
dec = dec + (scReadDoubleMM(0, 59.999999) / 3600.0);  //enter secs
dec = dec * userChoice;  //sets declination sign
dec = Math.toRadians(dec);  //converts from degrees to radians
System.out.println();

Then, the RA/Dec values are used to calculate the x, y, z values, still following the instructions on the page I linked to before:

//calculates x, y, z coords from ra/dec and distance values
xIn = ((dist * Math.cos(dec)) * Math.cos(ra));
yIn = ((dist * Math.cos(dec)) * Math.cos(ra));
zIn = (dist * Math.sin(dec));

Using this method, I'm getting a distance of 5.139 ly for Sirius (using the parallax and RA/Dec listed on Wikipedia), rather than the 8.60 ly value calculated using the parallax alone. I'm also getting underestimates for more distant things, like an object that should be ~388 ly away being a few tens of ly closer.

I can't really see any places where it might have gone wrong though. Te only thing I could think of is int values overriding doubles when entering H/M or D/M for RA/Dec, and I fixed that early on (it was causing even larger errors). Is there something I'm missing here? Maybe just lossiness due to using doubles rather than longs.


Solution

  • From the link you posted, it seems that yIn should be:

    ((dist * Math.cos(dec)) * Math.sin(ra));
    

    Instead of

    ((dist * Math.cos(dec)) * Math.cos(ra));