 # Need help with a Math problem

I have to turn a AZ/EL rotor system into a XY system.

For the X part this is the formula where az and el are the Azimuth and Elevation values.

Y = Degrees ( ArcSin ( Sin ( Radians ( -az ) * Cos ( Radians ( -el )))) + 90.0

In arduino code this would look like:

``````#include "Arduino.h"
#include <SoftwareSerial.h>
#include <Streaming.h>
#include <math.h>

long _XX;
long _YY;

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(1000);
_xyConvert(36000, 19700);
}

void loop() {

}

void _xyConvert(long el, long az)
{
double azFloat = az;
azFloat = azFloat /100;
double elFloat = el;
elFloat = elFloat /100;

_XX = atan(cos(-az) / tan(-el)) + 90;

_YY = asin(sin(-az) * cos(-el) ) + 90;

Serial << _FLOAT(_XX,2) << " - " << _FLOAT(_YY,2) << endl;
}
``````

But the result in both equals zero. Any help would be wolcome.

Moderator edit: Tags hopefully corrected

Well, the standard math libraries work in radians, not degrees.

I see that you're using degrees. All trigonometric math functions use radians. Meaning convert your degrees to radians (90 degrees == pi/2 radians). Second, making a variable a float or double doesn't make the math float/double. Here is a example:

``````float x = 90 * 1.1;
``````

Won't necessarily give you 99 because the number 90 is an integer. Type this instead to fix the problem:

``````float x = 90.0 * 1.1;
``````

By putting a ".0" in front of the number you automatically turned it from an integer to a float.

I'm not home, otherwise I would have tried your code...

I now have changed the code by including the radians to degrees conversion by declaring a static

``````  static const double DegreeToRadian = 0.0174532925;  // PI/180
``````

and included in the two calculations

``````    _XX = DegreeToRadian * ( atan(cos(-az) / tan(-el) ) ) + 90.0;
_YY = DegreeToRadian * ( asin(sin(-az) * cos(-el) ) ) + 90.0;
``````

But now the result is in both 90.0

But now the result is in both 90.0

So, print some intermediate results...

It's not the output of tan(), sin(), cos(), etc. that needs to be converted. Its the INPUT.

You got it backward... Try this instead...

``````az = az * DegreeToRadian;
_XX = (1 / DegreeToRadian) * ( atan(cos(-az) / tan(-el) ) ) + 90.0;
_YY = (1 / DegreeToRadian) * ( asin(sin(-az) * cos(-el) ) ) + 90.0;
``````

After postin i figured that out as wel en started to output every line of calculation. This is the result of that:

az(RAD) = 23000(4.01) and el(RAD) = 5100(0.89) Calculate Azimuth >> X cos(-azFloat) = -0.64 tan(-azFloat) = -1.23 cos(-azFloat)/tan(-azFloat) = 0.52 atan(cos(-azFloat)/tan(-azFloat)) = 0.48 atan(cos(-azFloat)/tan(-azFloat))*RadianToDegree = 27.50 (atan(cos(-azFloat)/tan(-azFloat))*RadianToDegree)+90.0 = 117.50 Calculate Elevation >> Y sin(-azFloat) = 0.77 cos(-elFloat) = 0.63 sin(-azFloat)*cos(-elFloat) = 0.48 asin(sin(-azFloat)*cos(-elFloat)) = 0.50 (asin(sin(-azFloat)*cos(-elFloat)))*RadianToDegree = 28.82 ((asin(sin(-azFloat)*cos(-elFloat)))*RadianToDegree)+90 = 118.82

Made by this code and gives the corect values.

``````void _xyConvert(long az, long el)
{
double azFloat = az;
double elFloat = el;

_XX = (atan(cos(-azFloat) / tan(-elFloat) )*RadianToDegree) + 90.0;
_YY = (asin(sin(-azFloat) * cos(-elFloat) )*RadianToDegree) + 90.0;
}
``````

But your code example gives a different answer _XX =75 and _YY=117

some observations: 1) make az and el float, that prevents truncating here -> azFloat /100*DegreeToRadian;

2) note there are several division by zero possible

