Trouble with a float equation, possible to get the same effect with int?

Hi

first the code in question

float steps;
 steps =(float)((float) StepsPerCalc / (float)StepsInArray);   //work out how often to put 1's
 for( float i =0; i<(float)StepsPerCalc; i+=steps){       // Iterate through the array and distribute the 1's at the calc interval
      whichArray[(int)i]=1; // distribute the steps.
  }

The above piece of code takes a fixed length array (at the moment set at 75) and then takes a variable number of steps (an int) and evenly distributes them in the array. It seems to works great, but i am having an issue with the length of time it takes to populate the array (i’m guessing because of the float calcs?) from my timing it seems to take between 900us and 5ms to complete (dependent on the number of steps to distribute) which for what i’m trying to do is a little too long. i ideally need to get it sub millisecond.

Any idea how i can convert this to int math ? i was reading about modulo maybe? or try multiplying out the ints first to get a couple of pseudo decimal places of precision?

The array is populated with a series of ones and zeros which then feed an interrupt driven pulse function that drives a stepper motor. What i’m doing (semi successfully) is building a compound sinusoidal motion profile on the fly. I’m doing the sin() approximations with a folded look up table which is really quick, but when the array propagation takes more than 1ms (the timer interrupt) the stepper runs out of steps and stops for a milliseconds leading to a move clunk… move clunk… etc

I’ve rewritten the code to use 2 separate arrays which are alternated (i.e. array1 is stepped as array2 is calc’d then they swap.) with some (little) success, but it makes the code a lot more complex than i wanted.

Any thoughts or ideas on how to approach this would be greatly appreciated. Or am i pushing the proverbial up hill and should look at porting to a raspi or something else with some floating point ability

Hi,

I'm doing the sin() approximations with a folded look up table which is really quick...

Given the facts that the processor has significantly more Flash than SRAM, reading constants from Flash is only a few clock cycles more than reading from SRAM, and you are working with constants why don't you put the full (pre-calculated) table in Flash?

They aren't constants, the table is precalculated but i havent found the need to put it on flash, its a unsigned 8bit int table, its not like its huge.

The number of steps varies from 0 to 70 at almost every interval. i suppose i could store 70 precalculated arrays? but that would become limiting pretty quickly. As i increase microstepping i need to increase the step rate and therefore the array size to get it to work as expected and avoid clipping issues.

Heres the flow, so hopefully it will make some more sense

Start at position 0. at that point our equation gives us a distance of zero. so we calculate an array with 0 steps. process the 75 0's in the array and flag for a recalculation.

