Monday, 17 February 2025

A floating point test for Arduino

 

How to choose the Arduino MCU for fast and double precision data processing

Giovanni Carrera, 17/02/2025

In some applications it is necessary to perform calculations in double precision, such as in the coordinate conversion of a GNSS receiver. This problem arises when I want to interface a satellite receiver with Arduino compatible boards.

At the moment it seems that floating point calculations performed with MicroPython are single precision only.

Google Maps wants the latitude and longitude in decimal degrees, so it is necessary to extract the substrings of the prime minutes from the coordinates of the NMEA sentences, and convert them into float numbers and then in tenths of a degree.

Operating with single precision variables, that is with 6-7 significant digits, you get about five decimal digits on decimal degrees, this leads to a horizontal resolution of about one meter, lower than the error of a common GNSS receiver. But if I want to do statistical calculations or work with RTK receivers this resolution is no longer acceptable. The RTK differential receivers, that work on the carrier phases, have a centimetre accuracy and provide the coordinates with 6-7 decimal digits on minutes, like the ones I used in my program. For these considerations it is necessary to use an MCU (Micro Controller Unit) that has a true double precision math.

For some MCUs it is not always clear how the floating point arithmetic is actually calculated, so I wrote a test program for the conversion from degrees and minutes in decimal degrees.

First I wrote my program on PC, in Matlab which operates in double precision. I started from the coordinates expressed in string, I convert the degrees and minutes into numbers, then in decimal degrees.

Lats = '4221.0081996';

Longs = '01321.4740622';

lat = str2double(Lats(1:2)) + (str2double(Lats(3:end))/60);

long = str2double(Longs(1:3))+ (str2double(Longs(4:end))/60);

fprintf('latitude    = %s \n',Lats);

fprintf('longitude   = %s \n',Longs);

fprintf('latitude (dec)  = %12.9f°\n',lat);

fprintf('longitude (dec) = %12.9f°\n',long);

 

With the coordinates indicated it gave the following results:

latitude    = 4221.0081996

longitude   = 01321.4740622

latitude (dec)  = 42.350136660°

longitude (dec) = 13.357901037°

 

So I wrote the following Arduino IDE program to evaluate the numerical results and processing times of the various MCUs on which I performed the test.

/* program doubletest.ino

 test double precision of MCU

 Giovanni Carrera, 14/10/2019*/

 

const String Lats = "4221.0081996";

const String Longs = "01321.4740622";

 

void setup(void) {

  Serial.begin(115200);

  while (!Serial) {

    ; // wait for serial port to connect

  }

  delay(100);

  Serial.println("MCU double precision test");

  // convert Lat&Long in decimal format

  unsigned long  ti= micros();

  String minuts = Lats.substring(2);// latitude minutes

  double minutes = minuts.toFloat();// convert it to float

  double decdeg = minutes/60.0;

  String Latdegs = Lats.substring(0,2);

  double Latd = Latdegs.toFloat() + decdeg;// latitude in decimal format (double)

  minuts = Longs.substring(3);// longitude minutes

  minutes = minuts.toFloat();// convert it to float

  decdeg = minutes/60.0;

  String Longdegs = Longs.substring(0,3);

  double Longd = Longdegs.toFloat() + decdeg;// longitude in decimal format (double)

  unsigned long  tf= micros();

  Serial.print("Latitude (dec)  = ");

  Serial.println(Latd,8);

  Serial.print("Longitude (dec) = ");

  Serial.println(Longd,8);

  Serial.print("elaboration time [us] = ");

  Serial.println(tf-ti);

} // end of setup

 

 

void loop() {

}

 

I tried this program also on 8 bit processors like the Arduino Uno to verify that the double precision is simulated and also on Teensy v3.2 that mount a 32-bit MCU type ARM Cortex-M4 at 72 MHz but that does not have a true 64-bit mathematics. So I narrowed down the study to six types of MCUs that yielded the same numerical results.

 

ESP8266

This module uses a 32-bit MCU clocked at 80 MHz. I ran the test program on a ESP8266 type Wemos D1 mini which features an ESP-12F module, with the results:

MCU double precision test

Latitude (dec)  = 42.35013666

Longitude (dec) = 13.35790103

elaboration time [us] = 388

Correct numerical results even if processed with relatively high times.

 

ESP32

This interesting and versatile module uses a single/dual-core 32-bit LX6 Xtensa MCU clocked at up to 240 MHz. I ran the test program on a Node MCU development board with ESP32 WROOM.

MCU double precision test

Latitude (dec)  = 42.35013666

Longitude (dec) = 13.35790103

elaboration time [us] = 152

Numerically correct values with very good processing times. I also obtained similar results with an ESP32 WROVER.

 

Arduino Due

I used an original Arduino board, the first to mount a 32-bit processor, using an Atmel SAM3X8E ARM Cortex-M3 clocked at 84 MHz.

MCU double precision test

Latitude (dec)  = 42.35013666

Longitude (dec) = 13.35790103

elaboration time [us] = 141

Correct results and with the best execution times.

 

Arduino Zero

For this test I used a Maduino A9G board, an Arduino Zero compatible, which mounts a 32 bit MCU type ATSAMD21G18 clocked at 48MHz and an A9G module that combines a GPRS / GSM terminal and a GPS / BDS satellite receiver on which I developed also a data logger program for satellite data

MCU double precision test

Latitude (dec)  = 42.35013666

Longitude (dec) = 13.35790103

elaboration time [us] = 250

 

Teensy 4.0

Teensy 4.0 has a 600 MHz ARM Cortex-M7 processor, an NXP iMXRT1062 chip, and is the fastest microcontroller available at the moment.

MCU double precision test

Latitude (dec)  = 42.35013666

Longitude (dec) = 13.35790103

elaboration time [us] = 5

 

Arduino Uno R4

This recent board mounts a Renesas R7FA4M1AB3CFM#AA0 processor type Arm® Cortex®-M4. at 48 MHz.

MCU double precision test

Latitude (dec)  = 42.35013666

Longitude (dec) = 13.35790103

elaboration time [us] = 184

 

Conclusions

The following table summarizes my test results.

board

MCU

CPU clock [MHz]

time [µs]

Arduino Due

Atmel SAM3X8E ARM Cortex-M3

84

141

ESP32 WROOM

Xtensa single-/dual-core 32-bit LX6

240

152

Arduino Zero

ATSAMD21G18

48

250

Wemos D1 mini

ESP8266EX, Tensilica L106

80

388

Teensy 4.0

ARM Cortex-M7

600

5

Arduino Uno R4

Arm Cortex-M4

48

184

The system that gave the best results is Teensy 4.0, followed by Arduino Due, which I had already used in the past for GNSS RTK data processing. Considering the performance/price ratio, the ESP32 is certainly the best system.