Skip to content

Commit

Permalink
AC side of subhourly clipping matrix method
Browse files Browse the repository at this point in the history
  • Loading branch information
mjprilliman committed Jul 27, 2023
1 parent 491f4fd commit ffe3266
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 6 deletions.
1 change: 1 addition & 0 deletions shared/lib_pv_io_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ PVSystem_IO::PVSystem_IO(compute_module* cm, std::string cmName, Simulation_IO*
}

numberOfInverters = cm->as_integer("inverter_count");
numberOfInvertersClipping = cm->as_integer("calculated_num_inverter_dcac_unity");
ratedACOutput = Inverter->ratedACOutput * numberOfInverters;
acDerate = 1 - cm->as_double("acwiring_loss") / 100;
acLossPercent = (1 - acDerate) * 100;
Expand Down
4 changes: 3 additions & 1 deletion shared/lib_pv_io_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ struct PVSystem_IO

size_t numberOfSubarrays;
size_t numberOfInverters;
size_t numberOfInvertersClipping;

Irradiance_IO * Irradiance;
Simulation_IO * Simulation;
Expand Down Expand Up @@ -350,7 +351,7 @@ struct PVSystem_IO
std::vector<ssc_number_t*> p_poaDiffuseFrontCS;
std::vector<ssc_number_t*> p_poaGroundFrontCS;
std::vector<ssc_number_t*> p_DNIIndex;
//std::vector<ssc_number_t*> p_ClippingPotential;
std::vector<ssc_number_t*> p_ClippingPotential;

// MPPT level outputs
std::vector<ssc_number_t *> p_mpptVoltage; /// An output vector containing input DC voltage in V to each mppt input
Expand Down Expand Up @@ -415,6 +416,7 @@ struct PVSystem_IO
ssc_number_t *p_dcLifetimeLoss; // kWdc

ssc_number_t *p_systemDCPower; // kWdc
ssc_number_t* p_systemDCPowerCS; // kWdc
ssc_number_t *p_systemACPower; // kWac
};

Expand Down
13 changes: 12 additions & 1 deletion shared/lib_shared_inverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "lib_util.h"

