Jump to content
thomasss

floating point - Math - and Trigonometry with msp430g2553

Recommended Posts

Hi Everyone,

 

I have been looking for about an hour online and haven't been able to find the answers to these questions.

- Can I use floating point with the msp4302553 ? the watch expression on CCS don't seems to like floating point for sure.

- Can I use math.h to do trigonometry calculus on the msp430g2553 ?

 

Let me tell you guys what I am trying to do so that it is more clear:

I am scanning a signal with an ADC. I would like to do an atan() on the signal and output the signal with an DAC.

Right now I can scan the signal and send it to the DAC. This works well. But I can't get the trigonometric conversion to work.

 

Is it possible to do it? And if yes could I get a little help from you guys ?

 

Thanks in advance for your help.

 

Thomas

 

PS: I saw about these Qmath functions that came out recently but couldn't get it to work either

http://www.ti.com/tool/MSP430-iqmathLIB?DCMP=ep-mcu-msp-iqmath-en&HQS=ep-mcu-msp-iqmath-pr-sw2-en

Share this post


Link to post
Share on other sites

i've found energia pretty good for most floating point functions. especially on the 2553 as it has enough flash.

 

i haven't done arc-tangent personally, as it would have to calculated from the other transcendentals; but i've used them all in other calculations with success.

 

about your d/a output, it depends on it's particular interface, but again, energia has a nice variety including spi, iic, even bit-banging serial.

 

hope this helps.

 

btw -  this assumes you're using a 2553 equipped ti launchpad board.

Share this post


Link to post
Share on other sites

Over in the Energia Libraries folder I have posted a port of libfixmath to msp430. I had to make a few changes to get it to compile, but not many. It is tested with Energia but I can't see any reason why it shouldn't compile with CCS. Libfixmath is much smaller & faster than floating point, but still gives good accuracy. You just have to be careful to avoid overflows.

 

 

Sent from my iPhone using Tapatalk

Share this post


Link to post
Share on other sites

The question I would ask is: do you really WANT to do the trig function, or can you use something that will approximate the behaviour? On a device with at least mult and div in hardware, not a huge issue. FP support in hardware, not issue at all. On a device such as the G-series, often not the best way to go.

 

If you are reading the ADC, applying func, then sending to DAC, I would presume some scaling is going on. The resolution is also limited by the hardware.

 

If the goal is just compression, then I would probably use less costly (time and memory) method, such as an efficient cube root in fixed point, (optimized series, CORDIC, Newton-Raphson method, lookup table with interpolation, etc, preferably optimized to the precision YOU need) and trying to do all of the scaling in one operation, rather than spreading it out.

 

If you actually NEED arctan, to the precision you will have for the input and output, you can likely still use a fixed point approximation that will be faster and smaller then the full blown trig function.

Share this post


Link to post
Share on other sites

For intensive calculations, I'd recommend the Tiva C Series LaunchPad as the TM4C123 includes a FPU=Floating-Pont Unit , enabled by default by Energia. Because it is hardware, it runs very fast.

 

On the MSP430, the float library takes 6KB out of 16KB, so you'll need to use approximations with integers to run fast and save memory.

Share this post


Link to post
Share on other sites

Hi Everyone,

 

Thanks all of you for your help. I didn't know about Energia but will look into it. Is it better than CCS ?

 

So if I understand well libfixmath is approximate math functions that only requires integers. Let's say I have the calculus atan(0.5)=~0.463 648 then you could find a function that do "atan"(500 000)=463 648.

 

am I right ?

 

Actually I have 2 ADC inputs (Va, Vb) and one DAC outputs (Vc) and I want to do Vc=Arctan(Va/Vb). Right now I only have a 10 bit adc so the resolution is limited to that. However the sensor has an accuracy of 0.0001. My future plan will be to switch to a 12 bit adc.

 

Is libfixmath powerful enough for this accuracy ? Should I just switch to the Tiva C Series instead ? Is it easier to use the Tiva C Series ? 

 

So I have a signal Va=0..1024 , Vb=0..1024. It is the sine and the cosine of an angle. And I want to extract the angle Vc=0..1024.

What's the easy way to do this ?

 

Thanks again for your kind help

Share this post


Link to post
Share on other sites

Libfixmath has a 16 bit whole number and 16 bit fraction portion. Therefore the number range is +/-32767 with 1/65536 resolution. In decimal that is approx 0.000015. Because it has a total of 32 bits, as long as you take care not to have overflow or underflow conditions, it is more than adequate for pretty much any calculations originating from a 12 bit source.

 

 

