From e5248cc14e3d86fc46c0d56ad0e9ce9c519a392d Mon Sep 17 00:00:00 2001 From: Pranay Oza <105095960+pranay-o@users.noreply.github.com> Date: Sat, 5 Sep 2026 22:56:33 -0700 Subject: [PATCH 1/4] soc values --- firmware/hexray/BMS/src/app/app_soc.cpp | 232 ++++++++++++++++++++++++ firmware/hexray/BMS/src/app/app_soc.hpp | 7 + firmware/hexray/BMS/src/tasks.cpp | 7 + 3 files changed, 246 insertions(+) create mode 100644 firmware/hexray/BMS/src/app/app_soc.cpp create mode 100644 firmware/hexray/BMS/src/app/app_soc.hpp diff --git a/firmware/hexray/BMS/src/app/app_soc.cpp b/firmware/hexray/BMS/src/app/app_soc.cpp new file mode 100644 index 0000000000..b8d534f29e --- /dev/null +++ b/firmware/hexray/BMS/src/app/app_soc.cpp @@ -0,0 +1,232 @@ +#include "app_soc.hpp" + +#include +#include + +namespace +{ +constexpr size_t P30B_SOC_N = 21U; +constexpr size_t P30B_TEMP_N = 4U; +using P30BTable = std::array, P30B_SOC_N>; + +// Capacity of a single cell in ampere-seconds (Ah * 3600), not of a 4P group +constexpr float P30B_CAP_AS = 10800.000000f; + +constexpr std::array P30B_SOC_BP = { + { 0.0000f, 0.0500f, 0.1000f, 0.1500f, 0.2000f, 0.2500f, 0.3000f, 0.3500f, 0.4000f, 0.4500f, 0.5000f, 0.5500f, + 0.6000f, 0.6500f, 0.7000f, 0.7500f, 0.8000f, 0.8500f, 0.9000f, 0.9500f, 1.0000f } +}; + +constexpr std::array P30B_TEMP_BP_C = { + { 10.00f, 23.00f, 35.00f, 45.00f } +}; + +// Open circuit voltage of one cell, in volts. +constexpr P30BTable P30B_OCV_V = { { + { 2.93650000f, 2.94040000f, 2.92633333f, 2.91900000f }, + { 3.16150000f, 3.15846667f, 3.15166667f, 3.14850000f }, + { 3.26100000f, 3.25753333f, 3.25166667f, 3.24900000f }, + { 3.33950000f, 3.33646667f, 3.33200000f, 3.33000000f }, + { 3.41400000f, 3.41270000f, 3.40983333f, 3.40850000f }, + { 3.47500000f, 3.47326667f, 3.47066667f, 3.46950000f }, + { 3.53300000f, 3.53126667f, 3.52966667f, 3.52900000f }, + { 3.57600000f, 3.57513333f, 3.57466667f, 3.57450000f }, + { 3.62250000f, 3.62250000f, 3.62283333f, 3.62300000f }, + { 3.67050000f, 3.67180000f, 3.67266667f, 3.67300000f }, + { 3.72250000f, 3.72336667f, 3.72550000f, 3.72650000f }, + { 3.76700000f, 3.76916667f, 3.77183333f, 3.77300000f }, + { 3.81050000f, 3.81266667f, 3.81533333f, 3.81650000f }, + { 3.85250000f, 3.85423333f, 3.85683333f, 3.85800000f }, + { 3.90600000f, 3.90643333f, 3.90850000f, 3.90950000f }, + { 3.95450000f, 3.95536667f, 3.95683333f, 3.95750000f }, + { 4.00850000f, 4.00936667f, 4.01050000f, 4.01100000f }, + { 4.05600000f, 4.05686667f, 4.05833333f, 4.05900000f }, + { 4.07800000f, 4.07930000f, 4.08083333f, 4.08150000f }, + { 4.09900000f, 4.10116667f, 4.10283333f, 4.10350000f }, + { 4.16650000f, 4.16780000f, 4.17100000f, 4.17250000f }, +} }; + +// d(OCV)/d(SOC) in volts per unit SOC +constexpr P30BTable P30B_dOCV_dSOC = { { + { 4.50000000f, 4.36133333f, 4.50666667f, 4.59000000f }, + { 3.24500000f, 3.17133333f, 3.25333333f, 3.30000000f }, + { 1.78000000f, 1.78000000f, 1.80333333f, 1.81500000f }, + { 1.53000000f, 1.55166667f, 1.58166667f, 1.59500000f }, + { 1.35500000f, 1.36800000f, 1.38666667f, 1.39500000f }, + { 1.19000000f, 1.18566667f, 1.19833333f, 1.20500000f }, + { 1.01000000f, 1.01866667f, 1.04000000f, 1.05000000f }, + { 0.89500000f, 0.91233333f, 0.93166667f, 0.94000000f }, + { 0.94500000f, 0.96666667f, 0.98000000f, 0.98500000f }, + { 1.00000000f, 1.00866667f, 1.02666667f, 1.03500000f }, + { 0.96500000f, 0.97366667f, 0.99166667f, 1.00000000f }, + { 0.88000000f, 0.89300000f, 0.89833333f, 0.90000000f }, + { 0.85500000f, 0.85066667f, 0.85000000f, 0.85000000f }, + { 0.95500000f, 0.93766667f, 0.93166667f, 0.93000000f }, + { 1.02000000f, 1.01133333f, 1.00000000f, 0.99500000f }, + { 1.02500000f, 1.02933333f, 1.02000000f, 1.01500000f }, + { 1.01500000f, 1.01500000f, 1.01500000f, 1.01500000f }, + { 0.69500000f, 0.69933333f, 0.70333333f, 0.70500000f }, + { 0.43000000f, 0.44300000f, 0.44500000f, 0.44500000f }, + { 0.88500000f, 0.88500000f, 0.90166667f, 0.91000000f }, + { 1.35000000f, 1.33266667f, 1.36333333f, 1.38000000f }, +} }; + +// Series resistance of one cell while discharging, in ohms. +constexpr P30BTable P30B_R0_DIS_OHM = { { + { 0.07083453f, 0.05563725f, 0.03550818f, 0.01513335f }, + { 0.07083453f, 0.05563725f, 0.03550818f, 0.01513335f }, + { 0.01045934f, 0.00315000f, 0.01853349f, 0.01795000f }, + { 0.02484000f, 0.01953264f, 0.01715625f, 0.01601668f }, + { 0.02073636f, 0.01770543f, 0.01580122f, 0.01475000f }, + { 0.01783676f, 0.01564444f, 0.01475714f, 0.01404375f }, + { 0.01484375f, 0.01445484f, 0.01369833f, 0.01290000f }, + { 0.01649875f, 0.01067419f, 0.00928793f, 0.00787143f }, + { 0.01825405f, 0.01256912f, 0.00989138f, 0.00860200f }, + { 0.01750000f, 0.01257857f, 0.01029844f, 0.00925000f }, + { 0.01713750f, 0.01201667f, 0.01036212f, 0.00890172f }, + { 0.01681111f, 0.01231176f, 0.01082000f, 0.00968594f }, + { 0.01739429f, 0.01202500f, 0.01069394f, 0.00946000f }, + { 0.01680000f, 0.01239375f, 0.01071935f, 0.00925536f }, + { 0.01782344f, 0.01292333f, 0.01108704f, 0.00985000f }, + { 0.01791094f, 0.01331000f, 0.01122593f, 0.01032593f }, + { 0.01801111f, 0.01272344f, 0.01123387f, 0.01036000f }, + { 0.01850000f, 0.01323714f, 0.01134394f, 0.01023333f }, + { 0.01861250f, 0.01294821f, 0.01101731f, 0.00976667f }, + { 0.01882647f, 0.01357273f, 0.01135714f, 0.00978158f }, + { 0.01882647f, 0.01357273f, 0.01135714f, 0.00978158f }, +} }; + +// RC branch resistance of one cell while discharging, in ohms. +constexpr P30BTable P30B_R1_DIS_OHM = { { + { 0.25501617f, 0.15832715f, 0.15887515f, 1723712.76189689f }, // bad fit + { 0.25501617f, 0.15832715f, 0.15887515f, 1723712.76189689f }, // bad fit + { 0.12435599f, 0.10125000f, 8772007.78175694f, 1079585.57379464f }, // bad fit + { 0.02929333f, 0.03280582f, 0.03189375f, 226265.23958991f }, // bad fit + { 0.01586070f, 0.01644790f, 0.01693767f, 0.01715000f }, + { 0.01422540f, 0.01219556f, 0.01301786f, 0.01428958f }, + { 0.01507530f, 0.01069766f, 0.01044258f, 0.00960000f }, + { 0.01351077f, 0.01165544f, 0.01054033f, 0.01046190f }, + { 0.01257407f, 0.01153422f, 0.00994473f, 0.00883411f }, + { 0.01250000f, 0.01190476f, 0.01081490f, 0.00945000f }, + { 0.01286250f, 0.01145833f, 0.01114082f, 0.00987181f }, + { 0.01300317f, 0.01157824f, 0.01200500f, 0.01095252f }, + { 0.01211876f, 0.01098500f, 0.01134452f, 0.01029000f }, + { 0.01143333f, 0.01086339f, 0.01146953f, 0.01005020f }, + { 0.01130265f, 0.01013917f, 0.00911681f, 0.00857500f }, + { 0.01188536f, 0.01024000f, 0.00920220f, 0.00923771f }, + { 0.01300317f, 0.01130265f, 0.01049260f, 0.01029000f }, + { 0.01250000f, 0.01181580f, 0.01134452f, 0.01066667f }, + { 0.01000417f, 0.00946512f, 0.00885542f, 0.00853333f }, + { 0.00793035f, 0.00744394f, 0.00714286f, 0.00647467f }, + { 0.00793035f, 0.00744394f, 0.00714286f, 0.00647467f }, +} }; + +// RC branch time constant of one cell while discharging, in seconds. +constexpr P30BTable P30B_TAU1_DIS_S = { { + { 30.51133733f, 30.66089373f, 65.98486785f, 894272663.74314451f }, // bad fit + { 30.51133733f, 30.66089373f, 65.98486785f, 894272663.74314451f }, // bad fit + { 28.97967789f, 24.66303462f, 11318785970.07135963f, 2453602231.18314409f }, // bad fit + { 38.11494687f, 60.24635791f, 84.90187016f, 914204893.76948404f }, // bad fit + { 17.46666335f, 35.43178459f, 50.39028822f, 64.87159195f }, + { 13.58106366f, 22.63299846f, 39.79079143f, 58.19019522f }, + { 11.92848837f, 20.08683828f, 32.01283740f, 34.76059497f }, + { 23.69699636f, 15.96281797f, 17.12481575f, 16.15406563f }, + { 27.82616432f, 27.36279264f, 20.71028955f, 18.43915194f }, + { 19.57615189f, 28.03673252f, 26.01377645f, 24.66303462f }, + { 17.86940293f, 19.57615189f, 24.06649415f, 21.67572580f }, + { 17.38029748f, 21.61584858f, 29.72013412f, 29.33182797f }, + { 19.79825777f, 20.59699077f, 30.10834473f, 29.72013412f }, + { 17.86940293f, 27.55538335f, 39.23226389f, 35.87915009f }, + { 18.46390358f, 23.39487665f, 25.44253550f, 29.72013412f }, + { 16.34516968f, 21.27643145f, 21.48858984f, 29.26121629f }, + { 17.38029748f, 18.46390358f, 22.87210480f, 29.72013412f }, + { 19.57615189f, 25.25918085f, 30.10834473f, 34.76059497f }, + { 17.86940293f, 23.31026209f, 28.34295403f, 34.76059497f }, + { 12.04313898f, 22.97170887f, 28.03673252f, 28.45776931f }, + { 12.04313898f, 22.97170887f, 28.03673252f, 28.45776931f }, +} }; + +// Series resistance of one cell while charging, in ohms. +constexpr P30BTable P30B_R0_CHG_OHM = { { + { 0.02044130f, 0.01613875f, 0.01446711f, 0.01295588f }, + { 0.02044130f, 0.01613875f, 0.01446711f, 0.01295588f }, + { 0.02187750f, 0.01666200f, 0.01383261f, 0.01199167f }, + { 0.01905000f, 0.01452692f, 0.01228800f, 0.01144792f }, + { 0.01712742f, 0.01240000f, 0.01044333f, 0.00983333f }, + { 0.01614394f, 0.01145857f, 0.00942742f, 0.00834138f }, + { 0.01586528f, 0.01106912f, 0.00922353f, 0.00847500f }, + { 0.01607381f, 0.01122368f, 0.00935000f, 0.00870000f }, + { 0.01501842f, 0.01135147f, 0.00994844f, 0.00883710f }, + { 0.01548194f, 0.01188387f, 0.01061000f, 0.00967143f }, + { 0.01575294f, 0.01188710f, 0.01024821f, 0.00912308f }, + { 0.01565000f, 0.01192333f, 0.01004286f, 0.00886731f }, + { 0.01587000f, 0.01152500f, 0.00984286f, 0.00890000f }, + { 0.01515887f, 0.01091912f, 0.00987500f, 0.00873393f }, + { 0.01316071f, 0.01173333f, 0.01008182f, 0.00922759f }, + { 0.01466983f, 0.00935000f, 0.01076668f, 0.00881094f }, + { 0.01468600f, 0.01038378f, 0.00853088f, 0.00787500f }, + { 0.01649429f, 0.01163125f, 0.01033261f, 0.00907391f }, + { 0.01649394f, 0.01245000f, 0.01016731f, 0.00859167f }, + { 0.01775517f, 0.01226522f, 0.01037900f, 0.00904896f }, + { 0.01775517f, 0.01226522f, 0.01037900f, 0.00904896f }, +} }; + +// RC branch resistance of one cell while charging, in ohms. +constexpr P30BTable P30B_R1_CHG_OHM = { { + { 0.01620974f, 0.01751338f, 0.01427077f, 0.01221719f }, + { 0.01620974f, 0.01751338f, 0.01427077f, 0.01221719f }, + { 0.00691096f, 0.00844185f, 0.00780201f, 0.00816548f }, + { 0.00857500f, 0.00944808f, 0.00873422f, 0.00886637f }, + { 0.01056873f, 0.01250000f, 0.01143167f, 0.01109167f }, + { 0.01127856f, 0.01215297f, 0.01056873f, 0.01003135f }, + { 0.01240211f, 0.01152299f, 0.01148897f, 0.01109167f }, + { 0.01418528f, 0.01283632f, 0.01215000f, 0.01280000f }, + { 0.01351015f, 0.01165091f, 0.01081333f, 0.01046603f }, + { 0.01261006f, 0.01049260f, 0.01029000f, 0.00979857f }, + { 0.01195539f, 0.01046624f, 0.00946717f, 0.00879359f }, + { 0.01143333f, 0.01014095f, 0.00952381f, 0.00885542f }, + { 0.01194667f, 0.01012500f, 0.00952381f, 0.00960000f }, + { 0.02255692f, 0.01152299f, 0.01109167f, 0.00962971f }, + { 0.01951560f, 0.01386667f, 0.01150568f, 0.01022741f }, + { 0.01997612f, 0.01663750f, 226897.65965426f, 0.01129361f }, // bad fit + { 0.01854019f, 0.01354788f, 0.01208112f, 0.01147500f }, + { 0.01361177f, 0.00904018f, 0.00780201f, 0.00791498f }, + { 0.01361177f, 0.00945000f, 0.00885542f, 0.00818833f }, + { 0.02007114f, 0.01562478f, 0.02063464f, 0.02475818f }, + { 0.02007114f, 0.01562478f, 0.02063464f, 0.02475818f }, +} }; + +// RC branch time constant of one cell while charging, in seconds. +constexpr P30BTable P30B_TAU1_CHG_S = { { + { 8.87165295f, 12.86953810f, 15.99760120f, 17.60612858f }, + { 8.87165295f, 12.86953810f, 15.99760120f, 17.60612858f }, + { 19.96903649f, 23.88285926f, 22.32019685f, 21.76125456f }, + { 29.72013412f, 37.27671435f, 32.52194339f, 39.07266895f }, + { 28.55491327f, 44.81420118f, 42.30319257f, 49.83288655f }, + { 21.10664896f, 31.66030274f, 28.55491327f, 31.09611078f }, + { 20.24215670f, 22.52600345f, 25.92940848f, 31.40173602f }, + { 23.74093145f, 23.64866498f, 24.66303462f, 34.76059497f }, + { 18.11369152f, 20.79120253f, 23.46952883f, 24.02919660f }, + { 18.96256110f, 22.87210480f, 29.72013412f, 32.74590996f }, + { 18.72369955f, 25.33863874f, 26.22142295f, 26.35118177f }, + { 17.86940293f, 26.11018876f, 28.03673252f, 28.34295403f }, + { 21.27643145f, 24.66303462f, 28.03673252f, 34.76059497f }, + { 37.40908149f, 22.52600345f, 31.40173602f, 30.17891850f }, + { 19.30714042f, 34.76059497f, 32.24195100f, 33.75347224f }, + { 20.26613977f, 22.12462197f, 916761456.07631612f, 33.84504642f }, // bad fit + { 16.39974519f, 16.84140447f, 18.14299484f, 24.66303462f }, + { 15.05662094f, 15.90814866f, 22.32019685f, 30.28085308f }, + { 13.83125590f, 24.66303462f, 28.34295403f, 28.71032962f }, + { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f }, + { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f }, +} }; +} // namespace + +namespace app::soc +{ +void update() { + // read of all cell voltages + // read of all cell temps +} +void broadcast() {} +} // namespace app::soc diff --git a/firmware/hexray/BMS/src/app/app_soc.hpp b/firmware/hexray/BMS/src/app/app_soc.hpp new file mode 100644 index 0000000000..db5246f311 --- /dev/null +++ b/firmware/hexray/BMS/src/app/app_soc.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace app::soc +{ +void update(); +void broadcast(); +} // namespace app::soc diff --git a/firmware/hexray/BMS/src/tasks.cpp b/firmware/hexray/BMS/src/tasks.cpp index e256462084..938cdd2b6c 100644 --- a/firmware/hexray/BMS/src/tasks.cpp +++ b/firmware/hexray/BMS/src/tasks.cpp @@ -35,6 +35,7 @@ constexpr size_t TASK_COUNT = 10; [[noreturn]] static void tasks_runAdbmsConfigs(void *arg); [[noreturn]] static void tasks_runAdbmsAux(void *arg); [[noreturn]] static void tasks_runAdbmsCellOwc(void *arg); +[[noreturn]] static void tasks_runSdCard(void *arg); static hw::rtos::StaticTask::StaticTaskStack<512> Task1kHzStack; static hw::rtos::StaticTask::StaticTaskStack<512> Task1HzStack; @@ -46,6 +47,7 @@ static hw::rtos::StaticTask::StaticTaskStack<1024 * 3> TaskAdbmsVoltagesStack; static hw::rtos::StaticTask::StaticTaskStack<1024 * 3> TaskAdbmsConfigsStack; static hw::rtos::StaticTask::StaticTaskStack<1024 * 3> TaskAdbmsAuxStack; static hw::rtos::StaticTask::StaticTaskStack<1024 * 3> TaskAdbmsCellOwcStack; +static hw::rtos::StaticTask::StaticTaskStack<512> TaskSdCardStack; static hw::rtos::StaticTask Task1kHz(osPriorityRealtime, "Task1kHz", tasks_run1kHz, Task1kHzStack); static hw::rtos::StaticTask Task1Hz(osPriorityAboveNormal, "Task1Hz", tasks_run1Hz, Task1HzStack); @@ -62,6 +64,7 @@ static hw::rtos::StaticTask static hw::rtos::StaticTask TaskAdbmsAux(osPriorityNormal, "TaskAdbmsAux", tasks_runAdbmsAux, TaskAdbmsAuxStack); static hw::rtos::StaticTask TaskAdbmsCellOwc(osPriorityNormal, "TaskAdbmsCellOwc", tasks_runAdbmsCellOwc, TaskAdbmsCellOwcStack); +static hw::rtos::StaticTask TaskSdCard(osPriorityNormal, "TaskSdCard", tasks_runSdCard, TaskSdCardStack); // static hw::runtimeStat::monitor runtimeMonitor( // { @@ -279,6 +282,10 @@ void tasks_runAdbmsCellOwc(void *arg) } } +void tasks_runSdCard(void *arg) { + +} + void BMS_StartAllTasks() { Task1kHz.start(); From 1a5da39cbcd1f28d691ccb05fee66bf47c13f84f Mon Sep 17 00:00:00 2001 From: Pranay Oza <105095960+pranay-o@users.noreply.github.com> Date: Sat, 5 Sep 2026 23:35:32 -0700 Subject: [PATCH 2/4] soc shi --- firmware/hexray/BMS/src/app/app_soc.cpp | 28 +++++++++++++++++-- firmware/hexray/BMS/src/app/app_soc.hpp | 8 ++++++ .../BMS/src/app/pack/app_pack_alerts.cpp | 6 ++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/firmware/hexray/BMS/src/app/app_soc.cpp b/firmware/hexray/BMS/src/app/app_soc.cpp index b8d534f29e..236e52928e 100644 --- a/firmware/hexray/BMS/src/app/app_soc.cpp +++ b/firmware/hexray/BMS/src/app/app_soc.cpp @@ -1,4 +1,5 @@ #include "app_soc.hpp" +#include "app_pack.hpp" #include #include @@ -220,13 +221,34 @@ constexpr P30BTable P30B_TAU1_CHG_S = { { { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f }, { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f }, } }; + +app::pack::PackChannel::Subscription volt_sub{ "soc_volt" }; +app::pack::PackChannel::Subscription temp_sub{ "soc_temp" }; + +app::soc::SocStats soc {}; +app::pack::VoltStats volts {}; +app::pack::TempStats temps {}; + } // namespace namespace app::soc { +void init() { + app::pack::voltage_channel.subscribe(volt_sub); + app::pack::temperature_channel.subscribe(temp_sub); + + //if there are intial soc values in sd card use that else use ocv lookup + //or maybe just take mean of the two idk +} void update() { - // read of all cell voltages - // read of all cell temps + + while (const auto stats = volt_sub.pop(0)) volts = *stats; + while (const auto stats = temp_sub.pop(0)) temps = *stats; + + if (volts.updated_ms > soc.updated_ms || temps.updated_ms > soc.updated_ms) + calculate(volts, temps); +} +void broadcast() { + } -void broadcast() {} } // namespace app::soc diff --git a/firmware/hexray/BMS/src/app/app_soc.hpp b/firmware/hexray/BMS/src/app/app_soc.hpp index db5246f311..3587b96a94 100644 --- a/firmware/hexray/BMS/src/app/app_soc.hpp +++ b/firmware/hexray/BMS/src/app/app_soc.hpp @@ -2,6 +2,14 @@ namespace app::soc { +struct SocStats { + uint32_t updated_ms = 0U; + app::pack::LocatedValue max{}; + app::pack::LocatedValue min{}; + io::adbms::Cells soc{}; + app::pack::CellFlags valid{}; +}; + void update(); void broadcast(); } // namespace app::soc diff --git a/firmware/hexray/BMS/src/app/pack/app_pack_alerts.cpp b/firmware/hexray/BMS/src/app/pack/app_pack_alerts.cpp index c9fb93e966..7c7560af76 100644 --- a/firmware/hexray/BMS/src/app/pack/app_pack_alerts.cpp +++ b/firmware/hexray/BMS/src/app/pack/app_pack_alerts.cpp @@ -125,9 +125,9 @@ bool isThermOpenWireInfo(const OwcStats &stats) return stats.updated_ms != 0U && anyClear(stats.therms_ok); } -app::pack::PackChannel::Subscription volt_sub{ "alerts_volt" }; -app::pack::PackChannel::Subscription temp_sub{ "alerts_temp" }; -app::pack::PackChannel::Subscription owc_sub{ "alerts_owc" }; +app::pack::PackChannel::Subscription volt_sub{ "alerts_volt" }; +app::pack::PackChannel::Subscription temp_sub{ "alerts_temp" }; +app::pack::PackChannel::Subscription owc_sub{ "alerts_owc" }; bool volt_fault_active = false; bool temp_fault_active = false; From 4bedd1b71bc4e0278cd85adca9207012c3b15db9 Mon Sep 17 00:00:00 2001 From: Pranay Oza <105095960+pranay-o@users.noreply.github.com> Date: Wed, 9 Sep 2026 21:56:51 -0700 Subject: [PATCH 3/4] better data --- firmware/hexray/BMS/src/app/app_soc.cpp | 371 ++++++++++++------------ firmware/hexray/BMS/src/app/app_soc.hpp | 6 + firmware/hexray/BMS/src/jobs.cpp | 5 + 3 files changed, 200 insertions(+), 182 deletions(-) diff --git a/firmware/hexray/BMS/src/app/app_soc.cpp b/firmware/hexray/BMS/src/app/app_soc.cpp index 236e52928e..f2c745c7b2 100644 --- a/firmware/hexray/BMS/src/app/app_soc.cpp +++ b/firmware/hexray/BMS/src/app/app_soc.cpp @@ -1,5 +1,6 @@ #include "app_soc.hpp" #include "app_pack.hpp" +#include "app_canTx.hpp" #include #include @@ -24,231 +25,237 @@ constexpr std::array P30B_TEMP_BP_C = { // Open circuit voltage of one cell, in volts. constexpr P30BTable P30B_OCV_V = { { - { 2.93650000f, 2.94040000f, 2.92633333f, 2.91900000f }, - { 3.16150000f, 3.15846667f, 3.15166667f, 3.14850000f }, - { 3.26100000f, 3.25753333f, 3.25166667f, 3.24900000f }, - { 3.33950000f, 3.33646667f, 3.33200000f, 3.33000000f }, - { 3.41400000f, 3.41270000f, 3.40983333f, 3.40850000f }, - { 3.47500000f, 3.47326667f, 3.47066667f, 3.46950000f }, - { 3.53300000f, 3.53126667f, 3.52966667f, 3.52900000f }, - { 3.57600000f, 3.57513333f, 3.57466667f, 3.57450000f }, - { 3.62250000f, 3.62250000f, 3.62283333f, 3.62300000f }, - { 3.67050000f, 3.67180000f, 3.67266667f, 3.67300000f }, - { 3.72250000f, 3.72336667f, 3.72550000f, 3.72650000f }, - { 3.76700000f, 3.76916667f, 3.77183333f, 3.77300000f }, - { 3.81050000f, 3.81266667f, 3.81533333f, 3.81650000f }, - { 3.85250000f, 3.85423333f, 3.85683333f, 3.85800000f }, - { 3.90600000f, 3.90643333f, 3.90850000f, 3.90950000f }, - { 3.95450000f, 3.95536667f, 3.95683333f, 3.95750000f }, - { 4.00850000f, 4.00936667f, 4.01050000f, 4.01100000f }, - { 4.05600000f, 4.05686667f, 4.05833333f, 4.05900000f }, - { 4.07800000f, 4.07930000f, 4.08083333f, 4.08150000f }, - { 4.09900000f, 4.10116667f, 4.10283333f, 4.10350000f }, - { 4.16650000f, 4.16780000f, 4.17100000f, 4.17250000f }, + { { 2.93650000f, 2.94040000f, 2.92633333f, 2.91900000f } }, + { { 3.16150000f, 3.15846667f, 3.15166667f, 3.14850000f } }, + { { 3.26100000f, 3.25753333f, 3.25166667f, 3.24900000f } }, + { { 3.33950000f, 3.33646667f, 3.33200000f, 3.33000000f } }, + { { 3.41400000f, 3.41270000f, 3.40983333f, 3.40850000f } }, + { { 3.47500000f, 3.47326667f, 3.47066667f, 3.46950000f } }, + { { 3.53300000f, 3.53126667f, 3.52966667f, 3.52900000f } }, + { { 3.57600000f, 3.57513333f, 3.57466667f, 3.57450000f } }, + { { 3.62250000f, 3.62250000f, 3.62283333f, 3.62300000f } }, + { { 3.67050000f, 3.67180000f, 3.67266667f, 3.67300000f } }, + { { 3.72250000f, 3.72336667f, 3.72550000f, 3.72650000f } }, + { { 3.76700000f, 3.76916667f, 3.77183333f, 3.77300000f } }, + { { 3.81050000f, 3.81266667f, 3.81533333f, 3.81650000f } }, + { { 3.85250000f, 3.85423333f, 3.85683333f, 3.85800000f } }, + { { 3.90600000f, 3.90643333f, 3.90850000f, 3.90950000f } }, + { { 3.95450000f, 3.95536667f, 3.95683333f, 3.95750000f } }, + { { 4.00850000f, 4.00936667f, 4.01050000f, 4.01100000f } }, + { { 4.05600000f, 4.05686667f, 4.05833333f, 4.05900000f } }, + { { 4.07800000f, 4.07930000f, 4.08083333f, 4.08150000f } }, + { { 4.09900000f, 4.10116667f, 4.10283333f, 4.10350000f } }, + { { 4.16650000f, 4.16780000f, 4.17100000f, 4.17250000f } }, } }; // d(OCV)/d(SOC) in volts per unit SOC constexpr P30BTable P30B_dOCV_dSOC = { { - { 4.50000000f, 4.36133333f, 4.50666667f, 4.59000000f }, - { 3.24500000f, 3.17133333f, 3.25333333f, 3.30000000f }, - { 1.78000000f, 1.78000000f, 1.80333333f, 1.81500000f }, - { 1.53000000f, 1.55166667f, 1.58166667f, 1.59500000f }, - { 1.35500000f, 1.36800000f, 1.38666667f, 1.39500000f }, - { 1.19000000f, 1.18566667f, 1.19833333f, 1.20500000f }, - { 1.01000000f, 1.01866667f, 1.04000000f, 1.05000000f }, - { 0.89500000f, 0.91233333f, 0.93166667f, 0.94000000f }, - { 0.94500000f, 0.96666667f, 0.98000000f, 0.98500000f }, - { 1.00000000f, 1.00866667f, 1.02666667f, 1.03500000f }, - { 0.96500000f, 0.97366667f, 0.99166667f, 1.00000000f }, - { 0.88000000f, 0.89300000f, 0.89833333f, 0.90000000f }, - { 0.85500000f, 0.85066667f, 0.85000000f, 0.85000000f }, - { 0.95500000f, 0.93766667f, 0.93166667f, 0.93000000f }, - { 1.02000000f, 1.01133333f, 1.00000000f, 0.99500000f }, - { 1.02500000f, 1.02933333f, 1.02000000f, 1.01500000f }, - { 1.01500000f, 1.01500000f, 1.01500000f, 1.01500000f }, - { 0.69500000f, 0.69933333f, 0.70333333f, 0.70500000f }, - { 0.43000000f, 0.44300000f, 0.44500000f, 0.44500000f }, - { 0.88500000f, 0.88500000f, 0.90166667f, 0.91000000f }, - { 1.35000000f, 1.33266667f, 1.36333333f, 1.38000000f }, + { { 4.50000000f, 4.36133333f, 4.50666667f, 4.59000000f } }, + { { 3.24500000f, 3.17133333f, 3.25333333f, 3.30000000f } }, + { { 1.78000000f, 1.78000000f, 1.80333333f, 1.81500000f } }, + { { 1.53000000f, 1.55166667f, 1.58166667f, 1.59500000f } }, + { { 1.35500000f, 1.36800000f, 1.38666667f, 1.39500000f } }, + { { 1.19000000f, 1.18566667f, 1.19833333f, 1.20500000f } }, + { { 1.01000000f, 1.01866667f, 1.04000000f, 1.05000000f } }, + { { 0.89500000f, 0.91233333f, 0.93166667f, 0.94000000f } }, + { { 0.94500000f, 0.96666667f, 0.98000000f, 0.98500000f } }, + { { 1.00000000f, 1.00866667f, 1.02666667f, 1.03500000f } }, + { { 0.96500000f, 0.97366667f, 0.99166667f, 1.00000000f } }, + { { 0.88000000f, 0.89300000f, 0.89833333f, 0.90000000f } }, + { { 0.85500000f, 0.85066667f, 0.85000000f, 0.85000000f } }, + { { 0.95500000f, 0.93766667f, 0.93166667f, 0.93000000f } }, + { { 1.02000000f, 1.01133333f, 1.00000000f, 0.99500000f } }, + { { 1.02500000f, 1.02933333f, 1.02000000f, 1.01500000f } }, + { { 1.01500000f, 1.01500000f, 1.01500000f, 1.01500000f } }, + { { 0.69500000f, 0.69933333f, 0.70333333f, 0.70500000f } }, + { { 0.43000000f, 0.44300000f, 0.44500000f, 0.44500000f } }, + { { 0.88500000f, 0.88500000f, 0.90166667f, 0.91000000f } }, + { { 1.35000000f, 1.33266667f, 1.36333333f, 1.38000000f } }, } }; // Series resistance of one cell while discharging, in ohms. constexpr P30BTable P30B_R0_DIS_OHM = { { - { 0.07083453f, 0.05563725f, 0.03550818f, 0.01513335f }, - { 0.07083453f, 0.05563725f, 0.03550818f, 0.01513335f }, - { 0.01045934f, 0.00315000f, 0.01853349f, 0.01795000f }, - { 0.02484000f, 0.01953264f, 0.01715625f, 0.01601668f }, - { 0.02073636f, 0.01770543f, 0.01580122f, 0.01475000f }, - { 0.01783676f, 0.01564444f, 0.01475714f, 0.01404375f }, - { 0.01484375f, 0.01445484f, 0.01369833f, 0.01290000f }, - { 0.01649875f, 0.01067419f, 0.00928793f, 0.00787143f }, - { 0.01825405f, 0.01256912f, 0.00989138f, 0.00860200f }, - { 0.01750000f, 0.01257857f, 0.01029844f, 0.00925000f }, - { 0.01713750f, 0.01201667f, 0.01036212f, 0.00890172f }, - { 0.01681111f, 0.01231176f, 0.01082000f, 0.00968594f }, - { 0.01739429f, 0.01202500f, 0.01069394f, 0.00946000f }, - { 0.01680000f, 0.01239375f, 0.01071935f, 0.00925536f }, - { 0.01782344f, 0.01292333f, 0.01108704f, 0.00985000f }, - { 0.01791094f, 0.01331000f, 0.01122593f, 0.01032593f }, - { 0.01801111f, 0.01272344f, 0.01123387f, 0.01036000f }, - { 0.01850000f, 0.01323714f, 0.01134394f, 0.01023333f }, - { 0.01861250f, 0.01294821f, 0.01101731f, 0.00976667f }, - { 0.01882647f, 0.01357273f, 0.01135714f, 0.00978158f }, - { 0.01882647f, 0.01357273f, 0.01135714f, 0.00978158f }, + { { 0.07083453f, 0.05563725f, 0.03550818f, 0.01513335f } }, + { { 0.07083453f, 0.05563725f, 0.03550818f, 0.01513335f } }, + { { 0.01045934f, 0.00315000f, 0.01853349f, 0.01795000f } }, + { { 0.02484000f, 0.01953264f, 0.01715625f, 0.01601668f } }, + { { 0.02073636f, 0.01770543f, 0.01580122f, 0.01475000f } }, + { { 0.01783676f, 0.01564444f, 0.01475714f, 0.01404375f } }, + { { 0.01484375f, 0.01445484f, 0.01369833f, 0.01290000f } }, + { { 0.01649875f, 0.01067419f, 0.00928793f, 0.00787143f } }, + { { 0.01825405f, 0.01256912f, 0.00989138f, 0.00860200f } }, + { { 0.01750000f, 0.01257857f, 0.01029844f, 0.00925000f } }, + { { 0.01713750f, 0.01201667f, 0.01036212f, 0.00890172f } }, + { { 0.01681111f, 0.01231176f, 0.01082000f, 0.00968594f } }, + { { 0.01739429f, 0.01202500f, 0.01069394f, 0.00946000f } }, + { { 0.01680000f, 0.01239375f, 0.01071935f, 0.00925536f } }, + { { 0.01782344f, 0.01292333f, 0.01108704f, 0.00985000f } }, + { { 0.01791094f, 0.01331000f, 0.01122593f, 0.01032593f } }, + { { 0.01801111f, 0.01272344f, 0.01123387f, 0.01036000f } }, + { { 0.01850000f, 0.01323714f, 0.01134394f, 0.01023333f } }, + { { 0.01861250f, 0.01294821f, 0.01101731f, 0.00976667f } }, + { { 0.01882647f, 0.01357273f, 0.01135714f, 0.00978158f } }, + { { 0.01882647f, 0.01357273f, 0.01135714f, 0.00978158f } }, } }; // RC branch resistance of one cell while discharging, in ohms. constexpr P30BTable P30B_R1_DIS_OHM = { { - { 0.25501617f, 0.15832715f, 0.15887515f, 1723712.76189689f }, // bad fit - { 0.25501617f, 0.15832715f, 0.15887515f, 1723712.76189689f }, // bad fit - { 0.12435599f, 0.10125000f, 8772007.78175694f, 1079585.57379464f }, // bad fit - { 0.02929333f, 0.03280582f, 0.03189375f, 226265.23958991f }, // bad fit - { 0.01586070f, 0.01644790f, 0.01693767f, 0.01715000f }, - { 0.01422540f, 0.01219556f, 0.01301786f, 0.01428958f }, - { 0.01507530f, 0.01069766f, 0.01044258f, 0.00960000f }, - { 0.01351077f, 0.01165544f, 0.01054033f, 0.01046190f }, - { 0.01257407f, 0.01153422f, 0.00994473f, 0.00883411f }, - { 0.01250000f, 0.01190476f, 0.01081490f, 0.00945000f }, - { 0.01286250f, 0.01145833f, 0.01114082f, 0.00987181f }, - { 0.01300317f, 0.01157824f, 0.01200500f, 0.01095252f }, - { 0.01211876f, 0.01098500f, 0.01134452f, 0.01029000f }, - { 0.01143333f, 0.01086339f, 0.01146953f, 0.01005020f }, - { 0.01130265f, 0.01013917f, 0.00911681f, 0.00857500f }, - { 0.01188536f, 0.01024000f, 0.00920220f, 0.00923771f }, - { 0.01300317f, 0.01130265f, 0.01049260f, 0.01029000f }, - { 0.01250000f, 0.01181580f, 0.01134452f, 0.01066667f }, - { 0.01000417f, 0.00946512f, 0.00885542f, 0.00853333f }, - { 0.00793035f, 0.00744394f, 0.00714286f, 0.00647467f }, - { 0.00793035f, 0.00744394f, 0.00714286f, 0.00647467f }, + { { 0.25501617f, 0.15832715f, 0.15887515f, 1723712.76189689f } }, // bad fit + { { 0.25501617f, 0.15832715f, 0.15887515f, 1723712.76189689f } }, // bad fit + { { 0.12435599f, 0.10125000f, 8772007.78175694f, 1079585.57379464f } }, // bad fit + { { 0.02929333f, 0.03280582f, 0.03189375f, 226265.23958991f } }, // bad fit + { { 0.01586070f, 0.01644790f, 0.01693767f, 0.01715000f } }, + { { 0.01422540f, 0.01219556f, 0.01301786f, 0.01428958f } }, + { { 0.01507530f, 0.01069766f, 0.01044258f, 0.00960000f } }, + { { 0.01351077f, 0.01165544f, 0.01054033f, 0.01046190f } }, + { { 0.01257407f, 0.01153422f, 0.00994473f, 0.00883411f } }, + { { 0.01250000f, 0.01190476f, 0.01081490f, 0.00945000f } }, + { { 0.01286250f, 0.01145833f, 0.01114082f, 0.00987181f } }, + { { 0.01300317f, 0.01157824f, 0.01200500f, 0.01095252f } }, + { { 0.01211876f, 0.01098500f, 0.01134452f, 0.01029000f } }, + { { 0.01143333f, 0.01086339f, 0.01146953f, 0.01005020f } }, + { { 0.01130265f, 0.01013917f, 0.00911681f, 0.00857500f } }, + { { 0.01188536f, 0.01024000f, 0.00920220f, 0.00923771f } }, + { { 0.01300317f, 0.01130265f, 0.01049260f, 0.01029000f } }, + { { 0.01250000f, 0.01181580f, 0.01134452f, 0.01066667f } }, + { { 0.01000417f, 0.00946512f, 0.00885542f, 0.00853333f } }, + { { 0.00793035f, 0.00744394f, 0.00714286f, 0.00647467f } }, + { { 0.00793035f, 0.00744394f, 0.00714286f, 0.00647467f } }, } }; // RC branch time constant of one cell while discharging, in seconds. constexpr P30BTable P30B_TAU1_DIS_S = { { - { 30.51133733f, 30.66089373f, 65.98486785f, 894272663.74314451f }, // bad fit - { 30.51133733f, 30.66089373f, 65.98486785f, 894272663.74314451f }, // bad fit - { 28.97967789f, 24.66303462f, 11318785970.07135963f, 2453602231.18314409f }, // bad fit - { 38.11494687f, 60.24635791f, 84.90187016f, 914204893.76948404f }, // bad fit - { 17.46666335f, 35.43178459f, 50.39028822f, 64.87159195f }, - { 13.58106366f, 22.63299846f, 39.79079143f, 58.19019522f }, - { 11.92848837f, 20.08683828f, 32.01283740f, 34.76059497f }, - { 23.69699636f, 15.96281797f, 17.12481575f, 16.15406563f }, - { 27.82616432f, 27.36279264f, 20.71028955f, 18.43915194f }, - { 19.57615189f, 28.03673252f, 26.01377645f, 24.66303462f }, - { 17.86940293f, 19.57615189f, 24.06649415f, 21.67572580f }, - { 17.38029748f, 21.61584858f, 29.72013412f, 29.33182797f }, - { 19.79825777f, 20.59699077f, 30.10834473f, 29.72013412f }, - { 17.86940293f, 27.55538335f, 39.23226389f, 35.87915009f }, - { 18.46390358f, 23.39487665f, 25.44253550f, 29.72013412f }, - { 16.34516968f, 21.27643145f, 21.48858984f, 29.26121629f }, - { 17.38029748f, 18.46390358f, 22.87210480f, 29.72013412f }, - { 19.57615189f, 25.25918085f, 30.10834473f, 34.76059497f }, - { 17.86940293f, 23.31026209f, 28.34295403f, 34.76059497f }, - { 12.04313898f, 22.97170887f, 28.03673252f, 28.45776931f }, - { 12.04313898f, 22.97170887f, 28.03673252f, 28.45776931f }, + { { 30.51133733f, 30.66089373f, 65.98486785f, 894272663.74314451f } }, // bad fit + { { 30.51133733f, 30.66089373f, 65.98486785f, 894272663.74314451f } }, // bad fit + { { 28.97967789f, 24.66303462f, 11318785970.07135963f, 2453602231.18314409f } }, // bad fit + { { 38.11494687f, 60.24635791f, 84.90187016f, 914204893.76948404f } }, // bad fit + { { 17.46666335f, 35.43178459f, 50.39028822f, 64.87159195f } }, + { { 13.58106366f, 22.63299846f, 39.79079143f, 58.19019522f } }, + { { 11.92848837f, 20.08683828f, 32.01283740f, 34.76059497f } }, + { { 23.69699636f, 15.96281797f, 17.12481575f, 16.15406563f } }, + { { 27.82616432f, 27.36279264f, 20.71028955f, 18.43915194f } }, + { { 19.57615189f, 28.03673252f, 26.01377645f, 24.66303462f } }, + { { 17.86940293f, 19.57615189f, 24.06649415f, 21.67572580f } }, + { { 17.38029748f, 21.61584858f, 29.72013412f, 29.33182797f } }, + { { 19.79825777f, 20.59699077f, 30.10834473f, 29.72013412f } }, + { { 17.86940293f, 27.55538335f, 39.23226389f, 35.87915009f } }, + { { 18.46390358f, 23.39487665f, 25.44253550f, 29.72013412f } }, + { { 16.34516968f, 21.27643145f, 21.48858984f, 29.26121629f } }, + { { 17.38029748f, 18.46390358f, 22.87210480f, 29.72013412f } }, + { { 19.57615189f, 25.25918085f, 30.10834473f, 34.76059497f } }, + { { 17.86940293f, 23.31026209f, 28.34295403f, 34.76059497f } }, + { { 12.04313898f, 22.97170887f, 28.03673252f, 28.45776931f } }, + { { 12.04313898f, 22.97170887f, 28.03673252f, 28.45776931f } }, } }; // Series resistance of one cell while charging, in ohms. constexpr P30BTable P30B_R0_CHG_OHM = { { - { 0.02044130f, 0.01613875f, 0.01446711f, 0.01295588f }, - { 0.02044130f, 0.01613875f, 0.01446711f, 0.01295588f }, - { 0.02187750f, 0.01666200f, 0.01383261f, 0.01199167f }, - { 0.01905000f, 0.01452692f, 0.01228800f, 0.01144792f }, - { 0.01712742f, 0.01240000f, 0.01044333f, 0.00983333f }, - { 0.01614394f, 0.01145857f, 0.00942742f, 0.00834138f }, - { 0.01586528f, 0.01106912f, 0.00922353f, 0.00847500f }, - { 0.01607381f, 0.01122368f, 0.00935000f, 0.00870000f }, - { 0.01501842f, 0.01135147f, 0.00994844f, 0.00883710f }, - { 0.01548194f, 0.01188387f, 0.01061000f, 0.00967143f }, - { 0.01575294f, 0.01188710f, 0.01024821f, 0.00912308f }, - { 0.01565000f, 0.01192333f, 0.01004286f, 0.00886731f }, - { 0.01587000f, 0.01152500f, 0.00984286f, 0.00890000f }, - { 0.01515887f, 0.01091912f, 0.00987500f, 0.00873393f }, - { 0.01316071f, 0.01173333f, 0.01008182f, 0.00922759f }, - { 0.01466983f, 0.00935000f, 0.01076668f, 0.00881094f }, - { 0.01468600f, 0.01038378f, 0.00853088f, 0.00787500f }, - { 0.01649429f, 0.01163125f, 0.01033261f, 0.00907391f }, - { 0.01649394f, 0.01245000f, 0.01016731f, 0.00859167f }, - { 0.01775517f, 0.01226522f, 0.01037900f, 0.00904896f }, - { 0.01775517f, 0.01226522f, 0.01037900f, 0.00904896f }, + { { 0.02044130f, 0.01613875f, 0.01446711f, 0.01295588f } }, + { { 0.02044130f, 0.01613875f, 0.01446711f, 0.01295588f } }, + { { 0.02187750f, 0.01666200f, 0.01383261f, 0.01199167f } }, + { { 0.01905000f, 0.01452692f, 0.01228800f, 0.01144792f } }, + { { 0.01712742f, 0.01240000f, 0.01044333f, 0.00983333f } }, + { { 0.01614394f, 0.01145857f, 0.00942742f, 0.00834138f } }, + { { 0.01586528f, 0.01106912f, 0.00922353f, 0.00847500f } }, + { { 0.01607381f, 0.01122368f, 0.00935000f, 0.00870000f } }, + { { 0.01501842f, 0.01135147f, 0.00994844f, 0.00883710f } }, + { { 0.01548194f, 0.01188387f, 0.01061000f, 0.00967143f } }, + { { 0.01575294f, 0.01188710f, 0.01024821f, 0.00912308f } }, + { { 0.01565000f, 0.01192333f, 0.01004286f, 0.00886731f } }, + { { 0.01587000f, 0.01152500f, 0.00984286f, 0.00890000f } }, + { { 0.01515887f, 0.01091912f, 0.00987500f, 0.00873393f } }, + { { 0.01316071f, 0.01173333f, 0.01008182f, 0.00922759f } }, + { { 0.01466983f, 0.00935000f, 0.01076668f, 0.00881094f } }, + { { 0.01468600f, 0.01038378f, 0.00853088f, 0.00787500f } }, + { { 0.01649429f, 0.01163125f, 0.01033261f, 0.00907391f } }, + { { 0.01649394f, 0.01245000f, 0.01016731f, 0.00859167f } }, + { { 0.01775517f, 0.01226522f, 0.01037900f, 0.00904896f } }, + { { 0.01775517f, 0.01226522f, 0.01037900f, 0.00904896f } }, } }; // RC branch resistance of one cell while charging, in ohms. constexpr P30BTable P30B_R1_CHG_OHM = { { - { 0.01620974f, 0.01751338f, 0.01427077f, 0.01221719f }, - { 0.01620974f, 0.01751338f, 0.01427077f, 0.01221719f }, - { 0.00691096f, 0.00844185f, 0.00780201f, 0.00816548f }, - { 0.00857500f, 0.00944808f, 0.00873422f, 0.00886637f }, - { 0.01056873f, 0.01250000f, 0.01143167f, 0.01109167f }, - { 0.01127856f, 0.01215297f, 0.01056873f, 0.01003135f }, - { 0.01240211f, 0.01152299f, 0.01148897f, 0.01109167f }, - { 0.01418528f, 0.01283632f, 0.01215000f, 0.01280000f }, - { 0.01351015f, 0.01165091f, 0.01081333f, 0.01046603f }, - { 0.01261006f, 0.01049260f, 0.01029000f, 0.00979857f }, - { 0.01195539f, 0.01046624f, 0.00946717f, 0.00879359f }, - { 0.01143333f, 0.01014095f, 0.00952381f, 0.00885542f }, - { 0.01194667f, 0.01012500f, 0.00952381f, 0.00960000f }, - { 0.02255692f, 0.01152299f, 0.01109167f, 0.00962971f }, - { 0.01951560f, 0.01386667f, 0.01150568f, 0.01022741f }, - { 0.01997612f, 0.01663750f, 226897.65965426f, 0.01129361f }, // bad fit - { 0.01854019f, 0.01354788f, 0.01208112f, 0.01147500f }, - { 0.01361177f, 0.00904018f, 0.00780201f, 0.00791498f }, - { 0.01361177f, 0.00945000f, 0.00885542f, 0.00818833f }, - { 0.02007114f, 0.01562478f, 0.02063464f, 0.02475818f }, - { 0.02007114f, 0.01562478f, 0.02063464f, 0.02475818f }, + { { 0.01620974f, 0.01751338f, 0.01427077f, 0.01221719f } }, + { { 0.01620974f, 0.01751338f, 0.01427077f, 0.01221719f } }, + { { 0.00691096f, 0.00844185f, 0.00780201f, 0.00816548f } }, + { { 0.00857500f, 0.00944808f, 0.00873422f, 0.00886637f } }, + { { 0.01056873f, 0.01250000f, 0.01143167f, 0.01109167f } }, + { { 0.01127856f, 0.01215297f, 0.01056873f, 0.01003135f } }, + { { 0.01240211f, 0.01152299f, 0.01148897f, 0.01109167f } }, + { { 0.01418528f, 0.01283632f, 0.01215000f, 0.01280000f } }, + { { 0.01351015f, 0.01165091f, 0.01081333f, 0.01046603f } }, + { { 0.01261006f, 0.01049260f, 0.01029000f, 0.00979857f } }, + { { 0.01195539f, 0.01046624f, 0.00946717f, 0.00879359f } }, + { { 0.01143333f, 0.01014095f, 0.00952381f, 0.00885542f } }, + { { 0.01194667f, 0.01012500f, 0.00952381f, 0.00960000f } }, + { { 0.02255692f, 0.01152299f, 0.01109167f, 0.00962971f } }, + { { 0.01951560f, 0.01386667f, 0.01150568f, 0.01022741f } }, + { { 0.01997612f, 0.01663750f, 226897.65965426f, 0.01129361f } }, // bad fit + { { 0.01854019f, 0.01354788f, 0.01208112f, 0.01147500f } }, + { { 0.01361177f, 0.00904018f, 0.00780201f, 0.00791498f } }, + { { 0.01361177f, 0.00945000f, 0.00885542f, 0.00818833f } }, + { { 0.02007114f, 0.01562478f, 0.02063464f, 0.02475818f } }, + { { 0.02007114f, 0.01562478f, 0.02063464f, 0.02475818f } }, } }; // RC branch time constant of one cell while charging, in seconds. constexpr P30BTable P30B_TAU1_CHG_S = { { - { 8.87165295f, 12.86953810f, 15.99760120f, 17.60612858f }, - { 8.87165295f, 12.86953810f, 15.99760120f, 17.60612858f }, - { 19.96903649f, 23.88285926f, 22.32019685f, 21.76125456f }, - { 29.72013412f, 37.27671435f, 32.52194339f, 39.07266895f }, - { 28.55491327f, 44.81420118f, 42.30319257f, 49.83288655f }, - { 21.10664896f, 31.66030274f, 28.55491327f, 31.09611078f }, - { 20.24215670f, 22.52600345f, 25.92940848f, 31.40173602f }, - { 23.74093145f, 23.64866498f, 24.66303462f, 34.76059497f }, - { 18.11369152f, 20.79120253f, 23.46952883f, 24.02919660f }, - { 18.96256110f, 22.87210480f, 29.72013412f, 32.74590996f }, - { 18.72369955f, 25.33863874f, 26.22142295f, 26.35118177f }, - { 17.86940293f, 26.11018876f, 28.03673252f, 28.34295403f }, - { 21.27643145f, 24.66303462f, 28.03673252f, 34.76059497f }, - { 37.40908149f, 22.52600345f, 31.40173602f, 30.17891850f }, - { 19.30714042f, 34.76059497f, 32.24195100f, 33.75347224f }, - { 20.26613977f, 22.12462197f, 916761456.07631612f, 33.84504642f }, // bad fit - { 16.39974519f, 16.84140447f, 18.14299484f, 24.66303462f }, - { 15.05662094f, 15.90814866f, 22.32019685f, 30.28085308f }, - { 13.83125590f, 24.66303462f, 28.34295403f, 28.71032962f }, - { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f }, - { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f }, + { { 8.87165295f, 12.86953810f, 15.99760120f, 17.60612858f } }, + { { 8.87165295f, 12.86953810f, 15.99760120f, 17.60612858f } }, + { { 19.96903649f, 23.88285926f, 22.32019685f, 21.76125456f } }, + { { 29.72013412f, 37.27671435f, 32.52194339f, 39.07266895f } }, + { { 28.55491327f, 44.81420118f, 42.30319257f, 49.83288655f } }, + { { 21.10664896f, 31.66030274f, 28.55491327f, 31.09611078f } }, + { { 20.24215670f, 22.52600345f, 25.92940848f, 31.40173602f } }, + { { 23.74093145f, 23.64866498f, 24.66303462f, 34.76059497f } }, + { { 18.11369152f, 20.79120253f, 23.46952883f, 24.02919660f } }, + { { 18.96256110f, 22.87210480f, 29.72013412f, 32.74590996f } }, + { { 18.72369955f, 25.33863874f, 26.22142295f, 26.35118177f } }, + { { 17.86940293f, 26.11018876f, 28.03673252f, 28.34295403f } }, + { { 21.27643145f, 24.66303462f, 28.03673252f, 34.76059497f } }, + { { 37.40908149f, 22.52600345f, 31.40173602f, 30.17891850f } }, + { { 19.30714042f, 34.76059497f, 32.24195100f, 33.75347224f } }, + { { 20.26613977f, 22.12462197f, 916761456.07631612f, 33.84504642f } }, // bad fit + { { 16.39974519f, 16.84140447f, 18.14299484f, 24.66303462f } }, + { { 15.05662094f, 15.90814866f, 22.32019685f, 30.28085308f } }, + { { 13.83125590f, 24.66303462f, 28.34295403f, 28.71032962f } }, + { { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f } }, + { { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f } }, } }; app::pack::PackChannel::Subscription volt_sub{ "soc_volt" }; app::pack::PackChannel::Subscription temp_sub{ "soc_temp" }; -app::soc::SocStats soc {}; -app::pack::VoltStats volts {}; -app::pack::TempStats temps {}; +app::soc::SocStats soc_stats{}; +app::pack::VoltStats volt_stats{}; +app::pack::TempStats temp_stats{}; } // namespace namespace app::soc { -void init() { +void init() +{ app::pack::voltage_channel.subscribe(volt_sub); app::pack::temperature_channel.subscribe(temp_sub); - - //if there are intial soc values in sd card use that else use ocv lookup - //or maybe just take mean of the two idk + //later will need to add ts_current channel s + } -void update() { - while (const auto stats = volt_sub.pop(0)) volts = *stats; - while (const auto stats = temp_sub.pop(0)) temps = *stats; +void update() +{ + while (const auto stats = volt_sub.pop(0)) + volt_stats = *stats; + while (const auto stats = temp_sub.pop(0)) + temp_stats = *stats; - if (volts.updated_ms > soc.updated_ms || temps.updated_ms > soc.updated_ms) - calculate(volts, temps); + // The ekf step goes here. } -void broadcast() { - + +void broadcast() +{ + // The weakest cell sets what the pack can actually deliver. + app::can_tx::BMS_HvBatterySoc_set( + soc_stats.updated_ms != 0U ? static_cast(soc_stats.min.value * 100.0f) : 0U); } } // namespace app::soc diff --git a/firmware/hexray/BMS/src/app/app_soc.hpp b/firmware/hexray/BMS/src/app/app_soc.hpp index 3587b96a94..888099d9bb 100644 --- a/firmware/hexray/BMS/src/app/app_soc.hpp +++ b/firmware/hexray/BMS/src/app/app_soc.hpp @@ -1,5 +1,10 @@ #pragma once +#include "app_pack.hpp" +#include "io_adbms.hpp" + +#include + namespace app::soc { struct SocStats { @@ -10,6 +15,7 @@ struct SocStats { app::pack::CellFlags valid{}; }; +void init(); void update(); void broadcast(); } // namespace app::soc diff --git a/firmware/hexray/BMS/src/jobs.cpp b/firmware/hexray/BMS/src/jobs.cpp index 4d51912770..0055185865 100644 --- a/firmware/hexray/BMS/src/jobs.cpp +++ b/firmware/hexray/BMS/src/jobs.cpp @@ -18,6 +18,7 @@ #include "app_pack.hpp" #include "app_powerLimit.hpp" #include "app_precharge.hpp" +#include "app_soc.hpp" #include "app_states.hpp" #include "app_tractiveSystem.hpp" #include "app_charger.hpp" @@ -84,6 +85,7 @@ void jobs_init() app::pack::sequence::init(); app::pack::alerts::init(); app::pack::balancing::init(); + app::soc::init(); app::StateMachine::init(&app::states::init_state); app::can_tx::BMS_Heartbeat_set(true); @@ -92,6 +94,7 @@ void jobs_init() void jobs_run1Hz_tick() { app::StateMachine::tick1Hz(); + app::soc::broadcast(); io::can_tx::enqueue1HzMsgs(); } @@ -128,6 +131,8 @@ void jobs_run100Hz_tick() app::can_tx::BMS_ChargerConnectedType_set(io::charger::getConnectionStatus()); app::charger::broadcast(); + app::soc::update(); + const bool pack_fault = app::pack::alerts::tick(); bms_ok_latch.setCurrentStatus( pack_fault ? io::FaultLatch::FaultLatchState::FAULT : io::FaultLatch::FaultLatchState::OK); From 22b264e7e301df3eeaedd52a4c38f2eff7ad2818 Mon Sep 17 00:00:00 2001 From: Pranay Oza <105095960+pranay-o@users.noreply.github.com> Date: Thu, 10 Sep 2026 17:11:46 -0700 Subject: [PATCH 4/4] dik --- firmware/hexray/BMS/src/app/app_soc.cpp | 77 ++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/firmware/hexray/BMS/src/app/app_soc.cpp b/firmware/hexray/BMS/src/app/app_soc.cpp index f2c745c7b2..9c3a543123 100644 --- a/firmware/hexray/BMS/src/app/app_soc.cpp +++ b/firmware/hexray/BMS/src/app/app_soc.cpp @@ -1,12 +1,14 @@ #include "app_soc.hpp" #include "app_pack.hpp" #include "app_canTx.hpp" +#include "app_tractiveSystem.hpp" #include #include namespace { +constexpr size_t CELLS_IN_PARALLEL = 4; constexpr size_t P30B_SOC_N = 21U; constexpr size_t P30B_TEMP_N = 4U; using P30BTable = std::array, P30B_SOC_N>; @@ -223,12 +225,82 @@ constexpr P30BTable P30B_TAU1_CHG_S = { { { { 19.84500334f, 27.69980701f, 50.28894551f, 73.45802012f } }, } }; +struct Interp { + float soc_i; + float soc_f; + float temp_i + float temp_f; +}; + +struct SocState { + float v1 = 0.0f; + float p00 = 0; //P_SOC (need to come up with initial value) + float p01 = 0.0f; //P_SOC_V1 + float p11 = 0; //P_V1 (need to come up with initial value) +}; + app::pack::PackChannel::Subscription volt_sub{ "soc_volt" }; app::pack::PackChannel::Subscription temp_sub{ "soc_temp" }; app::soc::SocStats soc_stats{}; app::pack::VoltStats volt_stats{}; app::pack::TempStats temp_stats{}; +io::adbms::Cells soc_states{}; + + +float lookup(const P30BTable &table, const Interp &in) { +} + +void calculate(const app::pack::VoltStats &volts, const app::pack::TempStats &temps) { + const float dt_s = static_cast(volt_stats.updated_ms - soc_stats.updated_ms) * 1.0e-3f; + soc_stats.updated_ms = volt_stats.updated_ms; + + const float cell_current_a = -app::ts::getCurrent() / static_cast(CELLS_IN_PARALLEL); //prob should change the convention (+ for discharge instead of + for charge) change this shit in ts file + + const bool charging = cell_current_a < 0; + for (size_t seg = 0; seg < NUM_SEGMENTS; seg++) { + for (size_t cell = 0; cell < CELLS_PER_SEGMENT; cell++) { + if (!volts.valid[seg][cell]) + continue;// should soc value go invalid???? prob not + + const float temp_c = temps.valid[seg][cell] ? temps.temperatures[seg][cell] : 0; //what should be the invalid temp path + + SocState &soc_state = soc_states[seg][cell]; + + + + // this is for reset so it can intialize with ocv lookup + if (!soc_stats.valid[seg][cell]) { + soc_stats.soc[seg][cell] = + soc_stats.valid[seg][cell] = true; + soc_state = {}; + continue; + } + + const float r0 = charging ? lookup(P30B_R0_CHG_OHM, soc, temp_c) : lookup(P30B_R0_DIS_OH, soc, temp_c); + const float r1 = + const float tau_s = charging ? lookup(P30B_TAU1_CHG_S, soc, temp_c) : lookup(P30B_TAU1_DIS_S, soc, temp_c); + const float a = std::exp(-dt_s / tau_s); + + //Predict next state and covariance + soc_stats.soc[seg][cell] -= cell_current_a * dt_s / P30B_CAP_AS; + soc_state.v1 = a* soc_state.v1 + r1 * (1.0f - a) * cell_current_a; + soc_state.p00 += Q_SOC; // need to come up with this value + soc_state.p01 += a; + soc_state.p11 = a * a * soc_state.p11 + Q_V1; //need to come up with this value + + //Calculate innovation + const float innovation = volts.votlages[seg][cell] - (lookup(P30B_OCV_V, ocv, temp) - r0 * cell_current_a - soc_state.v1); + + + } + } +} + + +} + + } // namespace @@ -244,12 +316,13 @@ void init() void update() { - while (const auto stats = volt_sub.pop(0)) + while (const auto stats = volt_sub.pop(0)) volt_stats = *stats; while (const auto stats = temp_sub.pop(0)) temp_stats = *stats; - // The ekf step goes here. + if (volt_stats.updated_ms > soc_stats.updated_ms || temp_stats.updated_ms > soc_stats.updated_ms) + calculate(volt_stats, temp_stats); } void broadcast()