# How to convert Proper Motion in RA & Dec to Galactic Coordinates

I'm trying to parse stellar data in the GAIA 2 release to galactic coordinates and am struggling with the velocity component. I've tried following online documentation and papers, but end up with velocity results with strange biases that indicate I'm probably doing something wrong. Sources I've used are: http://adsabs.harvard.edu/full/1987AJ.....93..864J

https://gea.esac.esa.int/archive/documentation//GDR1/Data_processing/chap_cu3ast/sec_cu3ast_intro.html#SS

The GAIA 2 dataset has these relevant variables per star:

• ra (from 0-360)
• dec (from -90 to 90)
• pmra
• pmdec
• parallax

And this is the code I have (C#) to try to obtain the velocity components. Done by first converting pmra and pmdec to cartesian velocities based on the stars position, and then rotating that location to galactic coordinates.

double RA = ra * Math.PI / 180.0;
double DEC = (dec + 90) * Math.PI / 90.0;

Microsoft.Xna.Framework.Matrix positionrotation = new Microsoft.Xna.Framework.Matrix();
positionrotation.M11 = (float)(Math.Cos(RA) * Math.Cos(DEC));
positionrotation.M12 = (float)-Math.Sin(RA);
positionrotation.M13 = (float)-(Math.Cos(RA) * Math.Sin(DEC));

positionrotation.M21 = (float)(Math.Sin(RA) * Math.Cos(DEC));
positionrotation.M22 = (float)Math.Cos(RA);
positionrotation.M23 = (float)-(Math.Sin(RA) * Math.Sin(DEC));

positionrotation.M31 = (float)(Math.Sin(DEC));
positionrotation.M32 = 0;
positionrotation.M33 = (float)(Math.Cos(DEC));

Microsoft.Xna.Framework.Vector3 vector = new Microsoft.Xna.Framework.Vector3((float)(radial_velocity), (float)(pmra / parallax), (float)(pmdec/ parallax));
vector = Microsoft.Xna.Framework.Vector3.Transform(vector, positionrotation);

Microsoft.Xna.Framework.Matrix galacticrotation = new Microsoft.Xna.Framework.Matrix();
galacticrotation.M11 = -0.054876f;
galacticrotation.M12 = -0.87347f;
galacticrotation.M13 = -0.483835f;
galacticrotation.M21 = 0.494109f;
galacticrotation.M22 = -0.444830f;
galacticrotation.M23 = 0.746982f;
galacticrotation.M31 = -0.867666f;
galacticrotation.M32 = -0.198076f;
galacticrotation.M33 = 0.455984f;
vector = Microsoft.Xna.Framework.Vector3.Transform(vector, galacticrotation);

• I'm totally confused by your question. What are you trying to do? Velocities are in km/s. Galactic coordinates refers to positions. Or are you talking about Galactic UVW velocity components, which your code doesn't address at all? – ProfRob Feb 22 at 8:38
• The Galactic UVW velocity components are what I'm after. In my code, those are supposed to be calculated in the final vector. Any velocity unit is fine as long as I know which it is. The intention of the 'positionrotation' section is rotating pmra, pmdec and radialvelocity to velocities in the equatorial coordinate system based on the position of the star, and the purpose of the galacticrotation is to convert that to velocities in the galactic coordinate system. If that approach is flawed, I'd love to learn how to accomplish this correctly – Borborbor Feb 22 at 17:57
• I wouldn't say flawed, just unorthodox. Astronomers who haven't been following your development process might find a more direct implementation of equations 3.57 - 3.71 easier to follow. The galactic (l, b) angular coordinates (eq. 3.63) might be useful for visualizations. – Mike G Feb 22 at 18:15
• I ended up not using the linked formulas since they don't take radial velocity into account. I was also left wondering how to exactly make use of the parallax here to obtain the real position and velocity vectors – Borborbor Feb 22 at 22:14

The DEC conversion in the question is incorrect. Try this:

double DEC = dec * Math.PI / 180.0;


positionrotation looks like a composition of two rotations bringing (1, 0, 0) to the RA and DEC of interest. It seems correct, but something like this would be easier to verify:

using Microsoft.Xna.Framework.Matrix;

Matrix positionrotation =
Matrix.CreateRotationZ((float) RA) * Matrix.CreateRotationY((float) -DEC);


The units in vector are mixed up. According to these Gaia DR2 docs, radial_velocity is in km/s. pmra and pmdec are in mas/yr; dividing (*) them by parallax in mas (1 au baseline) gives results in au/yr. Try this:

using Microsoft.Xna.Framework.Vector3;

// conversion to km/s
double au_yr = 1.49598e+8 / 3.15576e+7;

Vector3 velocity = new Vector3(
(float) pmra / parallax * au_yr,
(float) pmdec / parallax * au_yr);

Vector3 vel_icrs = Vector3.Transform(velocity, positionrotation);


If galacticrotation is from equation 3.61 in these Gaia DR2 docs,

// Matrix galacticrotation as above except
galacticrotation.M12 = -0.873437f;

Vector3 vel_gal = Vector3.transform(vel_ircs, galacticrotation);


(*) Actual distance in parsecs may differ from the reciprocal of measured parallax in arcseconds, which may be zero or negative.

• Thank you so much! Your changes make sense and seem to improve the results. The method of calculating the positionrotation matrix seems to have some slipped signs but it is otherwise identical. It does still seem like there's some issue left though, stellar velocity seems heavily correlated to the stellar positions. Here's a quick stellar map plot: puu.sh/Hj7A4/cf8192b8b1.png The axes here are RA (x) and DEC (y) and the color of stars represents their velocity along the W axis. – Borborbor Feb 22 at 17:46
• What happens if you account for the Sun's motion around the galaxy? – Mike G Feb 22 at 18:06
• Wouldn't that show the exact same pattern? If the sun moves at velocity x in direction W, wouldn't it just mean adjusting all the stellar velocities by a flat -x? Or is there some other way to adjust the velocities? – Borborbor Feb 22 at 20:58
• I guess you could compute a mean velocity vector for a sample of stars and subtract that. I would expect it to reduce the hemisphere-wide bias and make smaller-scale variations easier to see. – Mike G Feb 22 at 21:14
• If the calculations are correct now, that sounds like a decent idea to account for this bias and get more visible local fluctuation. Perhaps there's some bias in the data itself. I'm still rather suspicious though that this bias indicates there's some mistake remaining in my approach that would also make the local data worthless. – Borborbor Feb 22 at 21:48