电子说
步骤1:什么是AD转换器?
AD转换器是一种能够将模拟(连续)量转换为数字(离散)值的电路。这意味着什么?这意味着尽管数字值只能假设零和一的组合所形成的离散值,但模拟量可以假设范围内的任何值。例如,如果我们测量理想AA电池的电压,则可以找到0V至1.5V之间的任何值,因为这是模拟量。理想灯的输出状态必须仅假设两个状态(关闭或打开),这是一个离散的幅度。由于微控制器使用这种离散逻辑工作,因此我们需要一种能够将模拟量转换为数字量(或离散量)的电路。
步骤2:使用的资源
•一根Lolin32 Lite卡v1.0.0
•一台用于捕获的Tektronix TDS1001C示波器
•一根用于ESP32的USB电缆
•将Hantek DSO4102C示波器用作信号发生器
步骤3:ESP32 ADC
根据Espressif数据,ESP32芯片可能在测量结果中,从一个芯片到另一个芯片的误差为+/- 6%。
此外,该转换对于每个可用的读取范围都没有线性答案。乐鑫提供了一种校准方法,建议用户在认为有必要达到所需精度时采用其他方法。
我们将进行数据采集,并从中显示ADC响应和应用数学过程读取调整的示例。
有几种(更简单或更复杂的)方法可以完成这些修正。由您决定最适合您的项目。
此处显示的内容具有说明性目的,并尝试解决在调整过程中可以观察到的有趣点。
步骤4:使用的电路
我使用了示波器,其信号发生器的频率高达25 MHz,即Hantek DSO4102C。我们产生了由ESP A/D和示波器读取的波形。收集的数据记录在csv和电子表格中,我将在文章末尾进行下载。
第5步:使用过的符号
我们选择了一个低频梯形信号,该信号可以访问整个转换范围内的斜坡。
步骤6:示波器获得的数据
捕获由示波器执行。数据存储在csv文件中。请注意信号的上升和下降斜率上的轻微弯曲。
步骤7:示波器获得的数据(Excel中的csv文件)
我们在这里进行采样。
步骤8:ADC获得的数据
通过更改传输串行速率,我们可以查看ADC捕获的数据。观察梯形信号的变形。
在Arduino IDE串行绘图仪上观察到的数据
步骤9:ADC获得的数据-Excel
使用更高的速率和串行终端,我们可以捕获值并将其应用到Excel中进行比较。
步骤10:爬坡的比较
我们比较两个挡块的两个攀登坡道。
请注意两个坡道上出现的曲率。
请注意同样,对于相同的斜坡,ESP32的采样数要比示波器多。
步骤11:计算采样数
由于ESP32提供的样本数量比示波器多,因此我们需要将这些值均等化,因为它们将用作比较两条曲线的指标。
为此,我们将进行直接比较。
我们有305个示波器斜坡样本和2365个ADC斜坡样本。
因为这些斜坡属于在相同的范围内,可以说每个示波器大约有7.75个ADC采样。
将每个示波器采样的索引乘以相同的曲线,但是索引等于ADC和重新分配的数据。
要填充新职位的缺失数据,我们将应用一条曲线,以统计方式拟合已知数据。
步骤12:填补空白-趋势线
选择已知数据(蓝点),方法是单击,然后用右键单击,我们选择:“添加趋势线。. 。”
在出现的窗口中,我们选择多项式类型(阶数2就足够了。)
我们还选中了“在图表中查看方程式”和“显示”图表中的R平方值”。
我们单击“关闭”。
步骤13:填补空白-2级多项式曲线
Excel为我们提供了两条新信息:
请记住,距离1越近,方程越合适。
我们不需深入研究所涉及的数学,而仅将其用作工具即可。
步骤14:填补空白-评估函数
让我们填补用等式生成的数据在采样间隙中。然后,逐点比较它们。
y = -9E-08x2 + 0,0014x + 0,1505
R²= 0 ,9999
示波器电压= -9E-08 * index2 + 0,0014 * index + 0,1505
步骤15:将示波器电压转换为等效值以与ADC进行比较
让我们利用这一点还将示波器电压的值转换为等效ADC
由于在ESP32的ADP中获得的最高值为4095,相当于相同索引的2.958V读数,我们可以这样说:
每个示波器的测量电压大约等于AD的1384.4单位。因此,我们可以将示波器的所有测量值乘以该值。
步骤16:比较获得的两个斜坡
可视化
步骤17:ADC读数差异的行为(错误)
下面的曲线显示了ADC读数的差异如何随测量变化的行为。通过收集这些数据,我们可以找到校正函数。
要找到此曲线,我们只需绘制每个度量中的差异作为每个可能AD位置(0至4095)的函数即可。
p》
步骤18:ADC读取差异行为-查找校正函数
我们可以在Excel中通过添加趋势线来确定校正函数,现在已达到较高的程度,直到它完全适合我们的数据为止。
步骤19:使用其他软件
用于确定曲线的其他有趣软件是PolySolve,可直接在以下链接上使用:https://arachnoid.com/polysolve/或作为Java应用程序下载
它允许应用高级多项式回归和格式化函数以及其他功能的交付。
要使用它,只需在第一行文本中输入数据即可。框。数据必须遵循X,Y的顺序,并以逗号或制表符分隔。请谨慎使用正确的点作为小数点。
如果正确设置了输入数据的格式,则会在下一个框中显示一个图表。
这是我们ADC误差曲线的变化方式。
此窗口将显示回归的结果,包括函数充足性数据,该数据可以用几种方式格式化其输出:作为C/C ++函数,系数列表,函数
注意:注意小数点分隔符
步骤20:常量和设置()
I在此处指出用于模拟捕获的GPIO。我初始化了串行端口以及用于模拟捕获的引脚。
const int pin_leitura = 36; //GPIO usado para captura analógica
void setup() {
Serial.begin(1000000); //Iniciciando a porta serial somente para debug
pinMode(pin_leitura, INPUT); //Pino utilizado para captura analógica
}
步骤21:循环()和校正函数
我们会捕获调整后的电压,然后打印带有或不带有正确校正的值。
void loop() {
int valor_analogico = analogRead(pin_leitura); //realiza a captura da tensão ajustada
//Serial.print(valor_analogico + f(valor_analogico)); //imprime os valores para debug (COM CORREÇÃO)
Serial.print(valor_analogico); //imprimime os valores para debug (SEM CORREÇÃO)
Serial.print(“,”);
Serial.print(4095);//cria uma linha para marcar o valor máximo de 4095
Serial.print(“,”);
Serial.println(0); //cria uma linha para marcar o valor mínimo de 0
}
第12行中的通知中,我们可以选择使用
步骤22:使用PolySolve校正函数
在这里,我们在Arduino IDE内部使用PolySolve函数
/*
Mode: normal
Polynomial degree 6, 2365 x,y data pairs
Correlation coefficient (r^2) = 9,907187626418e-01
Standard error = 1,353761109831e+01
Output form: C/C++ function:
Copyright © 2012, P. Lutus -- http://www.arachnoid.com. All Rights Reserved.
*/
double f(double x) {
return 2.202196968876e+02
+ 3.561383996027e-01 * x
+ 1.276218788985e-04 * pow(x, 2)
+ -3.470360275448e-07 * pow(x, 3)
+ 2.082790802069e-10 * pow(x, 4)
+ -5.306931174991e-14 * pow(x, 5)
+ 4.787659214703e-18 * pow(x, 6);
}
注意逗号分隔作为小数点分隔符。
步骤23:带有校正的捕获-绘图仪序列
步骤24:计算成本
要执行多项式计算,处理器必须处理此任务。这可能会导致执行延迟,具体取决于源代码和可用的计算能力。
在这里,我们看到了使用多项式多项式的测试结果表。注意使用pow()函数的时间与不使用pow()函数的时间之间的时差。
步骤25:测试代码-设置()和循环启动()
在这里,我们有测试中使用的代码。
void setup() {
Serial.begin(1000000); //Iniciando a porta serial somente para debug
}
void loop() {
float valor_analogico = 500.0; //um valor arbtrario
float quantidade = 10000.0; //quantidade de chamadas
float contador = 0.0; //contador de chamadas
步骤26:测试代码-循环()和处理
我使用了micros()函数来获取以微秒为单位的值。
//============= inicia o processo
float agora = micros(); //marca o instante inicial
while (contador 《 quantidade) {
//v(valor_analogico); //função vazia
//r(valor_analogico); //função com retorno
//f0(valor_analogico); //grau 0
//f1(valor_analogico); //grau 1
//f2(valor_analogico); //grau 2
//f3(valor_analogico); //grau 3
//f4(valor_analogico); //grau 4
//f5(valor_analogico); //grau 5
//f6(valor_analogico); //grau 6
//f13_semPow(valor_analogico); //grau 13º SEM a função POW
//f13_comPow(valor_analogico); //grau 13º COM a função POW
contador++;
}
agora = (micros() - agora) / quantidade; //determina o intervalo que se passou para cada iteração
//============= finaliza o processo
步骤27:测试代码-循环()-结果
我们打印从13级函数返回的值(带有和不带有POW进行比较)以及处理间隔。
//imprime o valor retornado da função de grau 13 com e sem POW para comparação
Serial.print(f13_semPow(valor_analogico)); //grau 13º SEM a função POW
Serial.print(“ - ”);
Serial.print(f13_comPow(valor_analogico)); //grau 13º COM a função POW
Serial.print(“ - ”);
//imprime o intervalo do processamento
Serial.println(agora, 6);
}
步骤28:测试代码-使用的函数
空度为0和1的函数(仅带返回)。
//FUNÇÃO VAZIA
double v(double x) {
}
//FUNÇÃO SOMENTE COM RETORNO
double r(double x) {
return x;
}
//FUNÇÃO DE GRAU 0
double f0(double x) {
return 2.202196968876e+02;
}
//FUNÇÃO DE GRAU 1
double f1(double x) {
return 2.202196968876e+02
+ 3.561383996027e-01 * x;
}
2、3和4级函数。
//FUNÇÃO DE GRAU 2
double f2(double x) {
return 2.202196968876e+02
+ 3.561383996027e-01 * x
+ 1.276218788985e-04 * pow(x, 2);
}
//FUNÇÃO DE GRAU 3
double f3(double x) {
return 2.202196968876e+02
+ 3.561383996027e-01 * x
+ 1.276218788985e-04 * pow(x, 2)
+ -3.470360275448e-07 * pow(x, 3);
}
//FUNÇÃO DE GRAU 4
double f4(double x) {
return 2.202196968876e+02
+ 3.561383996027e-01 * x
+ 1.276218788985e-04 * pow(x, 2)
+ -3.470360275448e-07 * pow(x, 3)
+ 2.082790802069e-10 * pow(x, 4);
}
5和6级函数。
//FUNÇÃO DE GRAU 5
double f5(double x) {
return 2.202196968876e+02
+ 3.561383996027e-01 * x
+ 1.276218788985e-04 * pow(x, 2)
+ -3.470360275448e-07 * pow(x, 3)
+ 2.082790802069e-10 * pow(x, 4)
+ -5.306931174991e-14 * pow(x, 5);
}
//FUNÇÃO DE GRAU 6
double f6(double x) {
return 2.202196968876e+02
+ 3.561383996027e-01 * x
+ 1.276218788985e-04 * pow(x, 2)
+ -3.470360275448e-07 * pow(x, 3)
+ 2.082790802069e-10 * pow(x, 4)
+ -5.306931174991e-14 * pow(x, 5)
+ 4.787659214703e-18 * pow(x, 6);
}
使用POW的13级函数。
//FUNÇÃO DE GRAU 13 USANDO O POW
double f13_comPow(double x) {
return 2, 161282383460e+02
+ 3, 944594843419e-01 * x
+ 5, 395439724295e-04 * pow(x, 2)
+ -3, 968558178426e-06 * pow(x, 3)
+ 1, 047910519933e-08 * pow(x, 4)
+ -1, 479271312313e-11 * pow(x, 5)
+ 1, 220894795714e-14 * pow(x, 6)
+ -6, 136200785076e-18 * pow(x, 7)
+ 1, 910015248179e-21 * pow(x, 8)
+ -3, 566607830903e-25 * pow(x, 9)
+ 5, 000280815521e-30 * pow(x, 10)
+ 3, 434515045670e-32 * pow(x, 11)
+ -1, 407635444704e-35 * pow(x, 12)
+ 9,871816383223e-40 * pow(x,13);
}
不使用13级函数POW。
//FUNÇÃO DE GRAU SEM USAR O POW
double f13_semPow(double x) {
return 2, 161282383460e+02
+ 3, 944594843419e-01 * x
+ 5, 395439724295e-04 * x * x
+ -3, 968558178426e-06 * x * x * x
+ 1, 047910519933e-08 * x * x * x * x
+ -1, 479271312313e-11 * x * x * x * x * x
+ 1, 220894795714e-14 * x * x * x * x * x * x
+ -6, 136200785076e-18 * x * x * x * x * x * x * x
+ 1, 910015248179e-21 * x * x * x * x * x * x * x * x
+ -3, 566607830903e-25 * x * x * x * x * x * x * x * x * x
+ 5, 000280815521e-30 * x * x * x * x * x * x * x * x * x * x
+ 3, 434515045670e-32 * x * x * x * x * x * x * x * x * x * x * x
+ -1, 407635444704e-35 * x * x * x * x * x * x * x * x * x * x * x * x
+ 9, 871816383223e-40 * x * x * x * x * x * x * x * x * x * x * x * x * x;
}
责任编辑:wv
全部0条评论
快来发表一下你的评论吧 !