def test_batterystateful_model_change_chemistry(): model = battstfl.default("leadacid") original_capacity = model.ParamsPack.nominal_energy BatteryTools.battery_model_change_chemistry(model, 'nmcgraphite') params_new = battstfl.default('nmcgraphite').export() cell_params = params_new['ParamsCell'] pack_params = params_new['ParamsPack'] assert (model.value('nominal_energy') == pytest.approx( original_capacity, 0.1)) assert (model.ParamsCell.Vnom_default == cell_params['Vnom_default']) assert (model.ParamsPack.Cp == pack_params['Cp'])
def chem_batterystateful(model: BattStfl.BatteryStateful, chem): """ Helper function for battery_model_change_chemistry """ if type(model) != BattStfl.BatteryStateful: raise TypeError chem = chem.lower() if chem != 'LeadAcid' and chem != 'lfpgraphite' and chem != 'nmcgraphite': raise NotImplementedError if chem == 'leadacid': model.ParamsCell.chem = 0 else: model.ParamsCell.chem = 1 original_capacity = model.ParamsPack.nominal_energy original_voltage = model.ParamsPack.nominal_voltage params_dict = BattStfl.default(chem).export() for group in ('ParamsCell', 'ParamsPack'): for k, v in params_dict[group].items(): model.value(k, v) battery_model_sizing(model, -1, original_capacity, original_voltage)
def __init__(self, site: SiteInfo, battery_config: dict, chemistry: str = 'lfpgraphite', system_voltage_volts: float = 500): """ Battery Storage class based on PySAM's BatteryStateful Model :param site: Power source site information (SiteInfo object) :param battery_config: Battery configuration with the following keys: #. ``system_capacity_kwh``: float, Battery energy capacity [kWh] #. ``system_capacity_kw``: float, Battery rated power capacity [kW] :param chemistry: Battery storage chemistry, options include: #. ``LFPGraphite``: Lithium Iron Phosphate (Lithium Ion) #. ``LMOLTO``: LMO/Lithium Titanate (Lithium Ion) #. ``LeadAcid``: Lead Acid #. ``NMCGraphite``: Nickel Manganese Cobalt Oxide (Lithium Ion) :param system_voltage_volts: Battery system voltage [VDC] """ for key in ('system_capacity_kwh', 'system_capacity_kw'): if key not in battery_config.keys(): raise ValueError system_model = BatteryModel.default(chemistry) financial_model = Singleowner.from_existing(system_model, "StandaloneBatterySingleOwner") super().__init__("Battery", site, system_model, financial_model) self.Outputs = BatteryOutputs(n_timesteps=site.n_timesteps) self.system_capacity_kw: float = battery_config['system_capacity_kw'] self.chemistry = chemistry BatteryTools.battery_model_sizing(self._system_model, battery_config['system_capacity_kw'], battery_config['system_capacity_kwh'], system_voltage_volts, module_specs=Battery.module_specs) self._system_model.ParamsPack.h = 20 self._system_model.ParamsPack.Cp = 900 self._system_model.ParamsCell.resistance = 0.001 self._system_model.ParamsCell.C_rate = battery_config['system_capacity_kw'] / battery_config['system_capacity_kwh'] # Minimum set of parameters to set to get statefulBattery to work self._system_model.value("control_mode", 0.0) self._system_model.value("input_current", 0.0) self._system_model.value("dt_hr", 1.0) self._system_model.value("minimum_SOC", 10.0) self._system_model.value("maximum_SOC", 90.0) self._system_model.value("initial_SOC", 10.0) self._dispatch = None logger.info("Initialized battery with parameters and state {}".format(self._system_model.export()))
def test_battery_model_change_chemistry(): model = batt.default("GenericBatterySingleOwner") original_capacity = model.value('batt_computed_bank_capacity') original_power = model.BatterySystem.batt_power_discharge_max_kwac BatteryTools.battery_model_change_chemistry(model, 'leadacid') params_new = battstfl.default('leadacid').export() cell_params = params_new['ParamsCell'] pack_params = params_new['ParamsPack'] assert (model.value('batt_computed_bank_capacity') == pytest.approx( original_capacity, 0.1)) assert (model.value('batt_power_discharge_max_kwac') == pytest.approx( original_power, 0.1)) assert (model.BatteryCell.batt_chem == cell_params['chem']) assert (model.BatteryCell.batt_calendar_choice == cell_params['calendar_choice']) assert (model.BatteryCell.batt_Vnom_default == cell_params['Vnom_default']) assert ( model.BatteryCell.LeadAcid_q10_computed == cell_params['leadacid_q10']) assert (model.BatteryCell.batt_Cp == pack_params['Cp']) BatteryTools.battery_model_change_chemistry(model, 'nmcgraphite') params_new = battstfl.default('nmcgraphite').export() cell_params = params_new['ParamsCell'] pack_params = params_new['ParamsPack'] assert (model.value('batt_computed_bank_capacity') == pytest.approx( original_capacity, 0.1)) assert (model.value('batt_power_discharge_max_kwac') == pytest.approx( original_power, 0.1)) assert (model.BatteryCell.batt_C_rate == cell_params['C_rate']) assert (model.BatteryCell.batt_calendar_choice == cell_params['calendar_choice']) assert (model.BatteryCell.batt_Vexp == cell_params['Vexp']) assert (model.BatteryCell.batt_Cp == pack_params['Cp'])
def test_stateful(): b = bt.default("NMCGraphite") b.Controls.control_mode = 1 b.Controls.dt_hr = 1 b.ParamsCell.minimum_SOC = 10 b.ParamsCell.maximum_SOC = 90 b.ParamsCell.initial_SOC = 50 b.Controls.input_power = 0 b.setup() assert (b.StatePack.SOC == approx(50)) b.Controls.input_power = 0.5 b.execute(0) assert (b.StatePack.SOC == approx(44.811, 1e-2))
def test_stateful_lmolto(): b = bt.default("LMOLTO") b.Controls.control_mode = 1 b.Controls.dt_hr = 1 b.ParamsCell.minimum_SOC = 10 b.ParamsCell.maximum_SOC = 90 b.ParamsCell.initial_SOC = 50 b.Controls.input_power = 0 b.setup() assert (b.StatePack.SOC == approx(50)) b.Controls.input_power = 0.5 b.execute(0) assert (b.StatePack.SOC == approx(45.216, 1e-2))
def chem_battery(model: Batt.Battery, chem): """ Helper function for battery_model_change_chemistry """ if type(model) != Batt.Battery: raise TypeError chem = chem.lower() if chem != 'leadacid' and chem != 'lfpgraphite' and chem != 'nmcgraphite': raise NotImplementedError if chem == 'leadacid': model.BatteryCell.batt_chem = 0 else: model.BatteryCell.batt_chem = 1 original_capacity = model.value('batt_computed_bank_capacity') original_voltage = model.BatteryCell.batt_Vnom_default * model.BatterySystem.batt_computed_series if model.BatterySystem.batt_ac_or_dc: original_power = model.BatterySystem.batt_power_discharge_max_kwac else: original_power = model.BatterySystem.batt_power_discharge_max_kwdc params_dict = BattStfl.default(chem).export() for group in ('ParamsCell', 'ParamsPack'): for k, v in params_dict[group].items(): if k == 'nominal_voltage' or k == "T_room_init": continue elif k == 'cycling_matrix': k = 'batt_lifetime_matrix' elif 'leadacid' in k: k = 'LeadAcid' + k[8:] if 'tn' not in k: k += '_computed' elif k == 'h': k = 'batt_h_to_ambient' elif k == 'nominal_energy': k = 'batt_computed_bank_capacity' elif k == 'cap_vs_temp': pass else: k = 'batt_' + k model.value(k, v) battery_model_sizing(model, original_power, original_capacity, original_voltage)