daily_automated

This commit is contained in:
topicchi
2023-03-17 11:59:21 +00:00
parent 252ecca9cf
commit e2f276193e
4496 changed files with 1178007 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@@ -0,0 +1,98 @@
Static Tests of the Arduino Internal ADC.
Several people have asked about the DC accuracy of the Arduino ADC when used in my data logging applications at slow sample rates.
Here are my results of some "hobby level" measurements of the Arduino ADC.
One question is how important is the ADC clock rate. I did measurents for an ADC clock rate of 125 kHz to 2MHz.
Another question is how much does Noise Reduction Mode help. I did a series of measurements using this mode.
Noise Reduction Mode only reduced the mean absolute error slightly.
I do calibration to remove Offset Error and Gain Error. Calibration is very important for good accuracy.
These tests depend on the Arduino voltage regulator providing a stable voltage during the tests. The Arduino ADC reference voltage is Vcc for these tests. This may not be realistic for practical applications
Integral Non-linearity (INL) is the main remaining source of error.
Here are my results for static (DC) tests of the internal ADC for three UNOs.
The Arduinos are powered by a high quality nine volt power supply.
These tests measure a DC level so do not include problems due to time jitter, S/H time, and other dynamic errors.
There are several studies of the dynamic behavior of the Arduino ADC that determine ENOB (Effective Number Of Bits).
I used a shield with a 12-bit MCP4921 DAC to generate voltage levels. This ADC has an output buffer so it provides a very low impedance source.
I measured the voltage of the DAC with a calibrated 18-bit MCP3422 ADC on the shield.
I used DAC levels from 20 to 4075 to avoid zero offset errors at low voltages and DAC buffer problems at high voltages.
Each series of measurements has 4056 data points.
This is a voltage range of about 0.023 to 4.972 volts.
I calibrated the Arduino ADC for each series of measurements with a linear fit of the form.
v = a + b*adcValue
Errors are the difference between the value measured with the 18-bit ADC and the calibrated value measured with the AVR ADC.
I also show the results for no calibration, the NoCal column, using the datasheet formula.
Vin = Vref*adcValue/1024
The rows in the tables tables are.
Min - minimum error in millivolts
Max - maximum error in millivolts
MAE - mean absolute error in millivolts
The columns in the tables are:
Ideal - results for a perfect 10-bit ADC for comparison.
NoCal - datasheet formula (5/1024)*adcValue with Noise Reduction Mode.
NR128 - Noise Reduction mode with Prescaler of 128 (ADC clock of 125 kHz).
PS128 - analogRead with Prescaler of 128 (ADC clock of 125 kHz).
PS64 - analogRead with Prescaler of 64 (ADC clock of 250 kHz).
PS32 - analogRead with Prescaler of 32 (ADC clock of 500 kHz).
PS16 - analogRead with Prescaler of 16 (ADC clock of 1 MHz).
PS8 - analogRead with Prescaler of 8 (ADC clock of 2 MHz).
Results for three UNO Arduinos
First Arduino - Error Millivolts
Ideal NoCal NR128 PS128 PS64 PS32 PS16 PS8
Min -2.44 -2.43 -3.72 -4.01 -3.88 -4.53 -6.57 -27.18
Max 2.44 11.69 3.74 4.24 4.15 5.17 8.69 23.21
MAE 1.22 5.02 1.33 1.38 1.37 1.44 1.96 4.11
Second Arduino - Error Millivolts
Ideal NoCal NR128 PS128 PS64 PS32 PS16 PS8
Min -2.44 -9.24 -4.87 -4.86 -5.05 -5.34 -6.52 -24.04
Max 2.44 11.62 3.95 4.64 4.69 5.71 8.41 21.29
MAE 1.22 5.33 1.41 1.43 1.44 1.53 2.02 4.05
Third Arduino - Error Millivolts
Ideal NoCal NR128 PS128 PS64 PS32 PS16 PS8
Min -2.44 -7.88 -4.12 -4.40 -4.32 -4.41 -6.97 -26.93
Max 2.44 12.53 3.80 4.04 4.18 5.27 8.84 24.59
MAE 1.22 4.85 1.29 1.33 1.34 1.42 1.91 4.10

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,21 @@
Maximum Sample Rate Table
ADC clock kHz
125 250 500 1000
pins
1 7692 14286 25000 40000
2 3810 6667 11111 16667
3 2572 4790 8421 13559
4 1942 3636 6452 10526
5 1559 2930 5229 8602
6 1303 2454 4396 7273
7 1119 2111 3791 6299
8 980 1852 3333 5556
9 872 1649 2974 4969
10 786 1487 2685 4494
11 715 1354 2446 4103
12 656 1242 2247 3774
13 606 1148 2078 3493
14 563 1067 1932 3252
15 525 996 1806 3042
16 493 935 1695 2857

