Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCV vs. SOC curve configuration improvements #77

Merged
merged 5 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,32 @@ config BAT_CAPACITY_AH
Nominal battery capacity or sum of parallel cells capacity

choice
prompt "Cell type"
prompt "Default cell type"
default CELL_TYPE_LFP
help
Select the type of the single cells inside the battery
to determine voltage set points. Total voltage set points
are multiplied with the selected number of cells.

The default values based on this configuration can be overriden via ThingSet.

config CELL_TYPE_LFP
bool "LiFePO4, 3.3V nominal"

config CELL_TYPE_NMC
bool "NMC/Graphite, 3.7V nominal, 4.2V max"

config CELL_TYPE_NMC_HV
bool "NMC/Graphite High Voltage, 3.7V nominal, 4.35 max"

config CELL_TYPE_LTO
bool "NMC/Titanate, 2.4 V nominal"

config CELL_TYPE_CUSTOM
bool "Enable manual configuration for all customizable parameters"
endchoice

# values must match enum CellType in bms.h
config CELL_TYPE
int
default 0 if CELL_TYPE_CUSTOM
default 1 if CELL_TYPE_LFP
default 2 if CELL_TYPE_NMC
default 3 if CELL_TYPE_NMC_HV
default 4 if CELL_TYPE_LTO
default 0 if CELL_TYPE_LFP
default 1 if CELL_TYPE_NMC
default 2 if CELL_TYPE_LTO

endmenu

Expand Down
1 change: 1 addition & 0 deletions app/boards/bms_16s100_sc_esp32c3.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ CONFIG_SHELL_CMDS_SELECT=y

CONFIG_THINGSET_SHELL=y
CONFIG_THINGSET_SHELL_REPORTING=n
CONFIG_THINGSET_SHELL_CMD_BUF_SIZE=256
1 change: 1 addition & 0 deletions app/boards/bms_c1.conf
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ CONFIG_SHELL_CMDS_SELECT=y

CONFIG_THINGSET_SHELL=y
CONFIG_THINGSET_SHELL_REPORTING=n
CONFIG_THINGSET_SHELL_CMD_BUF_SIZE=256

# DFU over CAN
CONFIG_THINGSET_DFU=y
Expand Down
1 change: 1 addition & 0 deletions app/boards/native_sim.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ CONFIG_SHELL_CMDS_SELECT=y

CONFIG_THINGSET_SHELL=y
CONFIG_THINGSET_SHELL_REPORTING=n
CONFIG_THINGSET_SHELL_CMD_BUF_SIZE=256

CONFIG_EMUL=y
CONFIG_EEPROM=y
Expand Down
2 changes: 1 addition & 1 deletion app/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ CONFIG_THINGSET_NODE_NAME="Libre Solar BMS"
# Change default battery nominal capacity (in Ah)
#CONFIG_BAT_CAPACITY_AH=?

# Select cell type for initial configuration: LFP (default), NMC, NMC_HV, LTO or CUSTOM
# Select cell type for initial configuration: LFP (default), NMC or LTO
#CONFIG_CELL_TYPE_???=y
58 changes: 32 additions & 26 deletions app/src/bms_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,30 @@

LOG_MODULE_REGISTER(bms, CONFIG_LOG_DEFAULT_LEVEL);

static float ocv_lfp[OCV_POINTS] = { 3.392F, 3.314F, 3.309F, 3.308F, 3.304F, 3.296F, 3.283F,
3.275F, 3.271F, 3.268F, 3.265F, 3.264F, 3.262F, 3.252F,
3.240F, 3.226F, 3.213F, 3.190F, 3.177F, 3.132F, 2.833F };

static float ocv_nmc[OCV_POINTS] = { 4.198F, 4.135F, 4.089F, 4.056F, 4.026F, 3.993F, 3.962F,
3.924F, 3.883F, 3.858F, 3.838F, 3.819F, 3.803F, 3.787F,
3.764F, 3.745F, 3.726F, 3.702F, 3.684F, 3.588F, 2.800F };

float ocv_custom[OCV_POINTS] = { 0 };

static float soc_pct[OCV_POINTS] = { 100.0F, 95.0F, 90.0F, 85.0F, 80.0F, 85.0F, 70.0F,
65.0F, 60.0F, 55.0F, 50.0F, 45.0F, 40.0F, 35.0F,
30.0F, 25.0F, 20.0F, 15.0F, 10.0F, 5.0F, 0.0F };

float soc_custom[OCV_POINTS] = { 0 };
static const float ocv_lfp[NUM_OCV_POINTS] = {
3.392F, 3.314F, 3.309F, 3.308F, 3.304F, 3.296F, 3.283F, 3.275F, 3.271F, 3.268F, 3.265F,
3.264F, 3.262F, 3.252F, 3.240F, 3.226F, 3.213F, 3.190F, 3.177F, 3.132F, 2.833F,
};

