Maximum sampling frequency of ANALOG INPUT through Arduino UNO

383 views (last 30 days)
Hi,
I am wondering what is the maximum frequency at which Matlab can sample analog inputs through an Arduino Uno board. The current code that I have been using is below.
. . .
clock = tic;
for j = 1 : (1000)
voltage (j) = readVoltage(a,'A0'); %analog in pin 'A0'
end % for j
b = toc (clock);
disp 'time: '
disp (b)
. . .
Using this code, it only samples at ~100Hz. Is there any way go get it to sample faster, as Arduino states that the board should be able to sample at 10 000Hz (https://www.arduino.cc/en/Reference/AnalogRead)
Thanks in advance!!

Answers (3)

Brian Rasnow
Brian Rasnow on 19 Oct 2022
Edited: Brian Rasnow on 27 Oct 2022
The Arduino package has enormous overhead, both in Matlab, and on the Arduino. I program the Arduino in C using its IDE to respond to simple commands, e.g.,
#define NUMSAMP 400
const int analogOutputPin = 5;
int data[NUMSAMP + 1][2], i;
unsigned long t0, t1;
void measureWaveformsBinary()
{ // return a buffer of data + sample time in microseconds
t0 = micros(); // time it to compute sample rate
for (i = 0; i < NUMSAMP; i++)
{
data[i][0] = analogRead(A0);
data[i][1] = analogRead(A1);
}
t1 = micros();
data[i][0] = t1 - t0; // put dt at end of data
data[i][1] = (t1 - t0) >> 16; // most significant 2 bytes
Serial.write((uint8_t*)data, (NUMSAMP + 1) * 2 * sizeof(int));
} // measureWaveformsBinary
void setup()
{
Serial.begin(115200);
} // setup
void loop()
{
if (Serial.available())
{
switch (Serial.read())
{
case 'p': // set pwm value
{
int pwmVal = Serial.parseInt();
analogWrite(analogOutPin, constrain(pwmVal, 0, 255));
break;
}
case 'b': // readAndWriteWaveformsBinary
{
measureWaveformsBinary();
break;
}
} // switch
}
delay(1);
} // loop
Upload that code to the Arduino in the IDE, then quit the IDE or disconnect it from the Arduino (set menu Tools -> Port -> to anything else), since serial devices can't be shared between apps. Now open a serial port to the Arduino. I haven't found a great way to identify the Arduino in the port list, but on my Macintosh, it's always the last in the list so, in Matlab:
ports = serialportlist;
ard = serialport(ports{end},115200)
ard.Timeout = 1;
clear ports;
pause(1); % time to boot
To read and plot the data, send the 'b' character to the Arduino and then read the buffer:
write(ard,'b','char');
bin = read(ard,802,'int16');
dt = bitshift(bin(802),16)+bin(801); % microseconds
data = reshape(bin(1:800),2,400)';
t = linspace(0,dt/1000,400)'; % calibrate the time axis
plot(t, data, '.-')
xlabel('msec'); ylabel('ADU')
legend('A0','A1');
Data is read at ~8.9kHz, each channel half of that and there is channel skew (which spline or fft can fix). This loops around 3 times per second, with plot being the bottleneck. h = plot(...) the first time, and changing the line data in the graphics objects speeds that up significantly. Want faster? I could get >20 frames per second with a Raspberry pi Pico or Teensy microcontroller (and 12 bits ...).
Added a uicontrol radiobutton to a figure to toggle an oscilloscope display, and you can nicely see audio waveforms and the like, using just Matlab and a $5 microcontroller.
  2 Comments
Brian Rasnow
Brian Rasnow on 27 Oct 2022
Edited: Brian Rasnow on 27 Oct 2022
Sorry, in compacting the code here I deleted its definition --
const int analogOutputPin = 5;
I use pin D5 for PWM output. The Arduino responds to 2 commands. write(ard, 'b','char); returns a block 400 analog time series on A0 and A1, appended with the elapsed microseconds measured on the arduino. The other command, write(ard, 'p 128', 'char); tells Arduino to analogwrite(D5,128); , i.e., set pin D5 to analog voltage ~ 2.4V.

Sign in to comment.


Sam McDonald
Sam McDonald on 6 Mar 2017
Although the maximum reading rate for the analog pin is 10 kHz, this speed cannot be guaranteed with serial communication via Arduino and MATLAB. In other words, there is overhead involved by calling the "readVoltage" function in MATLAB, collecting the signal value from the Arduino pin, and sending it back to MATLAB. It is difficult to say what the theoretical maximum frequency is for data collection, other than performing tests similar to what you have done here.
You can perform a more in-depth analysis on performance by running the profiling tool:
That may help you gain more insight into how much time each function takes to execute, such as the "readVoltage" function.

Alberto Mora
Alberto Mora on 29 Dec 2018
Edited: Alberto Mora on 17 Dec 2020
Dear Valentin, I notice the same problem, and I'm also looking for a solution.
At the moment I have adopted the follow approach with discrete results:
  1. analogRead in Arduino environment
  2. Matlab in a while loop, read the data of serial port coming from Arduino
  3. Arduino print the analog value on the serial port, like:
Serial.print( millis() ); Serial.println( signal1_column )
In this last case, the speed is limited to the serial bus. In this way I reached a sampling of about 1-2kHz (even 3kHz but not very stable).
Note: a nice tip to speed up the serial bus is to increase the BaudRate, probably 9600 is too small! Anyhow you will not reach higher frequency of few kHz.
Anyhow I am not sure that is the best approach.
Regards,
A
  13 Comments
Walter Roberson
Walter Roberson on 2 Feb 2021
I mentioned about USB. If you are connecting the arduino to the matlab host using USB, then it is impossible to get more than 1000 transactions per second, as that is the USB 2 limit and arduino do not have USB 3. Each transaction can be a full buffer of up to 1020 (iirc) bytes with USB 2.1, slightly different for other USB versions. That is bytes, not samples. Each sample will typically need multiple bytes. If you are using print or println then the data is formatted as text, which can take roughly 4 times as much space as the number of bytes per sample. You also need delimiters between the samples if you are using text; println uses newline delimiter. println is often not as efficient to process as packing multiple text samples per line before a newline. Sending text is never as efficient as sending binary instead.
If you are using USB then the baud rate is mostly ignored.
It is also possible to connect arduino to matlab host using a true rs232 serial port. If that is done then the serial port speed does matter, and the latency is lower and you can get higher transactions per second. Noise can be more of a problem though: USB is more immune to noise because of the hardware specifications and ways it transmits.

Sign in to comment.

Categories

Find more on MATLAB Support Package for Arduino Hardware in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!