View File

@@ -0,0 +1,39 @@
#ifndef AnalogBinLogger_h
#define AnalogBinLogger_h
//------------------------------------------------------------------------------
// First block of file.
struct metadata_t {
unsigned long adcFrequency; // ADC clock frequency
unsigned long cpuFrequency; // CPU clock frequency
unsigned long sampleInterval; // Sample interval in CPU cycles.
unsigned long recordEightBits; // Size of ADC values, nonzero for 8-bits.
unsigned long pinCount; // Number of analog pins in a sample.
unsigned long pinNumber[123]; // List of pin numbers in a sample.
};
//------------------------------------------------------------------------------
// Data block for 8-bit ADC mode.
const size_t DATA_DIM8 = 508;
struct block8_t {
unsigned short count; // count of data bytes
unsigned short overrun; // count of overruns since last block
unsigned char data[DATA_DIM8];
};
//------------------------------------------------------------------------------
// Data block for 10-bit ADC mode.
const size_t DATA_DIM16 = 254;
struct block16_t {
unsigned short count; // count of data bytes
unsigned short overrun; // count of overruns since last block
unsigned short data[DATA_DIM16];
};
//------------------------------------------------------------------------------
// Data block for PC use
struct adcdata_t {
unsigned short count; // count of data bytes
unsigned short overrun; // count of overruns since last block
union {
unsigned char u8[DATA_DIM8];
unsigned short u16[DATA_DIM16];
} data;
};
#endif // AnalogBinLogger_h

View File

@@ -0,0 +1,82 @@
#include <stdio.h>
#include "AnalogBinLogger.h"
FILE *source;
FILE *destination;
int count = 0;
int main(int argc, char** argv) {
metadata_t meta;
adcdata_t adc;
// Make sure no padding/size problems.
if (sizeof(meta) != 512 || sizeof(adc) != 512) {
printf("block size error\n");
return 0;
}
if (argc != 3) {
printf("missing arguments:\n");
printf("%s binFile csvFile\n", argv[0]);
return 0;
}
source = fopen(argv[1], "rb");
if (!source) {
printf("open failed for %s\n", argv[1]);
return 0;
}
if (fread(&meta, sizeof(meta), 1, source) != 1) {
printf("read meta data failed\n");
return 0;
}
if ( meta.pinCount == 0
|| meta.pinCount > (sizeof(meta.pinNumber)/sizeof(meta.pinNumber[0]))
|| meta.adcFrequency < 50000 || meta.adcFrequency > 4000000) {
printf("Invalid meta data\n");
return 0;
}
destination = fopen(argv[2], "w");
if (!destination) {
printf("open failed for %s\n", argv[2]);
return 0;
}
int pinCount = meta.pinCount;
printf("pinCount: %d\n", pinCount);
printf("Sample pins:");
for (unsigned i = 0; i < meta.pinCount; i++) {
printf(" %d", meta.pinNumber[i]);
}
printf("\n");
printf("ADC clock rate: %g kHz\n", 0.001*meta.adcFrequency);
float sampleInterval = (float)meta.sampleInterval/(float)meta.cpuFrequency;
printf("Sample rate: %g per sec\n", 1.0/sampleInterval);
printf("Sample interval: %.4f usec\n", 1.0e6*sampleInterval);
fprintf(destination, "Interval,%.4f,usec\n", 1.0e6*sampleInterval);
// Write header with pin numbers
for (int i = 0; i < ((int)meta.pinCount - 1); i++) {
fprintf(destination, "pin%d,", meta.pinNumber[i]);
}
fprintf(destination, "pin%d\n", meta.pinNumber[meta.pinCount - 1]);
unsigned maxCount = meta.recordEightBits ? DATA_DIM8 : DATA_DIM16;
while (!feof(source)) {
if (fread(&adc, sizeof(adc), 1, source) != 1) break;
if (adc.count > maxCount) {
printf("****Invalid data block****\n");
return 0;
}
if (adc.overrun) {
fprintf(destination, "Overruns,%d\n", adc.overrun);
}
for (int i = 0; i < adc.count; i++) {
unsigned value = meta.recordEightBits ? adc.data.u8[i] : adc.data.u16[i];
if ((i + 1)%pinCount) {
fprintf(destination, "%d,", value);
} else {
fprintf(destination, "%d\n", value);
}
}
count += adc.count;
}
printf("%d ADC values read\n", count);
fclose(source);
fclose(destination);
return 0;
}

