电量计算

This commit is contained in:
PC 2026-01-30 11:22:20 +08:00
parent 0e9f83c84a
commit 3393089eee
2 changed files with 190 additions and 2 deletions

View File

@ -7,6 +7,7 @@ import com.cdzy.common.utils.CoordinateUtil;
import com.cdzy.report.enums.BitSwitch;
import com.cdzy.report.utils.BinaryUtil;
import com.cdzy.report.utils.RedisUtil;
import com.cdzy.report.utils.SOCVoltageMapper;
import com.ebike.feign.clients.OperationsFeignClient;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
@ -75,6 +76,12 @@ public class ReoprtHandler {
//生成换电工单
operateFeignClient.batterySwapOrder(deviceId,Boolean.FALSE);
}
//静止状态电量上报为0异常处理
if (resGpsDto.getSoc() == 0 && isMoving == '0'){
double voltage = resGpsDto.getVoltage() / 13000.0;
double socFromVoltage = SOCVoltageMapper.getSOCFromVoltage(voltage);
resGpsDto.setSoc((int) socFromVoltage);
}
resGpsDto.setEcuSn(deviceId);
resGpsDto.setHelmetExit(helmet);
resGpsDto.setAccOn(acc);
@ -89,12 +96,12 @@ public class ReoprtHandler {
boolean outOfChina = CoordinateUtil.outOfChina(doubles[0], doubles[1]);
if (!outOfChina) {
EbikeTracking ebikeTracking = new EbikeTracking(deviceId, doubles[1], doubles[0]);
operateFeignClient.saveEbikeTracking(ebikeTracking);
// operateFeignClient.saveEbikeTracking(ebikeTracking);
//车辆静止,直接落库
if (isMoving == '0') {
//TODO:优化为算法计算存储,计算拐点等关键位置而非单纯的等待2min的静止上报
log.info("记录中控绑定的车辆位置,中控编号:{}", deviceId);
operateFeignClient.changeLocation(deviceId,doubles[0], doubles[1]);
// operateFeignClient.changeLocation(deviceId,doubles[0], doubles[1]);
}
}

View File

@ -0,0 +1,181 @@
package com.cdzy.report.utils;
/**
* SOC电压映射工具类
* 根据电池开路电压值计算对应的SOC百分比
*/
public class SOCVoltageMapper {
// SOC-电压对应表典型值
private static final double[][] SOC_VOLTAGE_TABLE = {
{0.0, 3.000}, // 0% SOC
{5.0, 3.100}, // 5% SOC
{10.0, 3.225}, // 10% SOC
{15.0, 3.350}, // 15% SOC
{20.0, 3.475}, // 20% SOC
{25.0, 3.600}, // 25% SOC
{30.0, 3.675}, // 30% SOC
{35.0, 3.710}, // 35% SOC
{40.0, 3.736}, // 40% SOC
{45.0, 3.766}, // 45% SOC
{50.0, 3.796}, // 50% SOC
{55.0, 3.826}, // 55% SOC
{60.0, 3.856}, // 60% SOC
{65.0, 3.886}, // 65% SOC
{70.0, 3.934}, // 70% SOC
{75.0, 3.969}, // 75% SOC
{80.0, 4.004}, // 80% SOC
{85.0, 4.039}, // 85% SOC
{90.0, 4.074}, // 90% SOC
{95.0, 4.109}, // 95% SOC
{100.0, 4.144} // 100% SOC
};
// 关键点的电压范围校验SOC, 最小电压, 最大电压
private static final double[][] VOLTAGE_RANGE_CHECK = {
{0.0, 2.95, 3.05}, // 0% SOC范围
{10.0, 3.20, 3.25}, // 10% SOC范围
{20.0, 3.46, 3.49}, // 20% SOC范围
{30.0, 3.67, 3.68}, // 30% SOC范围
{50.0, 3.791, 3.801}, // 50% SOC范围
{100.0, 4.14, 4.20} // 100% SOC范围
};
/**
* 根据开路电压值获取对应的SOC百分比
* @param voltage 测量的开路电压值(V)
* @return 对应的SOC百分比(0-100)
*/
public static double getSOCFromVoltage(double voltage) {
// 边界检查
if (voltage < SOC_VOLTAGE_TABLE[0][1]) {
return 0.0; // 电压过低返回0%
}
if (voltage > SOC_VOLTAGE_TABLE[SOC_VOLTAGE_TABLE.length - 1][1]) {
return 100.0; // 电压过高返回100%
}
// 查找电压所在的区间
for (int i = 0; i < SOC_VOLTAGE_TABLE.length - 1; i++) {
double currentSOC = SOC_VOLTAGE_TABLE[i][0];
double currentVoltage = SOC_VOLTAGE_TABLE[i][1];
double nextSOC = SOC_VOLTAGE_TABLE[i + 1][0];
double nextVoltage = SOC_VOLTAGE_TABLE[i + 1][1];
// 如果电压正好匹配某个点
if (Math.abs(voltage - currentVoltage) < 0.001) {
return currentSOC;
}
// 如果电压在两点之间进行线性插值
if (voltage >= currentVoltage && voltage <= nextVoltage) {
return linearInterpolation(voltage, currentVoltage, nextVoltage, currentSOC, nextSOC);
}
}
// 默认返回
return linearInterpolation(voltage,
SOC_VOLTAGE_TABLE[0][1],
SOC_VOLTAGE_TABLE[SOC_VOLTAGE_TABLE.length - 1][1],
0.0, 100.0);
}
/**
* 线性插值计算
*/
private static double linearInterpolation(double voltage, double v1, double v2, double soc1, double soc2) {
double ratio = (voltage - v1) / (v2 - v1);
return soc1 + ratio * (soc2 - soc1);
}
/**
* 获取BMS校准推荐度
* @param soc SOC百分比
* @return 校准推荐度描述
*/
public static String getBMSCalibrationRecommendation(double soc) {
if (soc <= 0.1 || soc >= 99.9) {
return "★★★★★ (强制校准点)";
} else if (soc <= 5.1 || soc >= 95.1) {
return "★★★★☆";
} else if (soc <= 10.1 || (soc >= 20.1 && soc <= 20.9) ||
(soc >= 90.1 && soc <= 90.9) || soc >= 80.1) {
return "★★★★☆";
} else if (soc <= 15.1 || soc <= 25.1 ||
(soc >= 70.1 && soc <= 75.1) || soc >= 85.1) {
return "★★★☆☆";
} else if (soc <= 30.1 || (soc >= 50.1 && soc <= 60.1)) {
return "★★☆☆☆";
} else {
return "★☆☆☆☆ (平台区,不推荐校准)";
}
}
/**
* 检查电压是否在合理偏差范围内
* @param voltage 测量的电压
* @param soc 对应的SOC
* @return 是否在合理范围内
*/
public static boolean isVoltageInRange(double voltage, double soc) {
for (double[] range : VOLTAGE_RANGE_CHECK) {
if (Math.abs(soc - range[0]) < 0.5) {
return voltage >= range[1] && voltage <= range[2];
}
}
return true; // 非关键点默认认为合理
}
/**
* 获取关键SOC点的描述
* @param soc SOC百分比
* @return 关键点描述
*/
public static String getKeyPointDescription(double soc) {
if (soc <= 0.5) {
return "强制保护点";
} else if (Math.abs(soc - 10.0) < 0.5) {
return "低电量报警点";
} else if (Math.abs(soc - 20.0) < 0.5) {
return "建议充电点";
} else if (Math.abs(soc - 30.0) < 0.5) {
return "平台区开始";
} else if (Math.abs(soc - 40.0) < 0.5) {
return "最平区域";
} else if (Math.abs(soc - 50.0) < 0.5) {
return "标称电压点";
} else if (Math.abs(soc - 70.0) < 0.5) {
return "平台区结束";
} else if (Math.abs(soc - 80.0) < 0.5) {
return "高电量区";
} else if (soc >= 99.5) {
return "满电标志";
} else {
return "正常区域";
}
}
/**
* 测试示例
*/
public static void main(String[] args) {
// 测试不同电压值
double[] testVoltages = {3.0, 3.225, 3.475, 3.675, 3.736, 3.796, 4.004, 4.144};
System.out.println("SOC-电压映射测试:");
System.out.println("=========================================");
for (double voltage : testVoltages) {
double soc = getSOCFromVoltage(voltage);
String calibration = getBMSCalibrationRecommendation(soc);
String description = getKeyPointDescription(soc);
System.out.printf("电压: %.3fV -> SOC: %.1f%%\n", voltage, soc);
System.out.printf(" 校准推荐度: %s\n", calibration);
System.out.printf(" 关键点描述: %s\n", description);
System.out.printf(" 电压范围检查: %s\n",
isVoltageInRange(voltage, soc) ? "正常" : "异常");
System.out.println("-----------------------------------------");
}
}
}