static const float ocv_nmc[NUM_OCV_POINTS] = {
4.198F, 4.135F, 4.089F, 4.056F, 4.026F, 3.993F, 3.962F, 3.924F, 3.883F, 3.858F, 3.838F,
3.819F, 3.803F, 3.787F, 3.764F, 3.745F, 3.726F, 3.702F, 3.684F, 3.588F, 2.800F,
};

// Source: DOI:10.3390/batteries5010031 (https://www.mdpi.com/2313-0105/5/1/31)
static const float ocv_lto[NUM_OCV_POINTS] = {
2.800F, 2.513F, 2.458F, 2.415F, 2.376F, 2.340F, 2.309F, 2.282F, 2.259F, 2.240F, 2.224F,
2.210F, 2.198F, 2.187F, 2.177F, 2.166F, 2.154F, 2.141F, 2.125F, 2.105F, 2.000F,
};

static const float soc_default[NUM_OCV_POINTS] = {
100.0F, 95.0F, 90.0F, 85.0F, 80.0F, 85.0F, 70.0F, 65.0F, 60.0F, 55.0F, 50.0F,
45.0F, 40.0F, 35.0F, 30.0F, 25.0F, 20.0F, 15.0F, 10.0F, 5.0F, 0.0F,
};

// actually used OCV vs. SOC curve
float ocv_points[NUM_OCV_POINTS] = { 0 };
float soc_points[NUM_OCV_POINTS] = { 0 };