View File

@@ -0,0 +1,95 @@
AnalogBinLogger.ino logs analog data to a binary SD file at high rates.
Samples are logged at regular intervals by using timer1. Timer/Counter1
Compare Match B is used to trigger the ADC for the first pin in a sample.
The ADC is triggered for remaining sample pins in the ADC conversion complete
interrupt routine.
Data is captured in the ADC interrupt routine and saved in 512 byte buffers.
Buffered data is written to the SD in a function called from loop(). The
entire data set is written to a large contiguous file as a single multi-block
write. This reduces write latency problems.
Many inexpensive SD cards work well at lower rates. I used a $6.00
SanDisk 4 GB class 4 card for testing.
SanDisk class 4 cards work well at fairly high rates. I used the 4 GB SanDisk
card to log a single pin at 40,000 samples per second.
You may need to increase the time between samples if your card has higher
latency. Using a Mega Arduino can help since it has more buffering.
The bintocsv folder contains a PC program for converting binary files to
CSV files. Build it from the included source files. bintocvs is a command line program.
bintocsv binFile csvFile
AnalogBinLogger requires a recent version of the SdFat library. The SdFat
folder contains a beta version I used for development.
The latest stable version is here:
http://code.google.com/p/sdfatlib/downloads/list
You also need to install the included BufferedWriter library. It provides
fast text formatting.
Example data for a 2 kHz sine wave logged at 40,000 samples per second is
shown in DATA.PNG and FFT.PNG shows a FFT of the data. See ExcelFFT.pdf
in the ADCdocs folder for details on calculating a FFT.
The accuracy of the ADC samples depends on the ADC clock rate. See the
ADC_ENOB.PNG file for a plot of accuracy vs ADC clock frequency.
See files in the ADCdocs folder for more information on ADC accuracy.
To modify this program you will need a good knowledge of the Arduino
ADC, timer1 and C++ programming. This is not for the newbie.
I have an LED and resistor connected to pin 3 to signal fatal errors and
data overruns. Fatal errors are indicated by a blinking led. Overrun errors
are indicated by a solid lit led. The count of samples dropped is written
to the SD and data logging continues.
You can disable the error led feature by setting the error pin number negative:
To use AnalogBinLogger, install these items.
Place the BufferWriter and SdFat folders in your sketchbook libraries folder.
Place the AnalogIsrLogger folder in your sketchbook folder.
You must edit the configuration constants at the beginning of the program
to set the sample pins, sample rate, and other configuration values.
Initially the program is setup to log the first five analog pins at 5000
samples per second. Change these values to suit your needs.
See RateTable.txt for maximum allowed sample rates vs pin count and ADC clock
frequency.
The program has four commands:
c - convert file to CSV
d - dump data to Serial
e - overrun error details
r - record ADC data
All commands can be terminated by entering a character from the serial monitor.
The c command converts the current binary file to a text file. Entering a
character on the serial monitor terminates the command.
The d command converts the binary file to text and displays it on the serial
monitor. Entering a character on the serial monitor terminates the command.
The e command displays details about overruns in the current binary file.
Data overruns happen when data samples are lost due to long write latency
of the SD.
The r command will record ADC data to a binary file. It will terminate
when a character is entered on the serial monitor or the the maximum file
block count has been reached.
A number of program options can be set by changing constants at the beginning
of the program.