Sent from my iPhone using Tapatalk

Share this post


Link to post
Share on other sites

Are you trying to recover that angle over all four quadrants? Or only the first? Or two quadrants? There are ways of doing this more efficiently than using inverse trig, in particular if you don't need perfect.

Share this post


Link to post
Share on other sites

Thank you grahamf72, 1/65536 resolution is plenty for what I need I think.

 

enl, thanks for the input. I am trying to recover the angle on the 4 quads yep. What other ways are you talking about ?

 

I think if I get the angle on -Pi/2...Pi/2 I think I can just do:

 

For Va < 0 and Vb < 0, subtract 180

Share this post


Link to post
Share on other sites

grahamf72, I looked at the library code that you uploaded on http://forum.43oh.com/topic/4291-energia-library-fixed-point-math/

 

Do you think it will compile on CCS ?

And would you have a code example by any chance to explain how you use the code ?

In fix16_trig.c the first line is #include <limits.h> but I can't find the limit.h file in the zip

 

Right now my code looks like this: 

 

unsigned int getPosition() {
       theta = adcValues[0] + adcValues[1];
    return  theta 
}

 

I get the two values from the adc and I just added them to test that the adcs to dac transfer was good.

How would I include the code in here to use thefix16_atan2 function ?

 

Thank you so much guys

Share this post


Link to post
Share on other sites

If the inputs are 10 bit (or 12 bit) ints, and they represent sine and cosine with fixed scaling, so the same angle always produces the same input values, I would do the following:

 

Identify the octant the angle is in (0-45 deg, 45 to 90, etc)

 

Use the smaller value (which will be the higher resolution value) as index, look up a reference angle between 0 and 45deg.

 

Then correct the result for the appropriate quadrant.

 

Requires a lookup table with about 720 values (for 10 bit input)

 

If the table will be too big, Cut the number of entries by a factor of 4  or 8 (simple shift) and interpolate between values. Linear is likely to be ok (meets inherent error), for angles less than 45deg, with a table having 1/4 as many entries as input range transformed.

 

This avoids: division, trig, and, unless needed, floating and fixed point.

 

 

If the inputs may vary in scale, Divide smaller by larger, multiply by table size, and do the same thing, interpolating if needed.

 

 

You may find that even a fairly large table will take less space than the trig function in the build. Additionally, you can directly get the angle in degrees, or other units, if desired, rather than needing to convert from rad to degrees.

 

If you are going to us inverse tan, I would still identify octant, divide smaller by larger, and correct from there. Angles closer to 0 will be the highest accuracy and avoid risk of div by 0.

Share this post


Link to post
Share on other sites

Alright I like the idea of the look up table. You think the table may be too big to fit into the 16k of memory of the msp430 ?

I will have to do more testing on my input signals to see if they may vary in scale. If they don't vary too much I can generate my table on excel or something and input this into the msp430.

 

Is the look up operation time intensive or is it a fairly quick operation ?

Share this post


Link to post
Share on other sites

Look up is quick, in general. Really quick. Time required is a couple compares, an add or subtract, and an array index operation, followed by adjustment for octant (a switch and an add or subtract, if the octant is coded as an integer [0..7]). Fast. The balance is time vs. size of code vs. needed accuracy.

 

 

A few numbers, presuming that you are doing no other processing with the values, and that you are producing an integer value for the DAC that is of similar resolution to the input value from the ADC:

 

If the result you need is a single byte and the inputs are 10 bit, and come properly scaled for conversion, you just use the input (after adjustment for quadrant) as an array index into an array of bytes. By working octants, the range of the inputs will be 0.71*half of the input range (figuring the zero input is a count of 0x200, or midrange), which is about 370 bytes. Probably on par with, or less than, the code size for arctan. Since this will also eliminate all of the fixed or floating point math (unless it is needed elsewhere) the table will probably be much smaller than calculating.

 

If you need 12 bit outputs, and have 12 bit inputs, the table will need to be about 2800 bytes. Still competitive on size if it eliminated the need for real math, and still kicks butt for speed. Ths table could be cut by 1/4 of its size by packing 2 12bit values into 3 bytes, at the expense of a few more operations at lookup time.

 