void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nominal_capacity_Ah)
{
Expand Down Expand Up @@ -61,6 +70,11 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom
bms->ic_conf.cell_ov_delay_ms = 2000;
bms->ic_conf.cell_uv_delay_ms = 2000;

bms->ocv_points = ocv_points;
bms->soc_points = soc_points;

memcpy(soc_points, soc_default, sizeof(soc_points));

switch (type) {
case CELL_TYPE_LFP:
bms->ic_conf.cell_ov_limit = 3.80F;
Expand All @@ -74,8 +88,7 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom
* self-discharge
*/
bms->ic_conf.cell_uv_limit = 2.50F;
bms->ocv_points = ocv_lfp;
bms->soc_points = soc_pct;
memcpy(ocv_points, ocv_lfp, sizeof(ocv_points));
break;
case CELL_TYPE_NMC:
bms->ic_conf.cell_ov_limit = 4.25F;
Expand All @@ -85,8 +98,7 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom
bms->ic_conf.cell_uv_reset = 3.50F;
bms->ic_conf.cell_dis_voltage_limit = 3.20F;
bms->ic_conf.cell_uv_limit = 3.00F;
bms->ocv_points = ocv_nmc;
bms->soc_points = soc_pct;
memcpy(ocv_points, ocv_nmc, sizeof(ocv_points));
break;
case CELL_TYPE_LTO:
bms->ic_conf.cell_ov_limit = 2.85F;
Expand All @@ -96,13 +108,7 @@ void bms_init_config(struct bms_context *bms, enum bms_cell_type type, float nom
bms->ic_conf.cell_uv_reset = 2.10F;
bms->ic_conf.cell_dis_voltage_limit = 2.00F;
bms->ic_conf.cell_uv_limit = 1.90F;
// ToDo: Use typical OCV curve for LTO cells
bms->ocv_points = NULL;
bms->soc_points = NULL;
break;
case CELL_TYPE_CUSTOM:
bms->ocv_points = ocv_custom;
bms->soc_points = soc_custom;
memcpy(ocv_points, ocv_lto, sizeof(ocv_points));
break;
}

Expand Down
6 changes: 3 additions & 3 deletions app/src/bms_soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ void bms_soc_reset(struct bms_context *bms, int percent)
bms->soc = percent;
}
else if (bms->ocv_points != NULL && bms->soc_points != NULL
&& !is_empty((uint8_t *)bms->ocv_points, OCV_POINTS)
&& !is_empty((uint8_t *)bms->soc_points, OCV_POINTS))
&& !is_empty((uint8_t *)bms->ocv_points, NUM_OCV_POINTS)
&& !is_empty((uint8_t *)bms->soc_points, NUM_OCV_POINTS))
{
// Executes if both OCV and SOC points are valid pointers and arrays contain non-zero data.
bms->soc = interpolate(bms->ocv_points, bms->soc_points, OCV_POINTS,
bms->soc = interpolate(bms->ocv_points, bms->soc_points, NUM_OCV_POINTS,
bms->ic_data.cell_voltage_avg);
}
else {
Expand Down
22 changes: 17 additions & 5 deletions app/src/data_objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
#include <stdio.h>

extern struct bms_context bms;
extern float ocv_custom[OCV_POINTS];
extern float soc_custom[OCV_POINTS];
extern float ocv_points[NUM_OCV_POINTS];
extern float soc_points[NUM_OCV_POINTS];

static char manufacturer[] = "Libre Solar";
static char device_type[] = DT_PROP(DT_PATH(pcb), type);
Expand All @@ -35,9 +35,9 @@ static THINGSET_DEFINE_FLOAT_ARRAY(cell_voltages_arr, 3, bms.ic_data.cell_voltag
static THINGSET_DEFINE_FLOAT_ARRAY(cell_temps_arr, 1, bms.ic_data.cell_temps,
ARRAY_SIZE(bms.ic_data.cell_temps));

static THINGSET_DEFINE_FLOAT_ARRAY(ocv_points_arr, 3, ocv_custom, ARRAY_SIZE(ocv_custom));
static THINGSET_DEFINE_FLOAT_ARRAY(ocv_points_arr, 3, ocv_points, ARRAY_SIZE(ocv_points));

static THINGSET_DEFINE_FLOAT_ARRAY(soc_points_arr, 1, soc_custom, ARRAY_SIZE(soc_custom));
static THINGSET_DEFINE_FLOAT_ARRAY(soc_points_arr, 1, soc_points, ARRAY_SIZE(soc_points));

// used for xInitConf functions
static float new_capacity = 0;
Expand Down Expand Up @@ -188,6 +188,11 @@ THINGSET_ADD_FN_INT32(APP_ID_CONF, APP_ID_CONF_PRESET_LFP, "xPresetLFP", &bat_pr
THINGSET_ADD_ITEM_FLOAT(APP_ID_CONF_PRESET_LFP, APP_ID_CONF_PRESET_LFP_CAPACITY, "fCapacity_Ah",
&new_capacity, 1, THINGSET_ANY_RW, 0);

THINGSET_ADD_FN_INT32(APP_ID_CONF, APP_ID_CONF_PRESET_LTO, "xPresetLTO", &bat_preset_lto,
THINGSET_ANY_RW);
THINGSET_ADD_ITEM_FLOAT(APP_ID_CONF_PRESET_LTO, APP_ID_CONF_PRESET_LTO_CAPACITY, "fCapacity_Ah",
&new_capacity, 1, THINGSET_ANY_RW, 0);

// MEAS DATA ////////////////////////////////////////////////////////////

THINGSET_ADD_GROUP(TS_ID_ROOT, APP_ID_MEAS, "Meas", THINGSET_NO_CALLBACK);
Expand Down Expand Up @@ -280,7 +285,9 @@ int32_t bat_preset(enum bms_cell_type type)
}
#endif

return ret;
// Always return 1 in case of success, as the flags returned by bms_ic_configure can be
// confusing for end users in the App. Actually applied config can be retrieved via ThingSet.
return ret > 0 ? 1 : ret;
}

int32_t bat_preset_nmc()
Expand All @@ -293,6 +300,11 @@ int32_t bat_preset_lfp()
return bat_preset(CELL_TYPE_LFP);
}

int32_t bat_preset_lto()
{
return bat_preset(CELL_TYPE_LTO);
}

void print_registers()
{
bms_ic_debug_print_mem(bms.ic_dev);
Expand Down
7 changes: 7 additions & 0 deletions app/src/data_objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
#define APP_ID_CONF_PRESET_NMC_CAPACITY 0xA1
#define APP_ID_CONF_PRESET_LFP 0xA2
#define APP_ID_CONF_PRESET_LFP_CAPACITY 0xA3
#define APP_ID_CONF_PRESET_LTO 0xA4
#define APP_ID_CONF_PRESET_LTO_CAPACITY 0xA5
#define APP_ID_CONF_OCV_POINTS 0xB0
#define APP_ID_CONF_SOC_POINTS 0xB1

Expand Down Expand Up @@ -103,6 +105,11 @@ int32_t bat_preset_nmc();
*/
int32_t bat_preset_lfp();

/**
* Callback function to apply preset parameters for LTO type via ThingSet
*/
int32_t bat_preset_lto();

/**
* Callback to read and print common BMS registers via ThingSet
*/
Expand Down
2 changes: 1 addition & 1 deletion docs/src/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Amongst all features inherited from underlying Zephyr, the BMS has the following

- Pack layout

- Cell chemistry (LiFePO4, NMC, NCA)
- Cell chemistry (e.g. LiFePO4, NMC, NCA, LTO)
- Nominal capacity
- Number of cells
- Thermistor type
Expand Down
9 changes: 4 additions & 5 deletions include/bms/bms.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extern "C" {
#include <stdint.h>

/* fixed number of OCV vs. SOC points */
#define OCV_POINTS 21
#define NUM_OCV_POINTS 21

/**
* Possible BMS states
Expand All @@ -43,10 +43,9 @@ enum bms_state
*/
enum bms_cell_type
{
CELL_TYPE_CUSTOM = 0, ///< Custom settings
CELL_TYPE_LFP, ///< LiFePO4 Li-ion cells (3.3 V nominal)
CELL_TYPE_NMC, ///< NMC/Graphite Li-ion cells (3.7 V nominal)
CELL_TYPE_LTO ///< NMC/Titanate (2.4 V nominal)
CELL_TYPE_LFP, ///< LiFePO4 Li-ion cells (3.3 V nominal)
CELL_TYPE_NMC, ///< NMC/Graphite Li-ion cells (3.7 V nominal)
CELL_TYPE_LTO, ///< NMC/Titanate (2.4 V nominal)
};

/**
Expand Down
Loading