SharedInverter::SharedInverter(int inverterType, size_t numberOfInverters,
sandia_inverter_t* sandiaInverter, partload_inverter_t* partloadInverter, ond_inverter* ondInverter)
sandia_inverter_t* sandiaInverter, partload_inverter_t* partloadInverter, ond_inverter* ondInverter, size_t numberOfInvertersClipping)
{
m_inverterType = inverterType;
m_numInverters = numberOfInverters;
m_numInvertersClipping = numberOfInvertersClipping;
m_sandiaInverter = sandiaInverter;
m_partloadInverter = partloadInverter;
m_ondInverter = ondInverter;
m_tempEnabled = false;
m_subhourlyClippingEnabled = false;

if (m_inverterType == SANDIA_INVERTER || m_inverterType == DATASHEET_INVERTER || m_inverterType == COEFFICIENT_GENERATOR)
m_nameplateAC_kW = m_numInverters * m_sandiaInverter->Paco * util::watt_to_kilowatt;
Expand Down Expand Up @@ -78,6 +80,8 @@ SharedInverter::SharedInverter(const SharedInverter& orig) {
m_ondInverter = orig.m_ondInverter;
efficiencyAC = orig.efficiencyAC;

m_subhourlyClippingEnabled = orig.m_subhourlyClippingEnabled;

powerDC_kW = orig.powerDC_kW;
powerAC_kW = orig.powerAC_kW;
powerClipLoss_kW = orig.powerClipLoss_kW;
Expand Down Expand Up @@ -244,6 +248,7 @@ double SharedInverter::getInverterDCMaxPower(double p_dc_rated)
void SharedInverter::calculateACPower(const double powerDC_kW_in, const double DCStringVoltage, double tempC)
{
double P_par, P_lr;
double P_par_clipping, P_lr_clipping;
bool negativePower = powerDC_kW_in < 0 ? true : false;


Expand All @@ -253,6 +258,7 @@ void SharedInverter::calculateACPower(const double powerDC_kW_in, const double D
// 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;
Expand All @@ -261,6 +267,10 @@ void SharedInverter::calculateACPower(const double powerDC_kW_in, const double D
calculateTempDerate(DCStringVoltage, tempC, powerDC_Watts, power_ratio, tempLoss);
}

if (m_numInvertersClipping > 0) {
m_sandiaInverter->acpower(std::abs(powerDC_Watts) / m_numInvertersClipping, DCStringVoltage, &powerAC_Watts_clipping, &P_par_clipping, &P_lr_clipping, &efficiencyAC, &powerClipLoss_kW, &powerConsumptionLoss_kW, &powerNightLoss_kW);

}

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);
Expand All @@ -280,6 +290,7 @@ void SharedInverter::calculateACPower(const double powerDC_kW_in, const double D
// Convert units to kW- no need to scale to system size because passed in as power to total number of inverters
powerDC_kW = powerDC_Watts * util::watt_to_kilowatt;
convertOutputsToKWandScale(tempLoss, powerAC_Watts);
powerAC_kW_clipping = powerAC_Watts / 1000.0;

// In event shared inverter is charging a battery only, need to re-convert to negative power
if (negativePower) {
Expand Down
5 changes: 4 additions & 1 deletion shared/lib_shared_inverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class SharedInverter

/// Construct a shared inverter by registering the previously constructed inverter
SharedInverter(int inverterType, size_t numberOfInverters,
sandia_inverter_t* sandiaInverter, partload_inverter_t* partloadInverter, ond_inverter* ondInverter);
sandia_inverter_t* sandiaInverter, partload_inverter_t* partloadInverter, ond_inverter* ondInverter, size_t numberOfInvertersClipping = 0);

SharedInverter(const SharedInverter& orig);

Expand Down Expand Up @@ -96,6 +96,7 @@ class SharedInverter
// calculated values for the current timestep
double powerDC_kW;
double powerAC_kW;
double powerAC_kW_clipping;
double efficiencyAC; // 0-100
double powerClipLoss_kW;
double powerConsumptionLoss_kW;
Expand All @@ -109,10 +110,12 @@ class SharedInverter

int m_inverterType; ///< The inverter type
size_t m_numInverters; ///< The number of inverters in the system
size_t m_numInvertersClipping;
double m_nameplateAC_kW; ///< The total nameplate AC capacity for all inverters in kW

/// Temperate Derating: each curve contains DC voltage and pairs of start-derate temp [C] and slope [efficiency% lost per C]
bool m_tempEnabled;
bool m_subhourlyClippingEnabled;
std::vector<std::vector<double>> m_thermalDerateCurves; /// ordered by DC V
/// Given a temp, find which slope to apply
void findPointOnCurve(size_t idx, double T, double& startT, double& slope);
Expand Down
40 changes: 37 additions & 3 deletions ssc/cmod_pvsamv1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ static var_info _cm_vtab_pvsamv1[] = {
{SSC_INPUT, SSC_NUMBER, "irrad_mode", "Irradiance input translation mode", "", "0=beam&diffuse,1=total&beam,2=total&diffuse,3=poa_reference,4=poa_pyranometer", "Solar Resource", "?=0", "INTEGER,MIN=0,MAX=4", "" },
{SSC_INPUT, SSC_NUMBER, "sky_model", "Diffuse sky model", "", "0=isotropic,1=hkdr,2=perez", "Solar Resource", "?=2", "INTEGER,MIN=0,MAX=2", "" },
{SSC_INPUT, SSC_NUMBER, "inverter_count", "Number of inverters", "", "", "System Design", "*", "INTEGER,POSITIVE", "" },
{SSC_INPUT, SSC_NUMBER, "calculated_num_inverter_dcac_unity", "Number of inverters for DC:AC ratio of 1", "", "", "System Design", "", "INTEGER,POSITIVE", "" },
{SSC_INPUT, SSC_NUMBER, "enable_mismatch_vmax_calc", "Enable mismatched subarray Vmax calculation", "", "", "System Design", "?=0", "BOOLEAN", "" },
{SSC_INPUT, SSC_NUMBER, "calculate_rack_shading", "Calculate rack shading", "", "", "Losses", "?=0", "BOOLEAN", "" },
{SSC_INPUT, SSC_NUMBER, "calculate_bifacial_electrical_mismatch", "Calculate bifacial electrical mismatch", "", "", "Losses", "?=1", "BOOLEAN", "" },
Expand Down Expand Up @@ -2532,7 +2533,7 @@ void cm_pvsamv1::exec()

double dcPower_kW = PVSystem->p_systemDCPower[idx];

double dcPwer_kw_csky = PVSystem->p_systemDCPower[idx]
double dcPower_kW_csky = PVSystem->p_systemDCPowerCS[idx];

// Battery replacement
if (en_batt && (batt_topology == ChargeController::DC_CONNECTED))
Expand Down Expand Up @@ -2568,6 +2569,11 @@ void cm_pvsamv1::exec()
}
}

if (as_boolean("enable_subhourly_clipping")) {
sharedInverter->calculateACPower(dcPower_kW_csky, dcVoltagePerMppt[0], Irradiance->weatherRecord.tdry); //DC batteries not allowed with multiple MPPT, so can just use MPPT 1's voltage

}

//run AC power calculation
if (en_batt && (batt_topology == ChargeController::DC_CONNECTED)) // DC-connected battery
{
Expand Down Expand Up @@ -2622,11 +2628,39 @@ void cm_pvsamv1::exec()

if (as_boolean("en_subhourly_clipping")) {
//Calculate DNI clearness index (time step basis)

double dni_clearness_index = PVSystem->p_DNIIndex[0][idx];
//Calculate Clipping Potential ((P_dc,dryclean - P_ac,0) / P_ac,0) (time step basis)
sharedInverter->calculateACPower(dcPower_kW_csky, dcVoltagePerMppt[0], Irradiance->weatherRecord.tdry); //DC batteries not allowed with multiple MPPT, so can just use MPPT 1's voltage
double clip_pot = (dcPower_kW_csky - sharedInverter->powerAC_kW_clipping) / sharedInverter->powerAC_kW_clipping;
//Lookup matrix for percentage effect based on DNI index, Clipping potential //Lookup bias error in matrix (unitless) [CP, DNI]
util::matrix_t<double> sub_clipping_matrix = as_matrix("subhourly_clipping_matrix");
size_t nrows = sub_clipping_matrix.nrows();
size_t ncols = sub_clipping_matrix.ncols();
size_t dni_row = 0;
size_t clip_pot_col = 0;
double clip_correction = 0;
if (dni_clearness_index < sub_clipping_matrix.at(1, 0)) dni_row = 1;
else if (dni_clearness_index > sub_clipping_matrix.at(nrows - 1, 0)) dni_row = nrows - 1;
else {
for (size_t r = 1; r < nrows; r++) {
if (dni_clearness_index > sub_clipping_matrix.at(r, 0) && dni_clearness_index < sub_clipping_matrix.at(r + 1, 0)) {
dni_row = r;
}
}
}

//Lookup bias error in matrix (unitless) [CP, DNI]
//Clipping potential indexing
if (clip_pot < sub_clipping_matrix.at(0, 1)) clip_pot_col = 1;
else if (clip_pot > sub_clipping_matrix.at(0, ncols - 1)) clip_pot_col = ncols - 1;
else {
for (size_t c = 1; c < ncols; c++) {
if (clip_pot > sub_clipping_matrix.at(0, c) && clip_pot < sub_clipping_matrix.at(0, c + 1)) {
clip_pot_col = c;
}
}
}

acpwr_gross *= sub_clipping_matrix.at(dni_row, clip_pot_col);
}


Expand Down

0 comments on commit ffe3266

Please sign in to comment.