For the second case, I would probably, unless accuracy was critical--and at 12 bit inputs, I doubt the accuracy would be an issue-- reduce the table in size by a factor of 2, or 4, or even 8, and use interpolation. Even cutting by a factor of 4, I doubt that linear interpolation would produce any value would be more than one count from the ideal (least error) value, and the error would probably still be less than one count in all cases.  Again, this presumes using the sine or cosine input that is closer to zero to do the lookup, and the inputs need no scaling.

 

The error can be low because, for small angles, the sine of the angle is quite linear with the angle itself. This is more generally the case for sine, cosine, and tangent, when the function value is near zero, such as cosine for angles near a right angle, or sine near 180 degrees. Going to 45 degrees gets out of the really linear relation region, but it still isn't far enough out that a reasonably dense lookup table can't be used with linear interpolation. Note that the values in the table will be exact (more correctly, the least error value) conversion. Midrange between these is where the greatest error will occur.

 

 

Again, if the inputs are not properly scaled (the amplitude may  vary, such as with an unconditioned inductive quadrature pickup), the same technique works, but you build the table around tangent/cotangent values rather than sine/cosine, and you must divide the smaller input by the larger and scale the quotient to get the index, after selecting the quadrant. This will require floating point or fixed point arithmetic, and, though faster than the inverse trig function, may not save memory.

 

The next part is a little oversimplified, but substantially correct based upon the presumption of the ADC being a. monotonic, and b. linear to within 1lsb, and c. no missing codes. These are true for the MSP430, and most other modern devices. Often not even this good, in circuit, as noise, offset errors, etc, come into play, but reasonable for evaluating parameters of a design.

 

With 10bit ADC, the MAXIMUM you can get is about 2500 positions from the quadrature values. The highest resolution comes where sine or cosine are  zero, and this gives one ADC count is approximately 0.11 degree. Near the 45 degree point, one count is approximately 0.15 degree. With 12bit ADC, these are 0.03 and 0.04degree, approximately. You can't do better (ok, you can do a little better at 45degrees, at the expense of a lot of processing) These are you basic errors. Any work you do to try improving these without going to a higher resolution ADC is wasted.

Share this post


Link to post
Share on other sites

Since I am procrastinating on a fat load of paperwork, I'll give some sample (UNTESTED!) code for lookup table in this application:

// Preconditions:
// ADCsine has 10 bit ADC measurement representing the sine of the angle, scaled and offset so that
// 0x200=>10sin(0), 0x3ff=>1=sin(pi/2), 0x001=>-1=sin(-pi/2) (0, 90 and -90 degrees)
// The exclusion of 0x000 if for symmetry. 
// ADCcos has the corresponding cosine value. 
// Result:
// DACangle=> A value in the interval 0x0000 to 0x03ff, representing the angle, where 0x0000 is 0degrees, 0x0100 is 90 degrees 0x0200 
// is 180 degrees, etc. Degree measure D=DACangle*360/0x0400. This gives a resolution of 0.35 degrees for the 0 bit output

// No gaurantee that I didn't mess up a bound here...

// ID of octant can be more efficient... this is  sample and incomplete 
if (ADCsine>=0x200 && ADCcos>0x200) {// first quadrant
   if (ADCsine>=ADCcos) { // 45<=angle<90 degrees
      DACangle=0x0100-table[ADCcos-0x200];
   } else { // 0<=angle < 45degrees
      DACangle=table[ADCsine-0x200];
   }
} else if (ADCsine>0x200) { // second quadrant
   if (ADCsine>0x400-ADCcos) {
      // 90<=angle<135
   } else {
      // 135<=angle<180
   }
} else if ( // continue for other two quadrants... watch boundary conditions

// quadrant identified and angle is in DACangle

The table if defined as

// table has angle values corresponding to sines of angles 0<=angle<=45 degrees.
// 10 bit values for angle and for sine of angle, so the angle value for 45degrees is 0x0080
// THe total number of entries will be ceil( 0x0200*sine(45degrees)) = 362
// the table size will be 724bytes in this case

// Each entry will be arcsine(index/0x200) * 0x0400/(2pi), rounded as needed. The denominator should be 360 if degree mode arcsine is used.

unsigned table[]={ 0, 0, 1, 1, 1, 2, //....... fill out table until....


                            127, 128, 128 };

// Note that for 12 bit output, same thing, but multiple by 0x1000 rather than 0x0400
// for 12 bit input, divide index by 0x800 rather than 0x200

If is easy to see that the output resolution is such that the result will always have an error of less than one count, generally below the optimal max error of 1/2 count, based on the lookup. Doing a lot of arithmetic can do no better, but is slower.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×