From d82873405941b47f7e716224c6c6fd9377cf0d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bo=CC=88hm?= Date: Wed, 23 Oct 2024 19:24:44 +0200 Subject: [PATCH] determine solar inverter maxIncrease based on shaded mppts --- src/PowerLimiterSolarInverter.cpp | 57 +++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/src/PowerLimiterSolarInverter.cpp b/src/PowerLimiterSolarInverter.cpp index 7658412b3..df21fc760 100644 --- a/src/PowerLimiterSolarInverter.cpp +++ b/src/PowerLimiterSolarInverter.cpp @@ -18,8 +18,61 @@ uint16_t PowerLimiterSolarInverter::getMaxIncreaseWatts() const { if (!isEligible()) { return 0; } - // TODO(schlimmchen): left for the author of the scaling method: @AndreasBoehm - return std::min(getConfiguredMaxPowerWatts() - getCurrentOutputAcWatts(), 100); + // the maximum increase possible for this inverter + int16_t maxTotalIncrease = getConfiguredMaxPowerWatts() - getCurrentOutputAcWatts(); + + if (!isProducing()) { + // the inverter is not producing, we don't know how much we can increase + // TODO(AndreasBoehm): should we increas by only 100W in this case? Or go for the max? + return 100; // TODO(AndreasBoehm) or maxTotalIncrease + } + + auto pStats = _spInverter->Statistics(); + std::vector dcMppts = _spInverter->getMppts(); + size_t dcTotalMppts = dcMppts.size(); + + // 98% of the expected power is good enough + auto expectedAcPowerPerMppt = (getCurrentLimitWatts() / dcTotalMppts) * 0.98; + + float inverterEfficiencyFactor = pStats->getChannelFieldValue(TYPE_INV, CH0, FLD_EFF); + + // fall back to hoymiles peak efficiency as per datasheet if inverter + // is currently not producing (efficiency is zero in that case) + inverterEfficiencyFactor = (inverterEfficiencyFactor > 0) ? inverterEfficiencyFactor/100 : 0.967; + + size_t dcNonShadedMppts = 0; + + for (auto& m : dcMppts) { + float mpptPowerAC = 0.0; + std::vector mpptChnls = _spInverter->getChannelsDCByMppt(m); + + for (auto& c : mpptChnls) { + mpptPowerAC += pStats->getChannelFieldValue(TYPE_DC, c, FLD_PDC) * inverterEfficiencyFactor; + } + + if (mpptPowerAC >= expectedAcPowerPerMppt) { + dcNonShadedMppts++; + } + } + + if (dcNonShadedMppts == 0) { + // all mppts are shaded, we can't increase the power + return 0; + } + + if (dcNonShadedMppts == dcTotalMppts) { + // no mppt is shaded, we can increase the power by the maximum + // TODO(AndreasBoehm): If none of the mppts are shaded we assume that we can increase the power by the maximum. is this correct? + return maxTotalIncrease; + } + + // maximum increase per mppt, required to calculate how much the non-shaded mppts can increase + int16_t maxIncreasePerCMppt = maxTotalIncrease / dcTotalMppts; + + // maximum increase based on the non-shaded mppts + int16_t maxIncrease = maxIncreasePerCMppt * dcNonShadedMppts; + + return maxIncrease; } uint16_t PowerLimiterSolarInverter::applyReduction(uint16_t reduction, bool)