From 99ade809fe8b2b3c2b629e832b5054850728adf7 Mon Sep 17 00:00:00 2001 From: Brian Mirletz Date: Thu, 28 Sep 2023 17:14:28 -0600 Subject: [PATCH 1/3] Work in progress commit. Loss accounting is improved but still leaves unsatisfactory unmet critical load. Requires philosophical discussion before proceeding - might make sense to feed back to dispatch current instead. --- shared/lib_battery_powerflow.cpp | 20 +++-- .../lib_battery_powerflow_test.cpp | 86 +++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/shared/lib_battery_powerflow.cpp b/shared/lib_battery_powerflow.cpp index dfca723ef..718aa40d0 100644 --- a/shared/lib_battery_powerflow.cpp +++ b/shared/lib_battery_powerflow.cpp @@ -483,11 +483,8 @@ void BatteryPowerFlow::calculateACConnected() P_fuelcell_to_grid_ac = 0; } + // Priliminary batt to grid for DC losses P_batt_to_grid_ac = P_battery_ac - P_system_loss_ac - P_batt_to_load_ac - P_batt_to_pv_inverter; - if (m_BatteryPower->isOutageStep && P_batt_to_grid_ac > tolerance) { - m_BatteryPower->powerBatteryDC = (P_battery_ac - P_batt_to_grid_ac) / m_BatteryPower->singlePointEfficiencyDCToAC; - return calculateACConnected(); - } P_fuelcell_to_grid_ac = P_fuelcell_ac - P_fuelcell_to_load_ac; P_batt_to_system_loss = P_system_loss_ac; @@ -503,6 +500,20 @@ void BatteryPowerFlow::calculateACConnected() // Compute total system output and grid power flow P_gen_ac = P_pv_ac + P_fuelcell_ac + P_inverter_draw_ac + P_battery_ac - P_system_loss_ac; + // Final batt to grid for outage accounting + if (P_battery_ac > 0) + { + double P_required_for_load = P_batt_to_load_ac; + if (ac_loss_percent_post_battery < 1) { // Account for possible divide by zero + P_required_for_load /= (1 - ac_loss_percent_post_battery); + } + P_batt_to_grid_ac = P_battery_ac * (1 - ac_loss_percent_post_battery) - P_system_loss_ac - P_required_for_load - P_batt_to_pv_inverter; + if (m_BatteryPower->isOutageStep && P_batt_to_grid_ac > tolerance) { + m_BatteryPower->powerBatteryDC = (P_battery_ac - P_batt_to_grid_ac) / m_BatteryPower->singlePointEfficiencyDCToAC; + return calculateACConnected(); + } + } + // Apply AC losses to powerflow - note that these are applied to gen later P_pv_to_batt_ac *= (1 - ac_loss_percent_post_battery); P_pv_to_load_ac *= (1 - ac_loss_percent_post_battery); @@ -511,7 +522,6 @@ void BatteryPowerFlow::calculateACConnected() P_grid_to_batt_ac *= (1 - ac_loss_percent_post_battery); P_grid_to_load_ac *= (1 - ac_loss_percent_post_battery); P_batt_to_load_ac *= (1 - ac_loss_percent_post_battery); - P_batt_to_grid_ac *= (1 - ac_loss_percent_post_battery); P_fuelcell_to_batt_ac *= (1 - ac_loss_percent_post_battery); P_fuelcell_to_load_ac *= (1 - ac_loss_percent_post_battery); P_fuelcell_to_grid_ac *= (1 - ac_loss_percent_post_battery); diff --git a/test/shared_test/lib_battery_powerflow_test.cpp b/test/shared_test/lib_battery_powerflow_test.cpp index 4f4afe99e..8721b48b0 100644 --- a/test/shared_test/lib_battery_powerflow_test.cpp +++ b/test/shared_test/lib_battery_powerflow_test.cpp @@ -3055,6 +3055,47 @@ TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, AC_system_w_ac_losses) { gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); EXPECT_NEAR(m_batteryPower->powerLoad, 0, error); + + // Post batt loss affects meeting critical load + m_batteryPower->acLossPostBattery = 0.05; + m_batteryPower->acLossWiring = 0; + m_batteryPower->powerBatteryDC = 50; + m_batteryPower->isOutageStep = true; + m_batteryPower->powerCritLoad = 50; + m_batteryPower->powerLoad = 50; + m_batteryPowerFlow->calculate(); + + EXPECT_NEAR(m_batteryPower->powerBatteryAC, 48, error); + EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); + EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); + EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); + EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 45.6, error); + EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 4.4, error); + EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); + EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2, error); + EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); + EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); + + // Increasing batt power allows meeting critical load + m_batteryPower->acLossPostBattery = 0.05; + m_batteryPower->acLossWiring = 0; + m_batteryPower->powerBatteryDC = 60; + m_batteryPower->isOutageStep = true; + m_batteryPower->powerLoad = 50; + m_batteryPower->powerCritLoad = 50; + m_batteryPowerFlow->calculate(); + + EXPECT_NEAR(m_batteryPower->powerBatteryAC, 55.4, error); + EXPECT_NEAR(m_batteryPower->powerBatteryDC, 57.7, error); + EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); + EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); + EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); + EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 50.0, error); + EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 0.0, error); + EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); + EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.083, error); + EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); + EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); } TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, DC_system_w_ac_losses) { @@ -3259,4 +3300,49 @@ TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, DC_system_w_ac_losses) { EXPECT_NEAR(m_batteryPower->powerConversionLoss, 3.738, error); EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); EXPECT_NEAR(m_batteryPower->powerLoad, 0, error); + + m_batteryPower->acXfmrLoadLoss = 0.0; + m_batteryPower->acXfmrNoLoadLoss = 0.0; + + // Post batt loss affects meeting critical load + m_batteryPower->acLossPostBattery = 0.05; + m_batteryPower->acLossWiring = 0; + m_batteryPower->powerBatteryDC = 50; + m_batteryPower->isOutageStep = true; + m_batteryPower->powerCritLoad = 50; + m_batteryPower->powerLoad = 50; + m_batteryPowerFlow->calculate(); + + EXPECT_NEAR(m_batteryPower->powerBatteryAC, 46.26, error); + EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); + EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); + EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); + EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 43.947, error); + EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 6.053, error); + EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); + EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); + EXPECT_NEAR(m_batteryPower->powerConversionLoss, 3.738, error); + EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); + EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); + + // Increasing batt power allows meeting critical load + m_batteryPower->acLossPostBattery = 0.05; + m_batteryPower->acLossWiring = 0; + m_batteryPower->powerBatteryDC = 60; + m_batteryPower->isOutageStep = true; + m_batteryPower->powerLoad = 50; + m_batteryPower->powerCritLoad = 50; + m_batteryPowerFlow->calculate(); + + EXPECT_NEAR(m_batteryPower->powerBatteryAC, 52.63, error); + EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); + EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); + EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); + EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 50.0, error); + EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 0.0, error); + EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); + EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); + EXPECT_NEAR(m_batteryPower->powerConversionLoss, 3.99, error); + EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); + EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); } From 0c4da87151e7c639346da84bfdac60a09a1e713b Mon Sep 17 00:00:00 2001 From: Brian Mirletz Date: Mon, 2 Oct 2023 15:20:16 -0600 Subject: [PATCH 2/3] finalize powerflow loss accounting that allows the ac connected battery to deliver sufficient power to load --- shared/lib_battery_powerflow.cpp | 39 ++++++++++--------- .../lib_battery_powerflow_test.cpp | 4 +- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/shared/lib_battery_powerflow.cpp b/shared/lib_battery_powerflow.cpp index 718aa40d0..ab9a38f70 100644 --- a/shared/lib_battery_powerflow.cpp +++ b/shared/lib_battery_powerflow.cpp @@ -351,6 +351,11 @@ void BatteryPowerFlow::calculateACConnected() // Code simplification to remove redundancy for code that should use either critical load or actual load double calc_load_ac = (m_BatteryPower->isOutageStep ? P_crit_load_ac : P_load_ac); + double P_required_for_load = calc_load_ac; + + if (ac_loss_percent_post_battery < 1) { // Account for possible divide by zero + P_required_for_load /= (1 - ac_loss_percent_post_battery); + } // charging and idle if (P_battery_ac <= 0) @@ -365,11 +370,11 @@ void BatteryPowerFlow::calculateACConnected() if (m_BatteryPower->chargeOnlySystemExceedLoad) { P_pv_to_load_ac = P_pv_ac; - if (P_pv_to_load_ac > calc_load_ac) { - P_pv_to_load_ac = calc_load_ac; + if (P_pv_to_load_ac > P_required_for_load) { + P_pv_to_load_ac = P_required_for_load; } // Fuel cell goes to load next - P_fuelcell_to_load_ac = std::fmin(calc_load_ac - P_pv_to_load_ac, P_fuelcell_ac); + P_fuelcell_to_load_ac = std::fmin(P_required_for_load - P_pv_to_load_ac, P_fuelcell_ac); } // Excess PV can go to battery, if PV can cover charging losses @@ -398,11 +403,11 @@ void BatteryPowerFlow::calculateACConnected() P_pv_to_load_ac = P_pv_ac - P_pv_to_batt_ac; } - if (P_pv_to_load_ac > calc_load_ac) { - P_pv_to_load_ac = calc_load_ac; + if (P_pv_to_load_ac > P_required_for_load) { + P_pv_to_load_ac = P_required_for_load; } // Fuel cell goes to load next - P_fuelcell_to_load_ac = std::fmin(calc_load_ac - P_pv_to_load_ac, P_fuelcell_ac); + P_fuelcell_to_load_ac = std::fmin(P_required_for_load - P_pv_to_load_ac, P_fuelcell_ac); } // Fuelcell can also charge battery @@ -439,6 +444,7 @@ void BatteryPowerFlow::calculateACConnected() // discharging, not idle else { + // Test if battery is discharging erroneously if (!m_BatteryPower->canDischarge && P_battery_ac > 0) { P_batt_to_grid_ac = P_batt_to_load_ac = 0; @@ -448,9 +454,9 @@ void BatteryPowerFlow::calculateACConnected() P_pv_to_load_ac = P_pv_ac; // Excess PV production, no other component meets load - if (P_pv_ac >= calc_load_ac) + if (P_pv_ac >= P_required_for_load) { - P_pv_to_load_ac = calc_load_ac; + P_pv_to_load_ac = P_required_for_load; P_fuelcell_to_load_ac = 0; P_batt_to_load_ac = 0; @@ -459,14 +465,14 @@ void BatteryPowerFlow::calculateACConnected() P_fuelcell_to_grid_ac = P_fuelcell_ac; } else { - P_fuelcell_to_load_ac = std::fmin(P_fuelcell_ac, calc_load_ac - P_pv_to_load_ac); - P_batt_to_load_ac = std::fmin(P_battery_ac - P_system_loss_ac, calc_load_ac - P_pv_to_load_ac - P_fuelcell_to_load_ac); + P_fuelcell_to_load_ac = std::fmin(P_fuelcell_ac, P_required_for_load - P_pv_to_load_ac); + P_batt_to_load_ac = std::fmin(P_battery_ac - P_system_loss_ac, P_required_for_load - P_pv_to_load_ac - P_fuelcell_to_load_ac); } } else { - P_batt_to_load_ac = std::fmin(P_battery_ac, calc_load_ac); - P_fuelcell_to_load_ac = std::fmin(P_fuelcell_ac, calc_load_ac - P_batt_to_load_ac); - P_pv_to_load_ac = std::fmin(std::fmax(0, calc_load_ac - P_fuelcell_to_load_ac - P_batt_to_load_ac), P_pv_ac); + P_batt_to_load_ac = std::fmin(P_battery_ac, P_required_for_load); + P_fuelcell_to_load_ac = std::fmin(P_fuelcell_ac, P_required_for_load - P_batt_to_load_ac); + P_pv_to_load_ac = std::fmin(std::fmax(0, P_required_for_load - P_fuelcell_to_load_ac - P_batt_to_load_ac), P_pv_ac); P_pv_to_grid_ac = std::fmax(0, P_pv_ac - P_pv_to_load_ac); P_fuelcell_to_grid_ac = std::fmax(0, P_fuelcell_ac - P_fuelcell_to_load_ac); } @@ -503,11 +509,7 @@ void BatteryPowerFlow::calculateACConnected() // Final batt to grid for outage accounting if (P_battery_ac > 0) { - double P_required_for_load = P_batt_to_load_ac; - if (ac_loss_percent_post_battery < 1) { // Account for possible divide by zero - P_required_for_load /= (1 - ac_loss_percent_post_battery); - } - P_batt_to_grid_ac = P_battery_ac * (1 - ac_loss_percent_post_battery) - P_system_loss_ac - P_required_for_load - P_batt_to_pv_inverter; + P_batt_to_grid_ac = P_battery_ac * (1 - ac_loss_percent_post_battery) - P_system_loss_ac - P_batt_to_load_ac - P_batt_to_pv_inverter; if (m_BatteryPower->isOutageStep && P_batt_to_grid_ac > tolerance) { m_BatteryPower->powerBatteryDC = (P_battery_ac - P_batt_to_grid_ac) / m_BatteryPower->singlePointEfficiencyDCToAC; return calculateACConnected(); @@ -520,7 +522,6 @@ void BatteryPowerFlow::calculateACConnected() P_pv_to_batt_ac *= (1 - ac_loss_percent_post_battery); P_pv_to_grid_ac *= (1 - ac_loss_percent_post_battery); P_grid_to_batt_ac *= (1 - ac_loss_percent_post_battery); - P_grid_to_load_ac *= (1 - ac_loss_percent_post_battery); P_batt_to_load_ac *= (1 - ac_loss_percent_post_battery); P_fuelcell_to_batt_ac *= (1 - ac_loss_percent_post_battery); P_fuelcell_to_load_ac *= (1 - ac_loss_percent_post_battery); diff --git a/test/shared_test/lib_battery_powerflow_test.cpp b/test/shared_test/lib_battery_powerflow_test.cpp index 8721b48b0..be8c1cd03 100644 --- a/test/shared_test/lib_battery_powerflow_test.cpp +++ b/test/shared_test/lib_battery_powerflow_test.cpp @@ -3093,7 +3093,7 @@ TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, AC_system_w_ac_losses) { EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 50.0, error); EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 0.0, error); EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.083, error); + EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.308, error); EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); } @@ -3320,7 +3320,6 @@ TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, DC_system_w_ac_losses) { EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 43.947, error); EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 6.053, error); EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); EXPECT_NEAR(m_batteryPower->powerConversionLoss, 3.738, error); EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); @@ -3341,7 +3340,6 @@ TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, DC_system_w_ac_losses) { EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 50.0, error); EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 0.0, error); EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); EXPECT_NEAR(m_batteryPower->powerConversionLoss, 3.99, error); EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); From 3e0685a9e22d85d311e004fea9b893d5b190fd29 Mon Sep 17 00:00:00 2001 From: Brian Mirletz Date: Tue, 10 Oct 2023 10:05:48 -0600 Subject: [PATCH 3/3] fix spelling in comment --- shared/lib_battery_powerflow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/lib_battery_powerflow.cpp b/shared/lib_battery_powerflow.cpp index ab9a38f70..657267b51 100644 --- a/shared/lib_battery_powerflow.cpp +++ b/shared/lib_battery_powerflow.cpp @@ -489,7 +489,7 @@ void BatteryPowerFlow::calculateACConnected() P_fuelcell_to_grid_ac = 0; } - // Priliminary batt to grid for DC losses + // Preliminary batt to grid for DC losses P_batt_to_grid_ac = P_battery_ac - P_system_loss_ac - P_batt_to_load_ac - P_batt_to_pv_inverter; P_fuelcell_to_grid_ac = P_fuelcell_ac - P_fuelcell_to_load_ac;