Skip to content

Commit

Permalink
Implement Walker clipping method
Browse files Browse the repository at this point in the history
  • Loading branch information
mjprilliman committed Sep 29, 2023
1 parent 9c6fb78 commit 6dc0d4f
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 1 deletion.
2 changes: 2 additions & 0 deletions shared/lib_pv_io_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,8 @@ void PVSystem_IO::AllocateOutputs(compute_module* cm)
p_subhourlyClippingLoss = cm->allocate("subhourly_clipping_loss", numberOfLifetimeRecords);
p_subhourlyClippingLossFactor = cm->allocate("subhourly_clipping_loss_factor", numberOfLifetimeRecords);

p_DistributionClippingLoss = cm->allocate("distribution_clipping_loss", numberOfLifetimeRecords);

if (Simulation->useLifetimeOutput)
{
p_dcDegradationFactor = cm->allocate("dc_degrade_factor", numberOfYears);
Expand Down
2 changes: 2 additions & 0 deletions shared/lib_pv_io_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@ struct PVSystem_IO
ssc_number_t *p_subhourlyClippingLoss;
ssc_number_t* p_subhourlyClippingLossFactor;
ssc_number_t* p_ClippingPotential;

ssc_number_t* p_DistributionClippingLoss;
};

/**
Expand Down
48 changes: 48 additions & 0 deletions shared/lib_shared_inverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,54 @@ void SharedInverter::calculateACPower(const double powerDC_kW_in, const double D
}
}

void SharedInverter::calculateACPower(const double powerDC_kW_in, const double powerDC_kW_in_max, const double powerDC_kW_in_min, const double DCStringVoltage, double tempC)
{
double P_par, P_lr;
double P_par_clipping, P_lr_clipping;
double efficiencyAC_clipping, powerClipLoss_kW_clipping, powerConsumptionLoss_kW_clipping, powerNightLoss_kW_clipping = 0;
bool negativePower = powerDC_kW_in < 0 ? true : false;


dcWiringLoss_ond_kW = 0.0;
acWiringLoss_ond_kW = 0.0;

// Power quantities go in and come out in units of W
double powerDC_Watts = powerDC_kW_in * util::kilowatt_to_watt;
double powerAC_Watts = 0.0;
double powerAC_Watts_clipping = 0.0;
Tdry_C = tempC;
StringV = DCStringVoltage;
double tempLoss = 0.0;
double power_ratio = 1.0;
if (m_tempEnabled) {
calculateTempDerate(DCStringVoltage, tempC, powerDC_Watts, power_ratio, tempLoss);
}

m_sandiaInverter->acpower(std::abs(powerDC_Watts) / m_numInvertersClipping, DCStringVoltage, &powerAC_Watts_clipping, &P_par_clipping, &P_lr_clipping, &efficiencyAC_clipping, &powerClipLoss_kW_clipping, &powerConsumptionLoss_kW_clipping, &powerNightLoss_kW_clipping);


if (m_inverterType == SANDIA_INVERTER || m_inverterType == DATASHEET_INVERTER || m_inverterType == COEFFICIENT_GENERATOR)
m_sandiaInverter->acpower(std::abs(powerDC_Watts) / m_numInverters, DCStringVoltage, &powerAC_Watts, &P_par, &P_lr, &efficiencyAC, &powerClipLoss_kW, &powerConsumptionLoss_kW, &powerNightLoss_kW);
else if (m_inverterType == PARTLOAD_INVERTER)
m_partloadInverter->acpower(std::abs(powerDC_Watts) / m_numInverters, &powerAC_Watts, &P_lr, &P_par, &efficiencyAC, &powerClipLoss_kW, &powerNightLoss_kW);
else if (m_inverterType == OND_INVERTER)
m_ondInverter->acpower(std::abs(powerDC_Watts) / m_numInverters, DCStringVoltage, tempC, &powerAC_Watts, &P_par, &P_lr, &efficiencyAC, &powerClipLoss_kW, &powerConsumptionLoss_kW, &powerNightLoss_kW, &dcWiringLoss_ond_kW, &acWiringLoss_ond_kW);
else if (m_inverterType == NONE) {
powerClipLoss_kW = 0.;
powerConsumptionLoss_kW = 0.;
powerNightLoss_kW = 0.;
efficiencyAC = NONE_INVERTER_EFF;
powerAC_Watts = powerDC_Watts * efficiencyAC;
}



m_subhourlyClippingEnabled = true;
powerAC_kW_clipping = powerAC_Watts_clipping * m_numInvertersClipping * util::watt_to_kilowatt;
return;

}

/* This function takes input inverter DC power (kW) per MPPT input for a SINGLE multi-mppt inverter, DC voltage (V) per input, and ambient temperature (deg C), and calculates output for the total number of inverters in the system */
void SharedInverter::calculateACPower(const std::vector<double> powerDC_kW_in, const std::vector<double> DCStringVoltage, double tempC)
{
Expand Down
1 change: 1 addition & 0 deletions shared/lib_shared_inverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class SharedInverter
void calculateACPower(const double powerDC_kW, const double DCStringVoltage, double tempC);

void calculateACPower(const double powerDC_kW, const double DCStringVoltage, double tempC, bool clippingEnabled);
void calculateACPower(const double powerDC_kW, const double powerDC_kW_in_max, const double powerDC_kW_in_min, const double DCStringVoltage, double tempC);

/// Given the combined PV plus battery DC power (kW), voltage and ambient T, compute the AC power (kW) for a single inverter with multiple MPPT inputs
void calculateACPower(const std::vector<double> powerDC_kW, const std::vector<double> DCStringVoltage, double tempC);
Expand Down
57 changes: 56 additions & 1 deletion ssc/cmod_pvsamv1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ static var_info _cm_vtab_pvsamv1[] = {
// PV subhourly clipping inputs
{ SSC_INPUT, SSC_NUMBER, "enable_subhourly_clipping", "Enable subhourly clipping", "0/1", "", "PV Losses", "?=0", "INTEGER,MIN=0,MAX=1", "" },
{ SSC_INPUT, SSC_MATRIX, "subhourly_clipping_matrix", "PV Subhourly clipping correction matrix", "", "", "PV Losses", "", "", "" },
{ SSC_INPUT, SSC_NUMBER, "enable_subinterval_distribution", "Enable subinterval distribution of PV power output", "0/1", "", "PV Losses", "?=0", "INTEGER,MIN=0,MAX=1", "" },


// outputs
Expand Down Expand Up @@ -811,6 +812,7 @@ static var_info _cm_vtab_pvsamv1[] = {
{ SSC_OUTPUT, SSC_ARRAY, "ac_gross", "Inverter AC output power", "kW", "", "Time Series (Array)", "*", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "clipping_potential", "Clipping potential", "", "", "Time Series (Inverter)", "", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "subhourly_clipping_loss", "Subhourly clipping correction loss", "kW", "", "Time Series (Inverter)", "", "", "" },
{ SSC_OUTPUT, SSC_ARRAY, "distribution_clipping_loss", "Subinterval distribution clipping correction loss", "kW", "", "Time Series (Inverter)", "", "", "" },

// transformer model outputs
{ SSC_OUTPUT, SSC_ARRAY, "xfmr_nll_ts", "Transformer no load loss", "kW", "", "Time Series (Transformer)", "", "", "" },
Expand Down Expand Up @@ -957,6 +959,8 @@ static var_info _cm_vtab_pvsamv1[] = {
{ SSC_OUTPUT, SSC_NUMBER, "annual_dc_lifetime_loss_percent", "Lifetime daily DC loss- year 1", "%", "", "Loss", "", "", "" },
{ SSC_OUTPUT, SSC_NUMBER, "annual_dc_battery_loss_percent", "DC connected battery loss- year 1", "%", "", "Loss", "", "", "" },
{ SSC_OUTPUT, SSC_NUMBER, "annual_dc_inv_tdc_loss_percent", "DC inverter thermal derate loss", "%", "", "Loss", "", "", "" },
{ SSC_OUTPUT, SSC_NUMBER, "annual_distribution_clipping_loss_percent", "Subinterval distribution clipping correction loss percent", "%", "", "Loss", "", "", "" },

//annual_dc_net
{ SSC_OUTPUT, SSC_NUMBER, "annual_ac_inv_clip_loss_percent", "AC inverter power clipping loss", "%", "", "Loss", "", "", "" },
{ SSC_OUTPUT, SSC_NUMBER, "annual_ac_inv_pso_loss_percent", "AC inverter power consumption loss", "%", "", "Loss", "", "", "" },
Expand Down Expand Up @@ -991,6 +995,7 @@ static var_info _cm_vtab_pvsamv1[] = {
*/
{ SSC_OUTPUT, SSC_NUMBER, "annual_ac_wiring_loss", "AC wiring loss", "kWh", "", "Annual (Year 1)", "", "", "" },
{ SSC_OUTPUT, SSC_NUMBER, "annual_subhourly_clipping_loss", "Subhourly clipping correction loss", "kWh", "", "Annual (Year 1)", "", "", "" },
{ SSC_OUTPUT, SSC_NUMBER, "annual_distribution_clipping_loss", "Subinterval distribution clipping correction loss", "kWh", "", "Annual (Year 1)", "", "", "" },

{ SSC_OUTPUT, SSC_NUMBER, "annual_transmission_loss", "Transmission loss", "kWh", "", "Annual (Year 1)", "", "", "" },

Expand Down Expand Up @@ -2537,6 +2542,7 @@ void cm_pvsamv1::exec()
double annual_dc_loss_ond = 0, annual_ac_loss_ond = 0; // (TR)
double annual_subhourly_clipping_loss = 0;
double nominal_annual_clipping_output = 0;
double annual_distribution_clipping_loss = 0;
util::matrix_t<double> sub_clipping_matrix(21, 21);
if (as_boolean("enable_subhourly_clipping")) {
if (is_assigned("subhourly_clipping_matrix")) {
Expand Down Expand Up @@ -2613,7 +2619,9 @@ void cm_pvsamv1::exec()
double dcPower_kW = PVSystem->p_systemDCPower[idx];

double dcPower_kW_csky = PVSystem->p_systemDCPowerCS[idx];

double dcPower_kW_max = dcPower_kW_csky;
double dcPower_kW_min = dcPower_kW_max * 0.045 / 1.5; //AM?
double dcPower_kW_avg = dcPower_kW;
// Battery replacement
if (en_batt && (batt_topology == ChargeController::DC_CONNECTED))
{
Expand Down Expand Up @@ -2649,6 +2657,47 @@ void cm_pvsamv1::exec()
}
}

if (as_boolean("enable_subinterval_distribution")) {
if (dcPower_kW > 0) {
double dcPower_kW_max = dcPower_kW_csky;
double dcPower_kW_min = dcPower_kW_max * 0.045 / 1.5; //AM?
double dcPower_kW_avg = dcPower_kW;
double CF = (dcPower_kW_avg - dcPower_kW_min) / (dcPower_kW_max - dcPower_kW_min);
double n = CF / (1 - CF);
int inverter_count = as_integer("inverter_count");
//sharedInverter->calculateACPower(dcPower_kW_csky, dcVoltagePerMppt[0], Irradiance->weatherRecord.tdry, as_boolean("enable_subhourly_clipping"));
double inv_dc_max = sharedInverter->getInverterDCMaxPower(0.0) / 1000.0 * inverter_count;
double T = 1.0;
double log_test = 1 - (inv_dc_max - dcPower_kW_min) / (dcPower_kW_max - dcPower_kW_min);
double t_lm = 0.0;
if (log_test > 0.0) {
t_lm = T * exp(std::log(1 - (inv_dc_max - dcPower_kW_min) / (dcPower_kW_max - dcPower_kW_min)) / n); //fraction of hours
}
double E_clipped = dcPower_kW_max * t_lm - ((dcPower_kW_max - dcPower_kW_min) * pow(t_lm, n + 1) / ((n + 1) * pow(T, n))) - inv_dc_max * t_lm;
double E_remaining = (inv_dc_max - dcPower_kW_max) * T + ((dcPower_kW_max - dcPower_kW_min) * pow(T, n + 1) / ((n + 1) * pow(T, n))) - (inv_dc_max - dcPower_kW_max) * t_lm -
((dcPower_kW_max - dcPower_kW_min) * pow(t_lm, n + 1) / ((n + 1) * pow(T, n)));
double subinterval_clipping_loss = E_clipped;
if (E_clipped > 0) {
for (size_t m = 0; m < PVSystem->Inverter->nMpptInputs; m++)
{
dcPowerNetPerMppt_kW[m] -= E_clipped * dcPowerNetPerMppt_kW[m] / dcPower_kW;
}
dcPower_kW -= E_clipped;
PVSystem->p_DistributionClippingLoss[idx] = E_clipped;
if (iyear == 0) {
annual_distribution_clipping_loss += E_clipped;
}
}
else {
PVSystem->p_DistributionClippingLoss[idx] = 0.0;
}
}
else {
PVSystem->p_DistributionClippingLoss[idx] = 0.0;
}

}

//run AC power calculation
if (en_batt && (batt_topology == ChargeController::DC_CONNECTED)) // DC-connected battery
{
Expand Down Expand Up @@ -2750,6 +2799,7 @@ void cm_pvsamv1::exec()
//annual_subhourly_clipping_loss += ac_subhourlyclipping_loss;
}



ac_wiringloss = std::abs(acpwr_gross) * PVSystem->acLossPercent * 0.01;
//ac_subhourlyclipping_loss = std::abs(acpwr_gross) * annual_subhourly_clipping_loss;
Expand Down Expand Up @@ -3204,6 +3254,7 @@ void cm_pvsamv1::exec()

assign("annual_ac_wiring_loss", var_data((ssc_number_t)annual_ac_wiring_loss));
assign("annual_subhourly_clipping_loss", var_data((ssc_number_t)annual_subhourly_clipping_loss));
assign("annual_distribution_clipping_loss", var_data((ssc_number_t)annual_distribution_clipping_loss));

assign("annual_transmission_loss", var_data((ssc_number_t)annual_transmission_loss));

Expand Down Expand Up @@ -3313,6 +3364,10 @@ void cm_pvsamv1::exec()
if (annual_dc_gross > 0) percent = 100 * annual_dc_lifetime_loss / annual_dc_gross;
assign("annual_dc_lifetime_loss_percent", var_data((ssc_number_t)percent));

percent = 0.;
if (annual_dc_gross > 0) percent = 100 * annual_distribution_clipping_loss / annual_dc_gross;
assign("annual_distribution_clipping_loss_percent", var_data((ssc_number_t)percent));


//annual_dc_net
percent = 0.;
Expand Down

0 comments on commit 6dc0d4f

Please sign in to comment.