HvdcUtils.java
/**
* Copyright (c) 2023, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.iidm.network.util;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.*;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Anne Tilloy {@literal <anne.tilloy at rte-france.com>}
*/
public final class HvdcUtils {
public static double getConverterStationTargetP(HvdcConverterStation<?> station) {
// for a LCC converter station, we are in load convention.
// If the converter station is at side 1 and is a rectifier, p should be positive.
// If the converter station is at side 1 and is an inverter, p should be negative.
// If the converter station is at side 2 and is a rectifier, p should be positive.
// If the converter station is at side 2 and is an inverter, p should be negative.
boolean disconnectedAtOtherSide = station.getOtherConverterStation().map(otherConverterStation -> {
Bus bus = otherConverterStation.getTerminal().getBusView().getBus();
return bus == null;
}).orElse(true); // it means there is no HVDC line connected to station
return disconnectedAtOtherSide ? 0.0 : getSign(station) * getAbsoluteValuePAc(station);
}
public static double getLccConverterStationLoadTargetQ(LccConverterStation lccCs) {
// Load convention.
// If the converter station is at side 1 and is rectifier, p should be positive.
// If the converter station is at side 1 and is inverter, p should be negative.
// If the converter station is at side 2 and is rectifier, p should be positive.
// If the converter station is at side 2 and is inverter, p should be negative.
double pCs = getConverterStationTargetP(lccCs);
return Math.abs(
pCs * Math.tan(Math.acos(lccCs.getPowerFactor()))); // A LCC station always consumes reactive power.
}
public static double getSign(HvdcConverterStation<?> station) {
// This method gives the sign of PAc.
boolean isConverterStationRectifier = isRectifier(station);
double sign;
if (station instanceof LccConverterStation) { // load convention.
sign = isConverterStationRectifier ? 1 : -1;
} else if (station instanceof VscConverterStation) { // generator convention.
sign = isConverterStationRectifier ? -1 : 1;
} else {
throw new PowsyblException("Unknown HVDC converter station type: " + station.getClass().getSimpleName());
}
return sign;
}
public static boolean isRectifier(HvdcConverterStation<?> station) {
Objects.requireNonNull(station);
HvdcLine line = station.getHvdcLine();
return line.getConverterStation1() == station && line.getConvertersMode() == HvdcLine.ConvertersMode.SIDE_1_RECTIFIER_SIDE_2_INVERTER
|| line.getConverterStation2() == station && line.getConvertersMode() == HvdcLine.ConvertersMode.SIDE_1_INVERTER_SIDE_2_RECTIFIER;
}
private static double getAbsoluteValuePAc(HvdcConverterStation<?> station) {
boolean isConverterStationRectifier = isRectifier(station);
if (isConverterStationRectifier) {
return station.getHvdcLine().getActivePowerSetpoint();
} else {
// the converter station is inverter.
AtomicReference<Double> absoluteValueInverterPAc = new AtomicReference<>((double) 0);
Optional<? extends HvdcConverterStation<?>> otherStation = station.getOtherConverterStation();
otherStation.ifPresent(os -> absoluteValueInverterPAc.set(getAbsoluteValueInverterPAc(os.getLossFactor(), station.getLossFactor(), station.getHvdcLine())));
return absoluteValueInverterPAc.get();
}
}
public static double getHvdcLineLosses(double rectifierPDc, double nominalV, double r) {
// This method computes the losses due to the HVDC line.
// The active power value on rectifier DC side is known as the HVDC active power set point minus the losses related
// to AC/DC conversion (rectifier conversion), the voltage is approximated to the nominal voltage as attribute of the HVDC line.
// In an HVDC, as a branch with two sides, the difference between pDc1 and pDc2 can be computed with the assumptions:
// I = (V1 - V2) / R and pDc1 = I * V1 and pDc2 = I * V2 and V1 = nominalV
// we simply obtain that the absolute value of the difference is equal to R * pDc1 * pDc1 / (V1 * V1) if side 1 is rectifier side.
return r * rectifierPDc * rectifierPDc / (nominalV * nominalV);
}
private static double getAbsoluteValueInverterPAc(double rectifierLossFactor, double inverterLossFactor,
HvdcLine hvdcLine) {
// On inverter side, absolute value of PAc of a VSC converter station should be computed in three step:
// 1) compute the losses related to the rectifier conversion.
// 2) compute the losses related to the HVDC line itself (R i^2).
// 3) compute the losses related to the inverter conversion.
double rectifierPDc = hvdcLine.getActivePowerSetpoint() * (1 - rectifierLossFactor / 100); // rectifierPDc positive.
double inverterPDc = rectifierPDc - getHvdcLineLosses(rectifierPDc, hvdcLine.getNominalV(), hvdcLine.getR());
return inverterPDc * (1 - inverterLossFactor / 100); // always positive.
}
private HvdcUtils() {
}
}