今天開發(fā)一個(gè)小設(shè)備,需要顯示一下當(dāng)前電量,從ADC中獲取到了原始采樣值,換算出來(lái)電壓值以后就不想搬磚了。
所以,找個(gè)免費(fèi)勞動(dòng)力,把后面的代碼寫一下吧。
直接下任務(wù),不用先打招呼,也不用客套,甚至你都不需要給他講太細(xì),罵著他也好好的給你執(zhí)行。
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)
{
// 常見(jiàn)鋰電池開路電壓與SOC的近似關(guān)系
// 數(shù)據(jù)可以根據(jù)具體電池調(diào)整,這里用一個(gè)常見(jiàn)的線性插值示例
double[] voltagePoints = { 3.0, 3.2, 3.4, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2 }; // 電壓點(diǎn)
double[] socPoints = { 0, 10, 20, 40, 50, 60, 70, 85, 95, 100 }; // 對(duì)應(yīng)SOC點(diǎn) (%)
// 邊界處理
if (voltage <= voltagePoints[0]) return socPoints[0];
if (voltage >= voltagePoints[voltagePoints.Length - 1]) return socPoints[socPoints.Length - 1];
// 插值計(jì)算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]);
}
}
// 默認(rèn)返回0(正常情況下不會(huì)到達(dá)這里)
return 0;
}
}
不說(shuō)太細(xì)還真不行,因?yàn)樗芰μ珡?qiáng)了,以至于給我的是一個(gè)C#代碼,而需要的是一個(gè)跑在單片機(jī)上的C語(yǔ)言代碼。我只能罵他一下了。
#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) {
// 使用整數(shù)表示電壓 (單位: mV) 和 SOC (%)
int voltagePoints[] = { 3000, 3200, 3400, 3600, 3700, 3800, 3900, 4000, 4100, 4200 }; // 電壓點(diǎn) (單位: mV)
int socPoints[] = { 0, 10, 20, 40, 50, 60, 70, 85, 95, 100 }; // 對(duì)應(yīng)SOC點(diǎn) (%)
int numPoints = sizeof(voltagePoints) / sizeof(voltagePoints[0]);
// 邊界處理
if (voltage <= voltagePoints[0]) return socPoints[0];
if (voltage >= voltagePoints[numPoints - 1]) return socPoints[numPoints - 1];
// 插值計(jì)算SOC
for (int i = 0; i < numPoints - 1; i++) {
if (voltage >= voltagePoints[i] && voltage <= voltagePoints[i + 1]) {
// 線性插值公式,完全用整數(shù)計(jì)算
int deltaVoltage = voltagePoints[i + 1] - voltagePoints[i];
int deltaSOC = socPoints[i + 1] - socPoints[i];
int voltageOffset = voltage - voltagePoints[i];
// 計(jì)算插值的SOC,返回整數(shù)
return socPoints[i] + (voltageOffset * deltaSOC) / deltaVoltage;
}
}
// 默認(rèn)返回0(正常情況下不會(huì)到達(dá)這里)
return 0;
}
他懂得蠻多的,一聽說(shuō)是單片機(jī),不單把C#語(yǔ)言改成了C語(yǔ)言,然后還知道把浮點(diǎn)運(yùn)算全部轉(zhuǎn)換成整形數(shù)來(lái)運(yùn)算,提高效率。
貼心的注釋,以及簡(jiǎn)單的使用教程,接口調(diào)用都碼的明明白白。
電量顯示似乎還有點(diǎn)問(wèn)題,負(fù)載變化的時(shí)候,電壓不穩(wěn)定,電量百分百總是跳動(dòng)。
以下是他的回答,我不貼圖了,粘貼蚊子到這里吧。
1. 內(nèi)阻模型補(bǔ)償
利用電池的內(nèi)阻模型,根據(jù)當(dāng)前電流(I)和內(nèi)阻(R)計(jì)算出補(bǔ)償后的開路電壓:
#include <stdio.h>
int calculateSOC(int voltage, int current);
int compensateVoltage(int voltage, int current, int resistance);
int main() {
// 示例輸入,電壓和電流以整數(shù)表示
int voltage = 3650; // 3.65V = 3650mV (負(fù)載電壓)
int current = 2000; // 2000mA = 2A
int soc;
// 根據(jù)電壓電流計(jì)算SOC
soc = calculateSOC(voltage, current);
printf("負(fù)載電壓: %dmV, 電流: %dmA, SOC: %d (0.1%% 精度)n", voltage, current, soc);
return 0;
}
// 補(bǔ)償后的SOC計(jì)算
int calculateSOC(int voltage, int current) {
// 定義內(nèi)阻值(單位: mΩ)
int resistance = 50; // 內(nèi)阻50mΩ,可根據(jù)電池類型調(diào)整
// 補(bǔ)償后的電壓(估算開路電壓)
int compensatedVoltage = compensateVoltage(voltage, current, resistance);
// 使用補(bǔ)償后的電壓計(jì)算SOC
int voltagePoints[] = { 3000, 3200, 3400, 3600, 3700, 3800, 3900, 4000, 4100, 4200 }; // 電壓點(diǎn) (單位: mV)
int socPoints[] = { 0, 100, 200, 400, 500, 600, 700, 850, 950, 1000 }; // 對(duì)應(yīng)SOC點(diǎn) (擴(kuò)大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];
// 插值計(jì)算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; // 默認(rèn)返回0
}
// 電壓補(bǔ)償函數(shù)
int compensateVoltage(int voltage, int current, int resistance) {
// 使用 I * R 進(jìn)行電壓補(bǔ)償
// resistance 單位為 mΩ,current 單位為 mA,計(jì)算結(jié)果單位為 mV
return voltage + (current * resistance) / 1000;
}
2. 動(dòng)態(tài)內(nèi)阻調(diào)整
鋰電池的內(nèi)阻(R)會(huì)隨著SOC和溫度的變化而變化,可以通過(guò)查表或?qū)崟r(shí)監(jiān)控內(nèi)阻調(diào)整補(bǔ)償系數(shù):
低SOC(<20%)或高SOC(>80%):內(nèi)阻通常較大。
溫度低時(shí)(如<0°C):內(nèi)阻顯著增大。
實(shí)現(xiàn)建議:
使用一個(gè)二維查表機(jī)制,根據(jù)SOC和溫度動(dòng)態(tài)調(diào)整 resistance
的值。
在上面的 compensateVoltage
函數(shù)中替換固定內(nèi)阻值為動(dòng)態(tài)值。
3. 時(shí)間加權(quán)平均
如果負(fù)載波動(dòng)較大,可以通過(guò)時(shí)間加權(quán)平均法平滑SOC計(jì)算:
SOCsmooth=α?SOCnew+(1?α)?SOCold
其中,α 是平滑因子(0-1之間,通常取0.1到0.3)。
4. 擴(kuò)展方法:結(jié)合電流積分法
對(duì)負(fù)載電流(Coulomb計(jì)數(shù)法)與電壓估算法結(jié)合,可以在動(dòng)態(tài)負(fù)載情況下得到更穩(wěn)定的SOC值:
使用補(bǔ)償后的電壓計(jì)算初步SOC。
通過(guò)電流積分法對(duì)SOC進(jìn)行調(diào)整(例如長(zhǎng)期負(fù)載或高電流放電時(shí))。
總結(jié)
通過(guò)對(duì)負(fù)載電壓的補(bǔ)償,可以有效減小負(fù)載變化對(duì)SOC估算的影響。結(jié)合動(dòng)態(tài)內(nèi)阻調(diào)整或平滑方法,能夠進(jìn)一步提高SOC計(jì)算的穩(wěn)定性和準(zhǔn)確性。
哎,搬磚這事以后就不能自己干。