Skip to content

Commit

Permalink
Refactor max power and current to be functions instead of calculating…
Browse files Browse the repository at this point in the history
… in each individual location
  • Loading branch information
brtietz committed Nov 8, 2024
1 parent bd44be4 commit e8fd9ed
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 51 deletions.
56 changes: 27 additions & 29 deletions shared/lib_battery_dispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ dispatch_t::dispatch_t(battery_t* Battery, double dt_hour, double SOC_min, doubl
std::unique_ptr<BatteryPowerFlow> tmp(new BatteryPowerFlow(dt_hour));
m_batteryPowerFlow = std::move(tmp);
m_batteryPower = m_batteryPowerFlow->getBatteryPower();
m_batteryPower->currentChargeMax = Ic_max;
m_batteryPower->currentDischargeMax = Id_max;
m_batteryPower->setMaxChargeCurrent(Ic_max);
m_batteryPower->setMaxDischargeCurrent(Id_max);
m_batteryPower->stateOfChargeMax = SOC_max;
m_batteryPower->stateOfChargeMin = SOC_min;
m_batteryPower->depthOfDischargeMax = SOC_max - SOC_min;
m_batteryPower->powerBatteryChargeMaxDC = Pc_max_kwdc;
m_batteryPower->powerBatteryDischargeMaxDC = Pd_max_kwdc;
m_batteryPower->powerBatteryChargeMaxAC = Pc_max_kwac;
m_batteryPower->powerBatteryDischargeMaxAC = Pd_max_kwac;
m_batteryPower->setMaxDCChargePower(Pc_max_kwdc);
m_batteryPower->setMaxDCDischargePower(Pd_max_kwdc);
m_batteryPower->setMaxACChargePower(Pc_max_kwac);
m_batteryPower->setMaxACDischargePower(Pd_max_kwac);
m_batteryPower->meterPosition = battMeterPosition;
m_batteryPower->powerInterconnectionLimit = interconnection_limit;
m_batteryPower->chargeOnlySystemExceedLoad = chargeOnlySystemExceedLoad;
Expand Down Expand Up @@ -331,7 +331,7 @@ bool dispatch_t::restrict_current(double& I)
{
if (I < 0)
{
double max_current_charge = (1 - m_batteryPower->adjustLosses) * m_batteryPower->currentChargeMax;
double max_current_charge = m_batteryPower->getMaxChargeCurrent();
if (std::abs(I) > max_current_charge)
{
I = -max_current_charge;
Expand All @@ -340,7 +340,7 @@ bool dispatch_t::restrict_current(double& I)
}
else
{
double max_current_discharge = (1 - m_batteryPower->adjustLosses) * m_batteryPower->currentDischargeMax;
double max_current_discharge = m_batteryPower->getMaxDischargeCurrent();
if (I > max_current_discharge)
{
I = max_current_discharge;
Expand All @@ -367,8 +367,8 @@ bool dispatch_t::restrict_power(double& I)
// charging
if (powerBattery < 0)
{
double max_charge_dc = (1 - m_batteryPower->adjustLosses) * m_batteryPower->powerBatteryChargeMaxDC;
double max_charge_ac = (1 - m_batteryPower->adjustLosses) * m_batteryPower->powerBatteryChargeMaxAC;
double max_charge_dc = m_batteryPower->getMaxDCChargePower();
double max_charge_ac = m_batteryPower->getMaxACChargePower();
if (std::abs(powerBattery) > max_charge_dc * (1 + low_tolerance))
{
dP = std::abs(max_charge_dc - std::abs(powerBattery));
Expand All @@ -388,9 +388,9 @@ bool dispatch_t::restrict_power(double& I)
}
// This could just be grid power since that's technically the only AC component. But, limit all to this
else if (m_batteryPower->connectionMode == m_batteryPower->DC_CONNECTED &&
std::abs(powerBatteryAC) > m_batteryPower->powerBatteryChargeMaxAC * (1 + low_tolerance))
std::abs(powerBatteryAC) > max_charge_ac * (1 + low_tolerance))
{
dP = std::abs(m_batteryPower->powerBatteryChargeMaxAC - std::abs(powerBatteryAC));
dP = std::abs(max_charge_ac - std::abs(powerBatteryAC));

// increase (reduce) charging magnitude by percentage
I -= (dP / std::abs(powerBattery)) * I;
Expand All @@ -399,11 +399,9 @@ bool dispatch_t::restrict_power(double& I)
}
else
{
double max_discharge_dc = (1 - m_batteryPower->adjustLosses) * m_batteryPower->powerBatteryDischargeMaxDC;
double max_discharge_ac = (1 - m_batteryPower->adjustLosses) * m_batteryPower->powerBatteryDischargeMaxAC;
if (m_batteryPower->connectionMode == m_batteryPower->DC_CONNECTED) {
max_discharge_ac *= (1 - m_batteryPower->acLossSystemAvailability);
}
double max_discharge_dc = m_batteryPower->getMaxDCDischargePower();
double max_discharge_ac = m_batteryPower->getMaxACDischargePower();

if (std::abs(powerBattery) > max_discharge_dc * (1 + low_tolerance))
{
dP = std::abs(max_discharge_dc - powerBattery);
Expand Down Expand Up @@ -492,9 +490,9 @@ void dispatch_t::dispatch_dc_outage_step(size_t lifetimeIndex) {
double pv_kwac = m_batteryPower->sharedInverter->powerAC_kW;

double max_discharge_kwdc = _Battery->calculate_max_discharge_kw();
max_discharge_kwdc = std::fmin(max_discharge_kwdc, m_batteryPower->powerBatteryDischargeMaxDC * (1 - m_batteryPower->adjustLosses));
max_discharge_kwdc = std::fmin(max_discharge_kwdc, m_batteryPower->getMaxDCDischargePower());
double max_charge_kwdc = _Battery->calculate_max_charge_kw();
max_charge_kwdc = std::fmax(max_charge_kwdc, -1.0 * m_batteryPower->powerBatteryChargeMaxDC * (1 - m_batteryPower->adjustLosses)); // Max, since charging numbers are negative
max_charge_kwdc = std::fmax(max_charge_kwdc, -1.0 * m_batteryPower->getMaxDCChargePower()); // Max, since charging numbers are negative
double batt_losses = _Battery->calculate_loss(max_charge_kwdc, lifetimeIndex);

// Setup battery iteration
Expand Down Expand Up @@ -564,11 +562,11 @@ void dispatch_t::dispatch_ac_outage_step(size_t lifetimeIndex) {
double ac_loss_percent = m_batteryPower->acLossSystemAvailability;

double max_discharge_kwdc = _Battery->calculate_max_discharge_kw();
max_discharge_kwdc = std::fmin(max_discharge_kwdc, m_batteryPower->powerBatteryDischargeMaxDC * (1 - m_batteryPower->adjustLosses));
max_discharge_kwdc = std::fmin(max_discharge_kwdc, m_batteryPower->getMaxDCDischargePower());
double max_discharge_kwac = max_discharge_kwdc * m_batteryPower->singlePointEfficiencyDCToDC;
max_discharge_kwac = std::fmin(max_discharge_kwac, m_batteryPower->powerBatteryDischargeMaxAC * (1 - m_batteryPower->adjustLosses));
max_discharge_kwac = std::fmin(max_discharge_kwac, m_batteryPower->getMaxACDischargePower());
double max_charge_kwdc = _Battery->calculate_max_charge_kw();
max_charge_kwdc = std::fmax(max_charge_kwdc, -1.0 * m_batteryPower->powerBatteryChargeMaxDC); // Max, since charging numbers are negative
max_charge_kwdc = std::fmax(max_charge_kwdc, -1.0 * m_batteryPower->getMaxDCChargePower()); // Max, since charging numbers are negative

if ((pv_kwac + fuel_cell_kwac) * (1 - ac_loss_percent) > crit_load_kwac) {
double remaining_kwdc = -((pv_kwac + fuel_cell_kwac) * (1 - ac_loss_percent) - crit_load_kwac) * m_batteryPower->singlePointEfficiencyACToDC;
Expand Down Expand Up @@ -778,10 +776,10 @@ bool dispatch_automatic_t::check_constraints(double& I, size_t count)
double I_initial = I;
double P_battery = I * _Battery->V() * util::watt_to_kilowatt;
double P_target = m_batteryPower->powerBatteryTarget;
double charge_max_dc = m_batteryPower->powerBatteryChargeMaxDC * (1 - m_batteryPower->adjustLosses);
double charge_max_ac = m_batteryPower->powerBatteryChargeMaxAC * (1 - m_batteryPower->adjustLosses);
double discharge_max_dc = m_batteryPower->powerBatteryDischargeMaxDC * (1 - m_batteryPower->adjustLosses);
double discharge_max_ac = m_batteryPower->powerBatteryDischargeMaxAC * (1 - m_batteryPower->adjustLosses);
double charge_max_dc = m_batteryPower->getMaxDCChargePower();
double charge_max_ac = m_batteryPower->getMaxACChargePower();
double discharge_max_dc = m_batteryPower->getMaxDCDischargePower();
double discharge_max_ac = m_batteryPower->getMaxACDischargePower();

// Common to automated behind the meter and front of meter
iterate = true;
Expand Down Expand Up @@ -814,7 +812,7 @@ bool dispatch_automatic_t::check_constraints(double& I, size_t count)
iterate = false;
}
// Don't charge more if would violate current or power charge limits
if (I > m_batteryPower->currentChargeMax - tolerance ||
if (I > m_batteryPower->getMaxChargeCurrent() - tolerance ||
std::abs(P_battery) > charge_max_dc - powerflow_tolerance ||
std::abs(m_batteryPower->powerBatteryAC) > charge_max_ac - powerflow_tolerance) {
iterate = false;
Expand All @@ -833,7 +831,7 @@ bool dispatch_automatic_t::check_constraints(double& I, size_t count)
iterate = false;
}
// Don't discharge more if would violate current or power discharge limits
if (I > m_batteryPower->currentDischargeMax - tolerance ||
if (I > m_batteryPower->getMaxDischargeCurrent() - tolerance ||
P_battery > discharge_max_dc - powerflow_tolerance ||
m_batteryPower->powerBatteryAC > discharge_max_ac - powerflow_tolerance) {
iterate = false;
Expand Down Expand Up @@ -871,7 +869,7 @@ bool dispatch_automatic_t::check_constraints(double& I, size_t count)
{
// Don't let PV export to grid if can still charge battery (increase charging) (unless following custom dispatch)
if (_mode != dispatch_t::CUSTOM_DISPATCH && m_batteryPower->powerSystemToGrid > powerflow_tolerance && m_batteryPower->canSystemCharge &&
_Battery->SOC() < m_batteryPower->stateOfChargeMax - tolerance && std::abs(I) < std::abs(m_batteryPower->currentChargeMax))
_Battery->SOC() < m_batteryPower->stateOfChargeMax - tolerance && std::abs(I) < std::abs(m_batteryPower->getMaxChargeCurrent()))
{
if (std::abs(m_batteryPower->powerBatteryAC) < powerflow_tolerance)
I -= (m_batteryPower->powerSystemToGrid / m_batteryPower->singlePointEfficiencyDCToAC * util::kilowatt_to_watt / _Battery->V());
Expand Down
2 changes: 1 addition & 1 deletion shared/lib_battery_dispatch_automatic_btm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void dispatch_automatic_behind_the_meter_t::setup_rate_forecast()
{

forecast_setup rate_setup(_steps_per_hour, _nyears);
rate_setup.setup(rate.get(), _P_pv_ac, _P_load_ac, m_batteryPower->powerBatteryDischargeMaxAC);
rate_setup.setup(rate.get(), _P_pv_ac, _P_load_ac, m_batteryPower->getMaxACChargePower());

rate_forecast = std::shared_ptr<UtilityRateForecast>(new UtilityRateForecast(rate.get(), _steps_per_hour, rate_setup.monthly_net_load, rate_setup.monthly_gen, rate_setup.monthly_gross_load, _nyears, rate_setup.monthly_peaks));
rate_forecast->initializeMonth(0, 0);
Expand Down
6 changes: 3 additions & 3 deletions shared/lib_battery_dispatch_automatic_fom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ dispatch_automatic_front_of_meter_t::dispatch_automatic_front_of_meter_t(

revenueToClipCharge = revenueToDischarge = revenueToGridCharge = revenueToPVCharge = 0;

discharge_hours = (size_t) std::ceil(_Battery->energy_max(m_batteryPower->stateOfChargeMax, m_batteryPower->stateOfChargeMin) / (m_batteryPower->powerBatteryDischargeMaxDC * (1 - m_batteryPower->adjustLosses))) - 1;
discharge_hours = (size_t) std::ceil(_Battery->energy_max(m_batteryPower->stateOfChargeMax, m_batteryPower->stateOfChargeMin) / (m_batteryPower->getMaxDCDischargePower())) - 1;

costToCycle();
omCost();
Expand Down Expand Up @@ -268,14 +268,14 @@ void dispatch_automatic_front_of_meter_t::update_dispatch(size_t year, size_t ho

/*! Computed revenue to charge from PV in each of next X hours ($/kWh)*/
size_t t_duration = static_cast<size_t>(ceilf( (float)
_Battery->energy_nominal() / (float) m_batteryPower->powerBatteryChargeMaxDC));
_Battery->energy_nominal() / (float) m_batteryPower->getMaxDCChargePower()));
size_t pv_hours_on;
double revenueToPVChargeMax = 0;
if (m_batteryPower->canSystemCharge) {
std::vector<double> revenueToPVChargeForecast;
for (size_t i = lifetimeIndex; i < lifetimeIndex + idx_lookahead && i < _P_pv_ac.size(); i++) {
// when considering grid charging, require PV output to exceed battery input capacity before accepting as a better option
bool system_on = _P_pv_ac[i] >= m_batteryPower->powerBatteryChargeMaxDC ? 1 : 0;
bool system_on = _P_pv_ac[i] >= m_batteryPower->getMaxDCChargePower() ? 1 : 0;
if (system_on) {
revenueToPVChargeForecast.push_back(system_on * (*max_ppa_cost * m_etaDischarge - _forecast_price_rt_series[i] / m_etaPVCharge - m_cycleCost - m_omCost));
}
Expand Down
4 changes: 2 additions & 2 deletions shared/lib_battery_dispatch_manual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ bool dispatch_manual_t::check_constraints(double &I, size_t count)
if (m_batteryPower->powerSystemToGrid > low_tolerance &&
m_batteryPower->canSystemCharge && // only do if battery is allowed to charge
_Battery->SOC() < m_batteryPower->stateOfChargeMax - 1.0 && // and battery SOC is less than max
std::abs(I) < std::abs(m_batteryPower->currentChargeMax) && // and battery current is less than max charge current
std::abs(m_batteryPower->powerBatteryDC) < (m_batteryPower->powerBatteryChargeMaxDC - 1.0) &&// and battery power is less than max charge power
std::abs(I) < std::abs(m_batteryPower->getMaxChargeCurrent()) && // and battery current is less than max charge current
std::abs(m_batteryPower->powerBatteryDC) < (m_batteryPower->getMaxDischargeCurrent() - 1.0) &&// and battery power is less than max charge power
I <= 0) // and battery was not discharging
{
double dI = 0;
Expand Down
2 changes: 1 addition & 1 deletion shared/lib_battery_dispatch_pvsmoothing_fom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ void dispatch_pvsmoothing_front_of_meter_t::update_dispatch(size_t year, size_t
ssc_number_t battery_soc = _Battery->SOC()/100.0;
ssc_number_t battery_energy = _Battery->energy_nominal();
ssc_number_t batt_half_round_trip_eff = sqrt(m_etaDischarge * m_etaPVCharge);
ssc_number_t battery_power = m_batteryPower->powerBatteryChargeMaxAC;
ssc_number_t battery_power = m_batteryPower->getMaxACChargePower();
ssc_number_t soc_min = _Battery->get_params().capacity->minimum_SOC * 0.01;
ssc_number_t soc_max = _Battery->get_params().capacity->maximum_SOC * 0.01;
// scale by nameplate per ERPI code
Expand Down
27 changes: 25 additions & 2 deletions shared/lib_battery_powerflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,29 @@ double BatteryPower::adjustForDCEfficiencies(double power, double loss) {
}
}

double BatteryPower::getMaxACChargePower() {
return (1 - adjustLosses) * powerBatteryChargeMaxAC;
}
double BatteryPower::getMaxACDischargePower() {
double max_discharge_ac = (1 - adjustLosses) * powerBatteryDischargeMaxAC;
if (connectionMode == DC_CONNECTED) {
max_discharge_ac *= (1 - acLossSystemAvailability);
}
return max_discharge_ac;
}
double BatteryPower::getMaxDCChargePower() {
return (1 - adjustLosses) * powerBatteryChargeMaxDC;
}
double BatteryPower::getMaxDCDischargePower() {
return (1 - adjustLosses) * powerBatteryDischargeMaxDC;
}
double BatteryPower::getMaxChargeCurrent() {
return (1 - adjustLosses) * currentChargeMax;
}
double BatteryPower::getMaxDischargeCurrent() {
return (1 - adjustLosses) * currentDischargeMax;
}

BatteryPowerFlow::BatteryPowerFlow(double dtHour)
{
std::unique_ptr<BatteryPower> tmp(new BatteryPower(dtHour));
Expand Down Expand Up @@ -282,7 +305,7 @@ void BatteryPowerFlow::initialize(double stateOfCharge, bool systemPriorityCharg
(m_BatteryPower->powerSystem < m_BatteryPower->powerLoad || !m_BatteryPower->dischargeOnlyLoadExceedSystem || m_BatteryPower->meterPosition == dispatch_t::FRONT))
{
// try to discharge full amount. Will only use what battery can provide
m_BatteryPower->powerBatteryDC = m_BatteryPower->powerBatteryDischargeMaxDC * (1 - m_BatteryPower->adjustLosses);
m_BatteryPower->powerBatteryDC = m_BatteryPower->getMaxDCDischargePower();
}
// Is there extra power from system
else if ((((m_BatteryPower->powerSystem > m_BatteryPower->powerLoad) || !m_BatteryPower->chargeOnlySystemExceedLoad) && m_BatteryPower->canSystemCharge) || m_BatteryPower->canGridCharge || m_BatteryPower->canClipCharge || m_BatteryPower->canCurtailCharge)
Expand Down Expand Up @@ -311,7 +334,7 @@ void BatteryPowerFlow::initialize(double stateOfCharge, bool systemPriorityCharg
}
// if we want to charge from grid in addition to, or without array, we can always charge at max power
if (m_BatteryPower->canGridCharge) {
m_BatteryPower->powerBatteryDC = -m_BatteryPower->powerBatteryChargeMaxDC;
m_BatteryPower->powerBatteryDC = -m_BatteryPower->getMaxDCChargePower();
}
}
m_BatteryPower->powerBatteryTarget = m_BatteryPower->powerBatteryDC;
Expand Down
43 changes: 35 additions & 8 deletions shared/lib_battery_powerflow.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,32 @@ struct BatteryPower
*/
double adjustForDCEfficiencies(double power, double loss);

double getMaxACChargePower();
double getMaxACDischargePower();
double getMaxDCChargePower();
double getMaxDCDischargePower();
double getMaxChargeCurrent();
double getMaxDischargeCurrent();

void setMaxACChargePower(double power) {
powerBatteryChargeMaxAC = power;
}
void setMaxACDischargePower(double power) {
powerBatteryDischargeMaxAC = power;
}
void setMaxDCChargePower(double power) {
powerBatteryChargeMaxDC = power;
}
void setMaxDCDischargePower(double power) {
powerBatteryDischargeMaxDC = power;
}
void setMaxChargeCurrent(double current) {
currentChargeMax = current;
}
void setMaxDischargeCurrent(double current) {
currentDischargeMax = current;
}

/// Copy the enumeration for AC/DC connected systems from ChargeController
enum CONNECTION { DC_CONNECTED, AC_CONNECTED };

Expand Down Expand Up @@ -182,10 +208,6 @@ struct BatteryPower
double powerFuelCellToLoad; ///< The power from the fuelcell to the load (kW)
double powerFuelCellToBattery; ///< The power from the fuelcell to the battery (kW)
double powerPVInverterDraw; ///< The power draw from the PV inverter (kW)
double powerBatteryChargeMaxDC; ///< The maximum sustained power the battery can charge (kWdc)
double powerBatteryDischargeMaxDC; ///< The maximum sustained power the battery can discharge (kWdc)
double powerBatteryChargeMaxAC; ///< The maximum sustained power the battery can charge (kWac)
double powerBatteryDischargeMaxAC; ///< The maximum sustained power the battery can discharge (kWac)
double powerSystemLoss; ///< The auxiliary power loss in the system (kW)
double powerConversionLoss; ///< The power loss due to conversions in the battery power electronics (kW)
double powerInterconnectionLimit; ///< The size of the grid interconnection (kW).
Expand Down Expand Up @@ -228,11 +250,16 @@ struct BatteryPower
double stateOfChargeMin; ///< The minimum state of charge (0-100)
double depthOfDischargeMax; ///< The maximum depth of discharge (0-100)

double currentChargeMax; ///< The maximum sustained current for charging [A]
double currentDischargeMax; ///< The maximum sustained current for discharging [A]


double tolerance; ///< A numerical tolerance. Below this value, zero out the power flow

private:
// These variables have values that require computation. Access through functions
double powerBatteryChargeMaxDC; ///< The maximum sustained power the battery can charge (kWdc)
double powerBatteryDischargeMaxDC; ///< The maximum sustained power the battery can discharge (kWdc)
double powerBatteryChargeMaxAC; ///< The maximum sustained power the battery can charge (kWac)
double powerBatteryDischargeMaxAC; ///< The maximum sustained power the battery can discharge (kWac)
double currentChargeMax; ///< The maximum sustained current for charging [A]
double currentDischargeMax; ///< The maximum sustained current for discharging [A]
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, DispatchAutoBTMGridCharging) {
batteryPower = dispatchAutoBTM->getBatteryPower();
batteryPower->connectionMode = ChargeController::AC_CONNECTED;

EXPECT_EQ(batteryPower->powerBatteryChargeMaxAC, 50);
EXPECT_EQ(batteryPower->getMaxACChargePower(), 50);

// TEST 1: Verify no grid charging since disallowed (_P_battery_use target is ~ -50)
dispatchAutoBTM->dispatch(0, 0, 0); // original target for battery power is
Expand Down
Loading

0 comments on commit e8fd9ed

Please sign in to comment.