今天开发一个小设备,需要显示一下当前电量,从ADC中获取到了原始采样值,换算出来电压值以后就不想搬砖了。
所以,找个免费劳动力,把后面的代码写一下吧。
直接下任务,不用先打招呼,也不用客套,甚至你都不需要给他讲太细,骂着他也好好的给你执行。
using System;
class Program
{
static void Main(string[] args)
{
// 示例输入电压值
double voltage = 3.7; // 单位: V
double soc = CalculateSOC(voltage);
Console.WriteLine($"电压: {voltage}V, SOC: {soc:F2}%");
}
static double CalculateSOC(double voltage)
{
// 常见锂电池开路电压与SOC的近似关系
// 数据可以根据具体电池调整,这里用一个常见的线性插值示例
double[] voltagePoints = { 3.0, 3.2, 3.4, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2 }; // 电压点
double[] socPoints = { 0, 10, 20, 40, 50, 60, 70, 85, 95, 100 }; // 对应SOC点 (%)
// 边界处理
if (voltage <= voltagePoints[0]) return socPoints[0];
if (voltage >= voltagePoints[voltagePoints.Length - 1]) return socPoints[socPoints.Length - 1];
// 插值计算SOC
for (int i = 0; i < voltagePoints.Length - 1; i++)
{
if (voltage >= voltagePoints[i] && voltage <= voltagePoints[i + 1])
{
// 线性插值公式
double slope = (socPoints[i + 1] - socPoints[i]) / (voltagePoints[i + 1] - voltagePoints[i]);
return socPoints[i] + slope * (voltage - voltagePoints[i]);
}
}
// 默认返回0(正常情况下不会到达这里)
return 0;
}
}
不说太细还真不行,因为他能力太强了,以至于给我的是一个C#代码,而需要的是一个跑在单片机上的C语言代码。我只能骂他一下了。
#include <stdio.h>
int calculateSOC(int voltage);
int main() {
// 示例输入电压值(单位: mV)
int voltage = 3700; // 3.7V = 3700mV
int soc = calculateSOC(voltage);
printf("电压: %dmV, SOC: %d%%n", voltage, soc);
return 0;
}
int calculateSOC(int voltage) {
// 使用整数表示电压 (单位: mV) 和 SOC (%)
int voltagePoints[] = { 3000, 3200, 3400, 3600, 3700, 3800, 3900, 4000, 4100, 4200 }; // 电压点 (单位: mV)
int socPoints[] = { 0, 10, 20, 40, 50, 60, 70, 85, 95, 100 }; // 对应SOC点 (%)
int numPoints = sizeof(voltagePoints) / sizeof(voltagePoints[0]);
// 边界处理
if (voltage <= voltagePoints[0]) return socPoints[0];
if (voltage >= voltagePoints[numPoints - 1]) return socPoints[numPoints - 1];
// 插值计算SOC
for (int i = 0; i < numPoints - 1; i++) {
if (voltage >= voltagePoints[i] && voltage <= voltagePoints[i + 1]) {
// 线性插值公式,完全用整数计算
int deltaVoltage = voltagePoints[i + 1] - voltagePoints[i];
int deltaSOC = socPoints[i + 1] - socPoints[i];
int voltageOffset = voltage - voltagePoints[i];
// 计算插值的SOC,返回整数
return socPoints[i] + (voltageOffset * deltaSOC) / deltaVoltage;
}
}
// 默认返回0(正常情况下不会到达这里)
return 0;
}
他懂得蛮多的,一听说是单片机,不单把C#语言改成了C语言,然后还知道把浮点运算全部转换成整形数来运算,提高效率。
贴心的注释,以及简单的使用教程,接口调用都码的明明白白。
电量显示似乎还有点问题,负载变化的时候,电压不稳定,电量百分百总是跳动。
以下是他的回答,我不贴图了,粘贴蚊子到这里吧。
1. 内阻模型补偿
利用电池的内阻模型,根据当前电流(I)和内阻(R)计算出补偿后的开路电压:
#include <stdio.h>
int calculateSOC(int voltage, int current);
int compensateVoltage(int voltage, int current, int resistance);
int main() {
// 示例输入,电压和电流以整数表示
int voltage = 3650; // 3.65V = 3650mV (负载电压)
int current = 2000; // 2000mA = 2A
int soc;
// 根据电压电流计算SOC
soc = calculateSOC(voltage, current);
printf("负载电压: %dmV, 电流: %dmA, SOC: %d (0.1%% 精度)n", voltage, current, soc);
return 0;
}
// 补偿后的SOC计算
int calculateSOC(int voltage, int current) {
// 定义内阻值(单位: mΩ)
int resistance = 50; // 内阻50mΩ,可根据电池类型调整
// 补偿后的电压(估算开路电压)
int compensatedVoltage = compensateVoltage(voltage, current, resistance);
// 使用补偿后的电压计算SOC
int voltagePoints[] = { 3000, 3200, 3400, 3600, 3700, 3800, 3900, 4000, 4100, 4200 }; // 电压点 (单位: mV)
int socPoints[] = { 0, 100, 200, 400, 500, 600, 700, 850, 950, 1000 }; // 对应SOC点 (扩大10倍, 单位: 0.1%)
int numPoints = sizeof(voltagePoints) / sizeof(voltagePoints[0]);
// 边界处理
if (compensatedVoltage <= voltagePoints[0]) return socPoints[0];
if (compensatedVoltage >= voltagePoints[numPoints - 1]) return socPoints[numPoints - 1];
// 插值计算SOC
for (int i = 0; i < numPoints - 1; i++) {
if (compensatedVoltage >= voltagePoints[i] && compensatedVoltage <= voltagePoints[i + 1]) {
int deltaVoltage = voltagePoints[i + 1] - voltagePoints[i];
int deltaSOC = socPoints[i + 1] - socPoints[i];
int voltageOffset = compensatedVoltage - voltagePoints[i];
return socPoints[i] + (voltageOffset * deltaSOC) / deltaVoltage;
}
}
return 0; // 默认返回0
}
// 电压补偿函数
int compensateVoltage(int voltage, int current, int resistance) {
// 使用 I * R 进行电压补偿
// resistance 单位为 mΩ,current 单位为 mA,计算结果单位为 mV
return voltage + (current * resistance) / 1000;
}
2. 动态内阻调整
锂电池的内阻(R)会随着SOC和温度的变化而变化,可以通过查表或实时监控内阻调整补偿系数:
低SOC(<20%)或高SOC(>80%):内阻通常较大。
温度低时(如<0°C):内阻显著增大。
实现建议:
使用一个二维查表机制,根据SOC和温度动态调整 resistance
的值。
在上面的 compensateVoltage
函数中替换固定内阻值为动态值。
3. 时间加权平均
如果负载波动较大,可以通过时间加权平均法平滑SOC计算:
SOCsmooth=α⋅SOCnew+(1−α)⋅SOCold
其中,α 是平滑因子(0-1之间,通常取0.1到0.3)。
4. 扩展方法:结合电流积分法
对负载电流(Coulomb计数法)与电压估算法结合,可以在动态负载情况下得到更稳定的SOC值:
使用补偿后的电压计算初步SOC。
通过电流积分法对SOC进行调整(例如长期负载或高电流放电时)。
总结
通过对负载电压的补偿,可以有效减小负载变化对SOC估算的影响。结合动态内阻调整或平滑方法,能够进一步提高SOC计算的稳定性和准确性。
哎,搬砖这事以后就不能自己干。