Skip to content

Commit

Permalink
Merge branch 'develop' into me_cost_array_scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
mjprilliman committed Oct 12, 2023
2 parents 353a3bd + 25572cc commit 9e215e5
Show file tree
Hide file tree
Showing 18 changed files with 559 additions and 465 deletions.
49 changes: 30 additions & 19 deletions shared/lib_battery_powerflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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);
}
Expand All @@ -483,11 +489,8 @@ void BatteryPowerFlow::calculateACConnected()
P_fuelcell_to_grid_ac = 0;
}

// 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;
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;
Expand All @@ -503,15 +506,23 @@ 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)
{
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();
}
}

// 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);
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_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);
Expand Down
23 changes: 14 additions & 9 deletions shared/lib_battery_voltage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,31 +181,35 @@ voltage_t *voltage_table_t::clone() {
return new voltage_table_t(*this);
}

double voltage_table_t::calculate_voltage(double DOD) {
double voltage_table_t::calculate_voltage(double DOD, double I) {
DOD = fmax(0., DOD);
DOD = fmin(DOD, 100.);

size_t row = 0;
while (row < params->voltage_table.size() && DOD > params->voltage_table[row][0]) {
row++;
}
//
if (DOD < tolerance || DOD > 100. - tolerance) {
I = 0.0; // At full or empty, current must go to zero
}

return fmax(slopes[row] * DOD + intercepts[row], 0);
return fmax(slopes[row] * DOD + intercepts[row], 0) - I * params->resistance;
}

void voltage_table_t::set_initial_SOC(double init_soc) {
state->cell_voltage = calculate_voltage(100. - init_soc);
state->cell_voltage = calculate_voltage(100. - init_soc, 0.0);
}

double voltage_table_t::calculate_voltage_for_current(double I, double q, double qmax, double) {
double DOD = (q - I * params->dt_hr) / qmax * 100.;
return calculate_voltage(DOD) * params->num_cells_series;
return calculate_voltage(DOD, I / params->num_strings) * params->num_cells_series;
}


void voltage_table_t::updateVoltage(double q, double qmax, double, const double, double) {
void voltage_table_t::updateVoltage(double q, double qmax, double I, const double, double) {
double DOD = 100. * (1 - q / qmax);
state->cell_voltage = calculate_voltage(DOD);
state->cell_voltage = calculate_voltage(DOD, I / params->num_strings);
}

// helper fx to calculate depth of discharge from current and max capacities
Expand All @@ -215,7 +219,7 @@ double voltage_table_t::calculate_max_charge_w(double q, double qmax, double, do
double current = (q - qmax) / params->dt_hr;
if (max_current)
*max_current = current;
return calculate_voltage(0.) * current * params->num_cells_series;
return calculate_voltage(0., current / params->num_strings) * current * params->num_cells_series;
}

double voltage_table_t::calculate_max_discharge_w(double q, double qmax, double, double *max_current) {
Expand All @@ -230,7 +234,7 @@ double voltage_table_t::calculate_max_discharge_w(double q, double qmax, double,
dod = fmin(100, dod);
dod = fmax(0, dod);
double current = qmax * ((1. - DOD0 / 100.) - (1. - dod / 100.)) / params->dt_hr;
double p = calculate_voltage(dod) * current;
double p = calculate_voltage(dod, current / params->num_strings) * current;
if (p > max_P) {
max_P = p;
max_I = current;
Expand Down Expand Up @@ -291,7 +295,8 @@ double voltage_table_t::calculate_current_for_target_w(double P_watts, double q,
auto DOD_upper = params->voltage_table[upper][0];
auto DOD_lower = params->voltage_table[lower][0];
if (DOD_new <= DOD_upper && DOD_new >= DOD_lower) {
double P = (q - (100. - DOD_new) * qmax/100) * (a * DOD_new + b);
current = qmax * ((1. - DOD / 100.) - (1. - DOD_new / 100.)) / params->dt_hr;
double P = current * (a * DOD_new + b - current / params->num_strings * params->resistance);
if (std::abs(P) > std::abs(P_best)) {
P_best = P;
DOD_best = DOD_new;
Expand Down
2 changes: 1 addition & 1 deletion shared/lib_battery_voltage.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class voltage_table_t : public voltage_t {
std::vector<double> slopes;
std::vector<double> intercepts;

double calculate_voltage(double DOD);
double calculate_voltage(double DOD, double I);

private:
void initialize();
Expand Down
12 changes: 4 additions & 8 deletions ssc/cmod_annualoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,13 @@ static var_info _cm_vtab_annualoutput[] = {
{ SSC_INPUT, SSC_ARRAY, "energy_degradation", "Annual energy degradation", "%", "", "AnnualOutput", "*", "", "" },
{ SSC_INPUT, SSC_MATRIX, "energy_curtailment", "First year energy curtailment", "", "(0..1)", "AnnualOutput", "*", "", "" },
{ SSC_INPUT, SSC_NUMBER, "system_use_lifetime_output", "Lifetime hourly system outputs", "0/1", "0=hourly first year,1=hourly lifetime", "AnnualOutput", "*", "INTEGER,MIN=0", "" },
// { SSC_INPUT, SSC_ARRAY, "energy_net", "Hourly energy produced by the system", "kW", "", "AnnualOutput", "*", "", "" },
{ SSC_INPUT, SSC_ARRAY, "system_hourly_energy", "Hourly energy produced by the system", "kW", "", "AnnualOutput", "*", "", "" },
{ SSC_INPUT, SSC_ARRAY, "system_hourly_energy", "Hourly energy produced by the system", "kW", "", "AnnualOutput", "*", "", "" },


/* output */
// { SSC_OUTPUT, SSC_ARRAY, "annual_e_net_delivered", "Annual energy", "kWh", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "annual_energy", "Annual energy", "kWh", "", "AnnualOutput", "*", "", "" },
// { SSC_OUTPUT, SSC_ARRAY, "monthly_e_net_delivered", "Monthly energy", "kWh", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "monthly_energy", "Monthly energy gross", "kWh", "", "AnnualOutput", "*", "", "" },
// { SSC_OUTPUT, SSC_ARRAY, "hourly_e_net_delivered", "Hourly energy", "kWh", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "hourly_energy", "Hourly energy", "kWh", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "annual_energy", "Annual energy", "kWh", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "monthly_energy", "Monthly energy gross", "kWh", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "hourly_energy", "Hourly energy", "kWh", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "annual_availability", "Annual availability", "", "", "AnnualOutput", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "annual_degradation", "Annual degradation", "", "", "AnnualOutput", "*", "", "" },

Expand Down
Loading

0 comments on commit 9e215e5

Please sign in to comment.