simplefoc / Arduino-FOC

Arduino FOC for BLDC and Stepper motors - Arduino Based Field Oriented Control Algorithm Library
https://docs.simplefoc.com
MIT License
2.03k stars 521 forks source link

make foc_utils functions WEAK #262

Closed runger1101001 closed 1 year ago

runger1101001 commented 1 year ago

A change to enable alternative implementations of _sin() and _cos():

Tested this so far on STM32G4, where it has no impact on performance (none is expected since these are linker level things), and seems to work as expected in terms of the array: if I supply a different implementation of _sin() that just calls stdlib, the program size is 500 bytes smaller.

askuric commented 1 year ago

Makes sense, I like it. And would you be able to implement these functions in the arduino sketch?

runger1101001 commented 1 year ago

Yeah, in any cpp file that is part of the compile. But people can put them right in their sketch. I'm thinking of including an example also.

So if its ok, then I will merge this :-)

Then next I think we maybe have an optimised _sin() function - a little faster, a little more accurate and with built-in normalisation of the angle. I'm just testing it on various architectures. But I'll make a separate PR for you to examine when its ready.

FFiot commented 1 year ago

What do you think of these simple codes? https://github.com/FFiot/FF_FOC/tree/main/simpleFOC

runger1101001 commented 1 year ago

Hi @FFiot ,

Thank you for pointing this out!

I have tested it, and on the STM32G474 the arm_sin_f32 function is around 40-50% slower than the lookup table version we have. But it is more accurate than the lookup table version. It is considerably faster than the CORDIC for a single operation, but also a bit less accurate than the CORDIC.

It's certainly something people on ARM MCUs can consider using.

runger1101001 commented 1 year ago

For anyone interested here are my current timings on a STM32G474:

Timing CORDIC vs stdlib sin vs SimpleFOC Sine calculations...

CORDIC:
CORDIC Time (us) for 3217 steps: 6572
Result: 2048.00

SimpleFOC _sin:
SimpleFOC _sin time (us) for 3217 steps: 734
Result: 2048.00

stdlib sin:
stdlib sin time (us) for 3217 steps: 2714
Result: 2048.00

Deku sin:
Deku sin time (us) for 3217 steps: 793
Result: 2047.94

SimpleFOC sin + normalizeAngle:
SimpleFOC + normalizeAngle time (us) for 3217 steps: 2958
Result: 2048.00

Float257 Sine:
Float257 Sine time (us) for 3217 steps: 718
Result: 2048.00

Deku257 Sine:
Deku257 Sine time (us) for 3217 steps: 681
Result: 2048.00

Deku129 Sine:
Deku129 Sine time (us) for 3217 steps: 736
Result: 2047.99

Deku129i Sine:
Deku129i Sine time (us) for 3217 steps: 747
Result: 2047.93

ARM Sine:
ARM Sine time (us) for 3217 steps: 1099
Result: 2047.97

Comparing accuracy...
RMS difference between CORDIC and stdlib: 0.00000046
RMS difference between SimpleFOC and stdlib: 0.00125253
RMS difference between Deku256 Sine and stdlib: 0.00125757
RMS difference between Float Sine and stdlib: 0.00125250
RMS difference between Deku257 Sine and stdlib: 0.00125253
RMS difference between Deku129 Sine and stdlib: 0.00250501
RMS difference between Deku129i Sine and stdlib: 0.00003220
RMS difference between ARM Sine and stdlib: 0.00000971
Test complete.
askuric commented 1 year ago

Awesome overview @runger1101001,

I'd just like to add that when I wrote the _sin function I've verified that the error is under 0.001 radians against standard sin function. However, this error can be greatly improved by by using a bigger more precise lookup table.

FFiot commented 1 year ago

Compare on stm32G431CBU6。 Function arm_sin_cos_f32(angle, &_sin, &_cos) used 272 tickets, input in degrees and output 2 values. CORDIC used 172 tickets. Include input normalize and change to qint31, outputs change to float. CORDIC is good at large volumes of data processing with DMA.