We move to position 1, calculate a distance of 60 steps, from there we subtract the previous position from the new position and get 60 steps. (this works fine) the array is then calculated to distribute steps every 1.25 positions i.e. 1010101110101011 (or something like that) thats when we have issues. from the time the step ISR stops and flags the calc we have 1ms before it will try and pickup the array again and keep going. (the array is locked while calculating so when the 1ms is up the stepper stops until the calc is complete i.e. ~3-4ms later, this results in a "clunk". which isnt great given what i'm trying to achieve using a sin profile :D

I'm using a modifed version of this for the lookup table http://forum.arduino.cc//index.php?topic=196625.msg1453433#msg1453433

first the code in question

I'm sure that the fine folks at http://snippets-r-us.com will be able to help you with your snippets.

One thing to note, though, is that only one value in an equation needs to be a float in order to have floating point math performed. The result will be a float. It is rarely necessary to cast a float to a float.

Is this faster?
The amount of float operations is less

  float stepSize =  ((float) StepsPerCalc / StepsInArray ; // add rounding but go back to integer

  for( int i = 0; i < StepsInArray ; i++) 
  {
    whichArray [ i * stepSize ] = 1;   // distribute the steps.
  }

Other trick is to multiply it with a power of 2 and divide it back

  uint16_t stepSize =  16 * StepsPerCalc / StepsInArray ;

  for( int i = 0; i < StepsInArray ; i++) 
  {
    whichArray [ (i * stepSize) >> 4 ] = 1;   // distribute the steps.
  }

does it work?
how fast?

This last solution here is actually a fixed point arithmetic solution, with four binary digits to the right of the fixed point.

IMHO fixed point arithmetic of this sort is often a good solution to many problems when using processors where integer arithmetic is much faster than floating point, and there are integer word sizes available which are large enough that the remaining integer bits are sufficient for the problem to hand.

PaulS:

first the code in question

I’m sure that the fine folks at http://snippets-r-us.com will be able to help you with your snippets.

One thing to note, though, is that only one value in an equation needs to be a float in order to have floating point math performed. The result will be a float. It is rarely necessary to cast a float to a float.

The reason for not posting the entire code is mainly because its quite large, and secondly apart from having two int’s passed to it from the code stream and returning an array back to the main routine is completely isolated from the remainder of the code base. The code functions perfectly, i just need to speed it up a little.

So then given the only places i need to floating point precision are in steps and i i could chop it down to something like

float = ( StepsPerCalc  / StepsInArray );   //work out how often to put 1's
 for( float i =0; i< StepsPerCalc; i+=steps){       // Iterate through the array and distribute the 1's at the calc interval
      whichArray[(int)i]=1; // distribute the steps.
  }

What's wrong with the fixed point solution? To me it seems the ideal solution to your problem. Then you don't need any floating point numbers at all. Unless you receive your step size as a floating point argument to your function, in which case you only need to do one multiplication and conversion to integer to create a fixed point increment.

TangledWires: What's wrong with the fixed point solution? To me it seems the ideal solution to your problem. Then you don't need any floating point numbers at all. Unless you receive your step size as a floating point argument to your function, in which case you only need to do one multiplication and conversion to integer to create a fixed point increment.

I was getting to that :D thats the problem with being single threaded myself :) i can only reply to one post at a time.

I responded to the first question just to clarify i understood what he meant. Just in case the need arises in the future to do something like that, if i check now, i'll know later and wont have to bug you guys constantly

robtillaart:
Other trick is to multiply it with a power of 2 and divide it back

  uint16_t stepSize =  16 * StepsPerCalc / StepsInArray ;

for( int i = 0; i < StepsInArray ; i++)
  {
    whichArray [ (i * stepSize) >> 4 ] = 1;   // distribute the steps.
  }



does it work? 
how fast?

Ah this is what i just started reading about , that’s the problem when you’re new. you don’t know whats possible so you have no idea what to google.

I’ll give it a crack as see how it goes. (im at work at the moment so i cant try it straight away.)

So that >> thing is bitshifting?

float = ( StepsPerCalc  / StepsInArray );   //work out how often to put 1's

You can’t have a variable (of any type) named float. That’s a reserved keyword, for obvious reasons.

 for( float i =0; i< StepsPerCalc; i+=steps){       // Iterate through the array and distribute the 1's at the calc interval

Was there supposed to be a variable called steps called out in that statement above?

yes,

it appears when i was editing the comment i accidentally chopped steps rather than float.

speshnz: So that >> thing is bitshifting

Yes, bitshifting. I don't know exactly how much you know about bitwise operations, but if you are programming on a platform with limited memory and performance, knowing bitwise operations is IMHO really, really, useful.

robtillaart:
Other trick is to multiply it with a power of 2 and divide it back

  uint16_t stepSize =  16 * StepsPerCalc / StepsInArray ;

for( int i = 0; i < StepsInArray ; i++)
  {
    whichArray [ (i * stepSize) >> 4 ] = 1;   // distribute the steps.
  }



does it work? 
how fast?

Just remembered i have a nano under my desk logging temp data :smiley:

So i just hacked the code snip into a the same timing routine i used last time (so if my timing is bad, at least it should be consistently bad :D)

With all that float we were getting a return at worst about 4.8ms later, with that code piece the response seems to hover between 200us and 600us for an array of 100 steps the other calcs take about 23us so i’m well within my window which is awesome.

Thanks i appreciate you help, more tricks to add to the collection

Yeah,

I'm starting to work this out :)

That's the problem when you're first starting out, there's a lot of solutions to problems, but you have no idea which is best or in some cases which exist :)

I will add bitwise operations to my reading list.

Thanks to you too, i appreciate you help