hitl_tester.test_cases.bms.test_2590_milprf_full
This file is a work in progress!
See: MIL-PRF-32383 (2590)
The following tests must pass to meet the BB-2590 requirements
3.5.3 Capacity tests
Test | Requirement | Test Method | Discharge Rate (A) | Minimum Capacity (Ah) Capacity | 3.5.3 | 4.7.2.3 | 2 | 9.8 Cycle life (224th cycle) | 3.5.4 | 4.7.2.4 | 2 | 9.3 High rate | 3.5.3 | 4.7.2.5 | 10 | 9.8 Low temperature | 3.5.3 | 4.7.2.7 | 2 | 8.9 High temperature | 3.5.3 | 4.7.2.8 | 2 | 9.8 Inrush current | 3.5.5 | 4.7.2.12 | See 3.5.5 | 9.7 Charge acceptance | 3.5.10.1 | 4.7.2.9 | 2 | 5.1 Retention of charge | 3.5.10.2 | 4.7.2.10 | 2 | 9.7 Pulse | 3.5.3 | 4.7.2.11 | See 4.7.2.11 | 19.5 Extreme low temperature | 3.6.1 | 4.7.3.2 | 2 | 8.6 Extreme high temperature | 3.6.1 | 4.7.3.3 | 2 | 9.8 Temperature shock (post- test) | 3.6.3 | 4.7.3.5 | 2 | 9.8 Mechanical shock (post-test) | 3.6.4 | 4.7.3.6 | 2 | 9.8 Vibration (during test) | 3.6.5 | 4.7.3.7 | 0.8 | 9.7 Battery storage life | 3.6.8 | 4.7.3.10 | 2 | 9.3 Overcharge/electric leakage (post-test) | 3.7.2.2 | 4.7.4.7 | 2 | 9.8 Short circuit protection (post-test) | 3.7.2.3 | 4.7.4.8 | 2 | 9.7
High temperature temporary cut off | 3.7.2.4 | 4.7.4.9 | 2 | 9.7
3.5.6.2 Charge enable test 3.7.2.5 High temperature permanent cut off 4.6.1 Constant potential, current limited. 4.6.3 Alternate charging. 4.7.4.4 Nail penetration, cell.
1""" 2This file is a work in progress! 3 4See: MIL-PRF-32383 (2590) 5 6The following tests must pass to meet the BB-2590 requirements 7 83.5.3 Capacity tests 9--------------------------------------------------------------------------------------------------------------------- 10Test | Requirement | Test Method | Discharge Rate (A) | Minimum Capacity (Ah) 11Capacity | 3.5.3 | 4.7.2.3 | 2 | 9.8 12Cycle life (224th cycle) | 3.5.4 | 4.7.2.4 | 2 | 9.3 13High rate | 3.5.3 | 4.7.2.5 | 10 | 9.8 14Low temperature | 3.5.3 | 4.7.2.7 | 2 | 8.9 15High temperature | 3.5.3 | 4.7.2.8 | 2 | 9.8 16Inrush current | 3.5.5 | 4.7.2.12 | See 3.5.5 | 9.7 17Charge acceptance | 3.5.10.1 | 4.7.2.9 | 2 | 5.1 18Retention of charge | 3.5.10.2 | 4.7.2.10 | 2 | 9.7 19Pulse | 3.5.3 | 4.7.2.11 | See 4.7.2.11 | 19.5 20Extreme low temperature | 3.6.1 | 4.7.3.2 | 2 | 8.6 21Extreme high temperature | 3.6.1 | 4.7.3.3 | 2 | 9.8 22Temperature shock (post- test) | 3.6.3 | 4.7.3.5 | 2 | 9.8 23Mechanical shock (post-test) | 3.6.4 | 4.7.3.6 | 2 | 9.8 24Vibration (during test) | 3.6.5 | 4.7.3.7 | 0.8 | 9.7 25Battery storage life | 3.6.8 | 4.7.3.10 | 2 | 9.3 26Overcharge/electric leakage (post-test) | 3.7.2.2 | 4.7.4.7 | 2 | 9.8 27Short circuit protection (post-test) | 3.7.2.3 | 4.7.4.8 | 2 | 9.7 28High temperature temporary cut off | 3.7.2.4 | 4.7.4.9 | 2 | 9.7 29--------------------------------------------------------------------------------------------------------------------- 30 313.5.6.2 Charge enable test 323.7.2.5 High temperature permanent cut off 334.6.1 Constant potential, current limited. 344.6.3 Alternate charging. 354.7.4.4 Nail penetration, cell. 36""" 37 38from __future__ import annotations 39 40from time import sleep 41 42import pytest 43 44from hitl_tester.modules.bms.bms_hw import BMSHardware, UserInterrupt 45from hitl_tester.modules.bms.thermal_chamber import ThermalChamber 46from hitl_tester.modules.bms_types import DischargeType 47from hitl_tester.modules.logger import logger 48 49bms_hardware = BMSHardware(pytest.flags) # type: ignore[arg-type] 50bms_hardware.init() 51 52 53# Capacity tests 54 55MAX_THERMAL_CHAMBER_TIME = 30 * 60 56CHARGE_CURRENT_A = 3.0 57 58 59def standard_charge(): 60 """ 61 Charge batteries in accordance with 4.3.1 for not greater than three hours. 62 4.3.1 = 23 ± 5°C (73.4°F) ambient pressure/relative humidity, with 2+ hours between charge and discharge. 63 """ 64 bms_hardware.voltage = 33.6 65 bms_hardware.ov_protection = 34 66 bms_hardware.current = CHARGE_CURRENT_A 67 bms_hardware.termination_current = 0.100 68 bms_hardware.max_time = 3 * 3600 # not greater than three hours 69 bms_hardware.sample_interval = 10 70 bms_hardware.minimum_readings = 3 71 72 # Run the Charge cycle 73 bms_hardware.run_li_charge_cycle() 74 75 76def standard_rest(seconds: int = 2 * 3600): 77 """Stabilize the batteries for 2+ hours.""" 78 bms_hardware.max_time = seconds 79 bms_hardware.sample_interval = 60 80 bms_hardware.run_resting_cycle() 81 82 83def standard_charge_rest(): 84 """Charge batteries in accordance with 4.3.1 for not greater than three hours with 2+ hours rest.""" 85 standard_charge() 86 standard_rest() 87 88 89def standard_discharge(current: float = 2, voltage_cutoff: int = 20) -> float: 90 """Discharge at 2A unitl 20V.""" 91 bms_hardware.max_time = 8 * 3600 # 8 hours 92 bms_hardware.sample_interval = 10 93 bms_hardware.discharge_type = DischargeType.CONSTANT_CURRENT 94 bms_hardware.current = current 95 bms_hardware.uv_protection = voltage_cutoff - 1 96 bms_hardware.voltage = voltage_cutoff 97 return float(bms_hardware.run_discharge_cycle()) 98 99 100def set_temperature(temp: float | None = None): 101 assert isinstance(bms_hardware.thermal_chamber, ThermalChamber) 102 if temp is None: 103 bms_hardware.thermal_chamber.set_room_temperature() 104 else: 105 bms_hardware.thermal_chamber.internal_units = "C" 106 bms_hardware.thermal_chamber.set_point_temperature = -20.0 107 bms_hardware.thermal_chamber.block_until_set_point_reached(MAX_THERMAL_CHAMBER_TIME) 108 109 110def test_capacity_discharge(): 111 """Regular discharge at 2A. Permitted up to 3 cycles to pass.""" 112 standard_charge_rest() 113 capacity = standard_discharge() 114 assert capacity >= 9.8 # confirm capacity meets minimums 115 116 117def test_cycle(): 118 """Cycle the battery 224 times.""" 119 capacity = 0.0 # Appease linter 120 for i in range(8): 121 for j in range(26): # Cycle 1-26: charge, rest 5+ minutes, discharge @ 2A, rest 5+ minutes 122 logger.write_info_to_report(f"Starting cycle {i*28 + j + 1} / 224") 123 standard_charge() 124 standard_rest(5 * 60) # Stabilize the batteries for 5+ minutes 125 standard_discharge() 126 standard_rest(5 * 60) # Stabilize the batteries for 5+ minutes 127 128 # Cycle 27: charge, rest 4+ hours, discharge @ 2A, rest 4+ hours 129 logger.write_info_to_report(f"Starting cycle {i*28 + 27} / 224") 130 standard_charge() 131 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 132 standard_discharge() 133 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 134 135 # Cycle 28: charge, electric leakage test, rest 4+ hours, discharge @ 2A, record capacity. 136 logger.write_info_to_report(f"Starting cycle {i*28 + 28} / 224") 137 standard_charge() 138 logger.write_info_to_report("Pausing. Perform Electric leakage test (4.7.4.7d), then press CTRL-Z to continue.") 139 UserInterrupt.interrupt_requested.clear() 140 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 141 capacity = standard_discharge() 142 143 assert capacity >= 9.3 # confirm capacity meets minimums 144 145 146def test_high_rate_discharge(): 147 """Discharge at 10A.""" 148 standard_charge_rest() 149 capacity = standard_discharge(current=10) 150 assert capacity >= 9.8 # confirm capacity meets minimums 151 152 153def test_low_temperature_discharge(): 154 """Discharge at -20C.""" 155 standard_charge() 156 set_temperature(-20.0) 157 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 158 capacity = standard_discharge() 159 set_temperature() 160 assert capacity >= 8.9 # confirm capacity meets minimums 161 162 163def test_high_temperature_discharge(): 164 """Discharge at 50C.""" 165 standard_charge() 166 set_temperature(50.0) 167 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 168 capacity = standard_discharge() 169 set_temperature() 170 assert capacity >= 9.8 # confirm capacity meets minimums 171 172 173# Inrush Current (9.7 Ah) 174# - discharge at 5A for 5 minutes 175# - 3.5.5 lists the discharge currents for 1 second 176# - discharge at 10A for 4:59 minutes 177# - discharge at 5A for 5 minutes 178# - 3.5.5 lists the discharge currents for 1 second 179# - discharge at 10A for 4:59 minutes 180# - discharge at 5A until cutoff 181# - discharge as above 182 183 184def thread_inrush_current(): 185 delays = (10, 10, 10, 20, 40, 75, 150, 250, 275, 150, 299000) 186 # use nanosleep 187 for i in range(2): 188 bms_hardware.load.amps = 5 189 # nanosleep 5 minutes 190 bms_hardware.load.amps = 60 191 # 0.2 ms 192 bms_hardware.load.amps = 22.5 193 # sleep 9.8 ms 194 195 bms_hardware.load.amps = 20 196 for delay in delays: 197 # sleep delay 198 bms_hardware.load.amps -= 1 199 200 201def test_inrush_current(): 202 """""" 203 standard_charge_rest() 204 # FIXME(JA): create thread 205 capacity = standard_discharge(current=5) 206 # FIXME(JA): kill thread 207 assert capacity >= 9.7 # confirm capacity meets minimums 208 209 210def test_charge_acceptance(): 211 """""" 212 standard_discharge() 213 for temp in (-20.0, 50.0): 214 set_temperature(temp) 215 standard_rest(4 * 3600) 216 standard_charge_rest() 217 capacity = standard_discharge() 218 assert capacity >= 5.1 # confirm capacity meets minimums 219 220 221def retention_of_charge(): 222 """""" 223 standard_charge_rest() 224 set_temperature(50.0) 225 standard_rest(7 * 24 * 3600) 226 set_temperature() 227 standard_rest() 228 capacity = standard_discharge() 229 assert capacity >= 9.7 # confirm capacity meets minimums 230 231 232def thread_pulse_discharge(): 233 """Battery sections connected in parallel, 36 A for 5 seconds followed by 25 seconds off.""" 234 while True: # FIXME(JA): use threading event 235 bms_hardware.load.amps = 36 236 sleep(5) 237 bms_hardware.load.disable() 238 sleep(25) 239 bms_hardware.load.enable() 240 241 242def test_pulse_discharge(): 243 # - cutoff = 10V (parallel mode) 244 standard_charge_rest() 245 # FIXME(JA): create thread 246 capacity = standard_discharge(current=36, voltage_cutoff=10) 247 # FIXME(JA): kill thread 248 assert capacity >= 19.5 # confirm capacity meets minimums 249 250 251def test_extreme_low_temperature_discharge(): 252 """Discharge at -20C.""" 253 standard_charge() 254 set_temperature(-30.0) 255 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 256 capacity = standard_discharge() 257 set_temperature() 258 assert capacity >= 8.6 # confirm capacity meets minimums 259 260 261def test_extreme_high_temperature_discharge(): 262 """Discharge at 50C.""" 263 standard_charge() 264 set_temperature(55.0) 265 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 266 capacity = standard_discharge() 267 set_temperature() 268 assert capacity >= 9.8 # confirm capacity meets minimums 269 270 271""" 272Temperature shock (post-test) (9.8 Ah) 273 - charge + rest (may use 4.6.3) 274 - method 503 Procedure 1-B of MIL-STD-810 (75C+ -59C-) (2+ hours at either end, diurnal cycling not required) 275 - Capacity discharge test 276 277Mechanical shock (post-test) (9.8 Ah) 278 - Capacity discharge test 279 280Vibration (during test) (9.7 Ah) 281 - charge + rest (may use 4.6.3) 282 - discharge @ 0.8A 283 284Battery storage life (9.3 Ah) 285 a. discharge @ 1A (0.5C, C=2A) 286 b. charge @ 100+ mA until 220- mAh 287 c. store @ 60C +- 5C, 85%+ relative humidity for 622+ hours (~26 days) 288 d. rest at 23 ± 5°C, normal humidity for 2+ hours 289 e. charge + rest (may use 4.6.3) 290 f. electric leak test 291 g. discharge @ 2A 292 - repeat efg for two more cycles (3 charge/discharge) 293 294Overcharge/electric leakage (post-test) (differs from actual) >>>>>>>>>>>>>>>> 295 - Charge in parallel mode at 4 A with a charge voltage limit of 40 V. 296 - discharge @ 2A = 9.8 Ah 297 298Short circuit protection (post-test) (9.7 Ah) 299 - charge + rest (may use 4.6.3) 300 - measure OCV 301 - short for 1 hour 302 - measure OCV 303 - rest for 2+ hours 304 - charge + rest (may use 4.6.3) 305 - discharge @ 2A 306 307High temperature temporary cut off (9.7 Ah) 308 - charge + rest (may use 4.6.3) 309 a. store @ 75C +- 5C for 2+ hours 310 b. measure voltage 311 c. wait for it to cool to 40C +0/-5C 312 d. measure voltage 313 - repeat a-d five times (total 6) 314 - Capacity discharge test 315""" # pylint: disable=all 316 317# Other tests 318# 3.5.6.2 Charge enable test 319# 3.7.2.5 High temperature permanent cut off 320# 4.6.1 Constant potential, current limited. 321# 4.6.3 Alternate charging. 322# 4.7.4.4 Nail penetration, cell. 323 324# cell tests pg 21
60def standard_charge(): 61 """ 62 Charge batteries in accordance with 4.3.1 for not greater than three hours. 63 4.3.1 = 23 ± 5°C (73.4°F) ambient pressure/relative humidity, with 2+ hours between charge and discharge. 64 """ 65 bms_hardware.voltage = 33.6 66 bms_hardware.ov_protection = 34 67 bms_hardware.current = CHARGE_CURRENT_A 68 bms_hardware.termination_current = 0.100 69 bms_hardware.max_time = 3 * 3600 # not greater than three hours 70 bms_hardware.sample_interval = 10 71 bms_hardware.minimum_readings = 3 72 73 # Run the Charge cycle 74 bms_hardware.run_li_charge_cycle()
Charge batteries in accordance with 4.3.1 for not greater than three hours. 4.3.1 = 23 ± 5°C (73.4°F) ambient pressure/relative humidity, with 2+ hours between charge and discharge.
77def standard_rest(seconds: int = 2 * 3600): 78 """Stabilize the batteries for 2+ hours.""" 79 bms_hardware.max_time = seconds 80 bms_hardware.sample_interval = 60 81 bms_hardware.run_resting_cycle()
Stabilize the batteries for 2+ hours.
84def standard_charge_rest(): 85 """Charge batteries in accordance with 4.3.1 for not greater than three hours with 2+ hours rest.""" 86 standard_charge() 87 standard_rest()
Charge batteries in accordance with 4.3.1 for not greater than three hours with 2+ hours rest.
90def standard_discharge(current: float = 2, voltage_cutoff: int = 20) -> float: 91 """Discharge at 2A unitl 20V.""" 92 bms_hardware.max_time = 8 * 3600 # 8 hours 93 bms_hardware.sample_interval = 10 94 bms_hardware.discharge_type = DischargeType.CONSTANT_CURRENT 95 bms_hardware.current = current 96 bms_hardware.uv_protection = voltage_cutoff - 1 97 bms_hardware.voltage = voltage_cutoff 98 return float(bms_hardware.run_discharge_cycle())
Discharge at 2A unitl 20V.
101def set_temperature(temp: float | None = None): 102 assert isinstance(bms_hardware.thermal_chamber, ThermalChamber) 103 if temp is None: 104 bms_hardware.thermal_chamber.set_room_temperature() 105 else: 106 bms_hardware.thermal_chamber.internal_units = "C" 107 bms_hardware.thermal_chamber.set_point_temperature = -20.0 108 bms_hardware.thermal_chamber.block_until_set_point_reached(MAX_THERMAL_CHAMBER_TIME)
111def test_capacity_discharge(): 112 """Regular discharge at 2A. Permitted up to 3 cycles to pass.""" 113 standard_charge_rest() 114 capacity = standard_discharge() 115 assert capacity >= 9.8 # confirm capacity meets minimums
Regular discharge at 2A. Permitted up to 3 cycles to pass.
118def test_cycle(): 119 """Cycle the battery 224 times.""" 120 capacity = 0.0 # Appease linter 121 for i in range(8): 122 for j in range(26): # Cycle 1-26: charge, rest 5+ minutes, discharge @ 2A, rest 5+ minutes 123 logger.write_info_to_report(f"Starting cycle {i*28 + j + 1} / 224") 124 standard_charge() 125 standard_rest(5 * 60) # Stabilize the batteries for 5+ minutes 126 standard_discharge() 127 standard_rest(5 * 60) # Stabilize the batteries for 5+ minutes 128 129 # Cycle 27: charge, rest 4+ hours, discharge @ 2A, rest 4+ hours 130 logger.write_info_to_report(f"Starting cycle {i*28 + 27} / 224") 131 standard_charge() 132 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 133 standard_discharge() 134 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 135 136 # Cycle 28: charge, electric leakage test, rest 4+ hours, discharge @ 2A, record capacity. 137 logger.write_info_to_report(f"Starting cycle {i*28 + 28} / 224") 138 standard_charge() 139 logger.write_info_to_report("Pausing. Perform Electric leakage test (4.7.4.7d), then press CTRL-Z to continue.") 140 UserInterrupt.interrupt_requested.clear() 141 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 142 capacity = standard_discharge() 143 144 assert capacity >= 9.3 # confirm capacity meets minimums
Cycle the battery 224 times.
147def test_high_rate_discharge(): 148 """Discharge at 10A.""" 149 standard_charge_rest() 150 capacity = standard_discharge(current=10) 151 assert capacity >= 9.8 # confirm capacity meets minimums
Discharge at 10A.
154def test_low_temperature_discharge(): 155 """Discharge at -20C.""" 156 standard_charge() 157 set_temperature(-20.0) 158 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 159 capacity = standard_discharge() 160 set_temperature() 161 assert capacity >= 8.9 # confirm capacity meets minimums
Discharge at -20C.
164def test_high_temperature_discharge(): 165 """Discharge at 50C.""" 166 standard_charge() 167 set_temperature(50.0) 168 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 169 capacity = standard_discharge() 170 set_temperature() 171 assert capacity >= 9.8 # confirm capacity meets minimums
Discharge at 50C.
185def thread_inrush_current(): 186 delays = (10, 10, 10, 20, 40, 75, 150, 250, 275, 150, 299000) 187 # use nanosleep 188 for i in range(2): 189 bms_hardware.load.amps = 5 190 # nanosleep 5 minutes 191 bms_hardware.load.amps = 60 192 # 0.2 ms 193 bms_hardware.load.amps = 22.5 194 # sleep 9.8 ms 195 196 bms_hardware.load.amps = 20 197 for delay in delays: 198 # sleep delay 199 bms_hardware.load.amps -= 1
233def thread_pulse_discharge(): 234 """Battery sections connected in parallel, 36 A for 5 seconds followed by 25 seconds off.""" 235 while True: # FIXME(JA): use threading event 236 bms_hardware.load.amps = 36 237 sleep(5) 238 bms_hardware.load.disable() 239 sleep(25) 240 bms_hardware.load.enable()
Battery sections connected in parallel, 36 A for 5 seconds followed by 25 seconds off.
252def test_extreme_low_temperature_discharge(): 253 """Discharge at -20C.""" 254 standard_charge() 255 set_temperature(-30.0) 256 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 257 capacity = standard_discharge() 258 set_temperature() 259 assert capacity >= 8.6 # confirm capacity meets minimums
Discharge at -20C.
262def test_extreme_high_temperature_discharge(): 263 """Discharge at 50C.""" 264 standard_charge() 265 set_temperature(55.0) 266 standard_rest(4 * 3600) # Stabilize the batteries for 4+ hours 267 capacity = standard_discharge() 268 set_temperature() 269 assert capacity >= 9.8 # confirm capacity meets minimums
Discharge at 50C.