I use “atan2(x,y)”. It’s not 100% what you’re looking for (measured (-pi,pi] from the x-axis clockwise) but it does all of the “hard work” in the standard library so it should be efficient in the general case. The conversion from there to what you want is straight forward.
atan2(x,y) gives +/-pi clockwise from the +Y axis. That puts the discontinuity on the -Y axis, which then requires you to add conditional logic to fix it. There’s a better way.
BTW, concerning atan2(0,0), many modern implementations, such as the microcode in the FP unit of the Pentium*, helpfully return zero when both arguments are zero. Does anyone know what the FRC versions of LabVIEW, C++, and Java do?
here’s a short test code written in Delphi:
USES windows, sysutils;
Function FPatan2(y : extended; x : extended): Extended;
asm fld [y] ; fld [x] ; fpatan end ;
Well, it takes less clock cycles to just retrieve data from an array compared to calculating the angle on the fly. Even though a look up table does take up considerable amount of space in the RAM (Not really since we are dealing with 64 MB of RAM…) Also given the level of accuracy we only really need, about ± pi/180 radian. I think it should be fine.
I though you were going to post the trig logic to do all of the calculations. “atan2” is certainly the way to go, transforming coordinates before using it is great.
I need to look at a clock again… right hand rule = CCW!!! :ahh: See my earlier post.
From a readability perspective, consider defining a macro statement such that.
angle = HEADING(0,0);
atan2(0,0) is undefined in the standard. So for cross platform use, you should check for this as an arbitrary compiler can throw an exception.
if y == 0.0 then y = 1e-8.
Assuming you aren’t working with nano-bots this will do nicely and leave your (0,0) point at 0. Unfortunately this adds a comparison operation which, as implied here, are commonly the most costly operations and what you are trying to avoid. This is a prety good arguement for changing the standard.
I did some reading, and as Ether pointed out, ALL recent Intel chips define (0,0) as 0 and this is on the chip and part of the FPU. If you use a look-up table, you need an unbounded (or large) 2D table in x and y… You can manage this by normalization or conversion to a one dimensional problem but atan2 solves it right there in the silicon. There are a host of other issues with the look-up table but the one that strikes me is the effort associated with continually moving a table back and forth through the layers of cache on the chip (Cache is MUCH smaller than RAM). It’s not a good option and should not be faster (coding or execution with other intensive code in the loop) or portable to higher resolution applications. In the interest of exhausting all alternatives, the look-up table certainly is “out of the box” and I like it. Keep up the good work!
With the Intel FPU, most modern PC’s and Macs will get (0,0) = 0 “right” provided the compiler actually accesses the FPU directly for this calculation (that would be most compilers including gcc). But what does the cRIO do? Is the FPGA intel based? Looks like “Xilinx Virtex” is a custom processor for FPGA? So you need documentation of a firm commitment to define the result as 0, or you need to test and a re-test every time the chip is upgraded which could happen without a “model” change to cRIO.
I’m pretty sure LabVIEW has two different atan commands in its Math/Trig library (which I believe is supported on the cRio). The first takes a float which should be your y/x value, and then spits out theta on the interval (+pi/2, -pi/2) relative to +X (note the inability to deal with infinite slope, one of the problems avoided by the other command). The other takes an x and a y separately, then does all the logic for you to return theta on the interval [0,2pi) from +X. To find the angle from +Y, you can subtract 90 (careful of wrapping, if it matters), or feed y in for x and -x in for y (the second one is waaaaay better).
Edit: Theta is counter-clockwise from reference point, of course. All x and y inputs are on [-1, 1] as one would expect on a unit circle.
Edit: And now I see that you asked for clockwise from +Y. Simply flip your inputs around the y-axis: give it y for x and **+**x for y.
In theory, this two parameter atan calculation only needs to do the following:
Take the arc cosine of x, which is on -1, 1] to get theta on [0, pi], via whatever method is effective (lookup table, polynomial approximation, etc.) If y is less than 0, subtract theta from 2pi. Done. Theta is on the interval 0, 2pi), counterclockwise from the positive x-axis.
Then you swap inputs as outlined above to get the special, non conventional stuff the OP is asking for. This effectively flips the whole situation about y=x, which is equivalent to the relationship between his question and convention.
. Does anyone know what the FRC versions of LabVIEW, C++, and Java do?
I’m pretty sure LabVIEW has two different atan commands in its Math/Trig library (which I believe is supported on the cRio). The first takes a float which should be your y/x value, and then spits out theta on the interval (+pi/2, -pi/2) relative to +X (note the inability to deal with infinite slope, one of the problems avoided by the other command). The other takes an x and a y separately, then does all the logic for you to** return theta on the interval [0,2pi) [/b]from +X.**
1) The question was asked in the context of the handling of atan2(0,0) for FRC. The answer, for LabVIEW, is that it returns 0, at least according to the simple test I ran on a desktop PC (not in a cRIO). Not being a LabVIEW guru, I don’t know if it sets any error flags which might have side effects elsewhere. Does anyone know what the FRC versions of C++ and Java do when running on cRIO?
2) LabVIEW atan2 does not return [0,2pi). It returns an answer in the range (-pi…pi] (not surprisingly).
You are given arbitrary (x,y). So you must take the arc cosine of x/sqrt(x2+y2). Not that it matters for purposes of FRC, but numerically that is inferior to a properly implemented atan2(y,x) (and also suffers from the 0,0 problem). Also, since the sign of y is lost in the squaring operation, additional conditional logic is necessary to get the desired range.
There were a number of questions raised. I’ll respond to the ones I remember.
What is atan2 of 0 and 0. In LabVIEW, it is 0, at least on an Intel mac. I don’t have a cRIO in front of me. I hope/suspect that the PPC LV will return the same, but since I don’t have the LV test suite in front of me to prove that is a tested result, I’ll speculate that it returns zero. The applied mathematicians on the LV team tend to be picky about things like that, so they have test suites that enforce the results across platforms. Can someone test for sure?
What does the FPGA do? Is it Intel? It is not Intel, and it doesn’t natively do FPU operations. It is a field programmable gate array, a bunch of low level logic operations. In order for it to do an integer addition, an adder has to be constructed in it. If you also wish to multiply, a multiplier has to be constructed. The results of those operations are determined by the adder or multiplier you emit to the FPGA. The FPGA image used for FRC contains no floating point trig operations, and in fact I doubt it contains any floating point operations at all as they consume gates very quickly.
Which is faster/better, the atan2 operation, or a lookup table? I have my suspicion/opinion, but this is the sort of thing where the actual answer is … it depends. Rather than take someone’s answer, the approach I’d encourage you to take is to implement both and learn the magnitude of the operations involved. If the lookup table is pretty fast, what if you interpolate for more precision. My point is that knowing A is faster than B is useful info, but more useful is to know the rest of the tradeoffs, and to know how much faster and why.
There seems to be a lot of confusion as to what an FPGA is, specifically what the FPGA in the cRIO is, if anyone is so inclined it may be of value for someone to write up a description about it. It seems that despite being tucked well within NI’s system there is a lot of curiosity about it.
To answer quickly FPGA’s and processors are inherently different things. an FPGA or field programmable gate array is basically a huge array of gates, basically if you could take millions of nand gates and organize them in an array such that you can combine them in any way you like you would have the functional equivalent of an FPGA. Obviously the execution of an FPGA is a bit mor ecomplicated but you can visualize what is happening this way. By combining the gates in the FPGA in different ways you can create any logic circuits within the chip, including processors. The Xilinx Virtex is simply the family of FPGA’s the one on board the cRIO belongs to. Xilinx is the manufacturer, Virtex is the family. Xilinx does have a few different soft core processors (processors created wthin the FPGA) that you can load onto the chip (MicroBlaze, PicoBlaze etc.). I do not howeve know whether these (or any thing simmilar) are implemented in the FPGA, I would guess they are not.