3) style (is a matter of taste) double azFloat = az; azFloat = azFloat /100*DegreeToRadian;

can be a one liner without loosing readability

double azFloat = az / 100.0 * DegreeToRadian;

``````void _xyConvert(float az, float el)  {

_XX =  (asin(sin(-azFloat) * cos(-elFloat) )*RadianToDegree) + 90.0;
if(el < 0.1) {
el = 0.1;
}
else {
_YY = (atan(cos(-azFloat) / tan(-elFloat) )*RadianToDegree) + 90.0;
}
}
``````

According to the theoritical guys there are some differences between there results on a sacel-ruler en this routine.
How i can i prefent/tactle the divisions by 0?

How i can i prefent/tactle the divisions by 0?

The obvious one that I see is the atan(y/x) problem. Since tan(a) = sin(a)/cos(a) then tan becomes asymptopic at PI/2 and multiples of PI thereafter (3PI/2 etc)

I am not sure how safe the maths library is for using atan2(x,y) or whether it may be better to write your own arctan procedure in order to get the angle in the correct quadrant.

Here is a link that describes the problem clearly and simply:

http://hyperphysics.phy-astr.gsu.edu/hbase/ttrig.html

baselsw: ``` float x = 90 * 1.1; ```

Won't necessarily give you 99 because the number 90 is an integer

It will never give 99, but it will always give 99.0 !!

It does because the result of an operator will be widened to float if any of its operands are float. Having the 1.1 is enough to make the RHS float. However it is easy to make mistakes when mixing integer and floating point values, such as with

``````  float a = 2000 / 13 * 4.5 ;
``````

This is parsed as (2000 / 13) * 4.5 so that the coercion to floating point doesn't happen till after the divide has happened, so integer (truncating) divide would be used. It is thus good practice to always use floating point constants for floating point values - it also makes your intent clear in the code to those that have to work with it later.

Some came with a other aproach and while constructing it i created this:

``````  _XX = 90 - ( atan( sin( azFloat ) / tan( elFloat ) ) * RadianToDegree );
_YY = 90 - ( atan( ( cos(azFloat) * cos(elFloat) ) / sqrt( 1 - ( cos(azFloat) * cos(elFloat) ) * cos(azFloat) * cos(elFloat) ) ) * RadianToDegree );
``````

So i think better to use some extra brackets than to litle

gharryh: I now have changed the code by including the radians to degrees conversion by declaring a static

``````  static const double DegreeToRadian = 0.0174532925;  // PI/180
``````

and included in the two calculations

``````    _XX = DegreeToRadian * ( atan(cos(-az) / tan(-el) ) ) + 90.0;
_YY = DegreeToRadian * ( asin(sin(-az) * cos(-el) ) ) + 90.0;
``````

But now the result is in both 90.0

Wrong: ``` x = sin(45) / 57.29578; print x;    (yields 0.014851, expected 0.707107) ```

Right: ``` x = sin(45 / 57.29578); print x;      (yields 0.707107) ```

(btw, 57.29578 is 180 / pi).

And you can generate PI like this: ``` double pi = 4 * atan(1); ```

I did some rework on the sketch using the internal Arduino PI value

``````static const double DegreeToRadian = PI/180 ;  // PI/180
static const double RadianToDegree = 1/DegreeToRadian;    // 1 / ( PI / 180 )
``````

And also som rewriting on the xyConverter:

``````void _xyConvert(float az, float el)  {

if(el == 90.0) {
el = 89.9;
}
if(el < 0.1)   {
el = 0.1;
}

}
``````
``````cos(azFloat)*cos(elFloat))*cos(azFloat)*cos(elFloat)
``````

sin() and cos() are not fast functions. Why call them more than you need to?

PaulS: ``` cos(azFloat)*cos(elFloat))*cos(azFloat)*cos(elFloat) ```

sin() and cos() are not fast functions. Why call them more than you need to?

I havent done any speed optimizing yet. Its done this way to make some people clear that what they asked me to do is done.

Its done this way to make some people clear that what they asked me to do is done.

``````float cosAZ = cos(azFloat)
float sinAZ = sin(azFloat);

float cosEL = cos(elFloat);
float sinEL = sin(elFloat);