def control(self,
                currentCV: np.ndarray,
                idq0SP: np.ndarray = np.zeros(3),
                **kwargs):
        """
        Performs the calculations for a discrete step of the controller

        :param currentCV: 1d-array with 3 entries, one for each phase in abc. The feedback values for current
        :param idq0SP: 1d-array with 3 entries, one for each phase in dq0. Current set points for current sourcing ctrl

        :return: Modulation index for the inverter in abc
        """

        # Get the next phase rotation angle to implement
        phase = self._phaseDDS.step(self.f_nom)

        # Transform the feedback to the dq0 frame
        CVIdq0 = abc_to_dq0(currentCV, phase)

        # current setpoint
        SPIdq0 = np.array(idq0SP[:])
        SPIabc = dq0_to_abc(SPIdq0, phase)
        # Current controller calculations
        MVdq0 = self._currentPI.step(SPIdq0, CVIdq0)
        MVabc = dq0_to_abc(MVdq0, phase)

        # Add intern measurment
        self._last_meas = [phase, *CVIdq0, *SPIdq0, *SPIabc, *MVdq0, *MVabc]

        # Transform the MVs back to the abc frame
        return MVabc
Example #2
0
    def rew_fun(self, cols: List[str], data: np.ndarray, risk) -> float:
        """
        Defines the reward function for the environment. Uses the observations and set-points to evaluate the quality of
        the used parameters.
        Takes current and voltage measurements and set-points to calculate the mean-root control error and uses a
        logarithmic barrier function in case of violating the current limit. Barrier function is adjustable using
        parameter mu.

        :param cols: list of variable names of the data
        :param data: observation data from the environment (ControlVariables, e.g. currents and voltages)
        :return: Error as negative reward
        """
        self.set_idx(cols)
        idx = self._idx

        iabc_master = data[idx[0]]  # 3 phase currents at LC inductors
        phase = data[idx[1]]  # phase from the master controller needed for transformation
        vabc_master = data[idx[3]]  # 3 phase currents at LC inductors

        # set points (sp)
        isp_dq0_master = data[idx[2]]  # setting dq current reference
        isp_abc_master = dq0_to_abc(isp_dq0_master, phase)  # convert dq set-points into three-phase abc coordinates
        vsp_dq0_master = data[idx[4]]  # setting dq voltage reference
        vsp_abc_master = dq0_to_abc(vsp_dq0_master, phase)  # convert dq set-points into three-phase abc coordinates

        # control error = mean-root-error (MRE) of reference minus measurement
        # (due to normalization the control error is often around zero -> compared to MSE metric, the MRE provides
        #  better, i.e. more significant,  gradients)
        # plus barrier penalty for violating the current constraint
        error = np.sum((np.abs((isp_abc_master - iabc_master)) / i_lim) ** 0.5, axis=0) \
                + -np.sum(mu * np.log(1 - np.maximum(np.abs(iabc_master) - i_nom, 0) / (i_lim - i_nom)), axis=0) \
                + np.sum((np.abs((vsp_abc_master - vabc_master)) / net.v_nom) ** 0.5, axis=0)

        return -error.squeeze()
    def control(self, currentCV: np.ndarray, voltageCV: np.ndarray, **kwargs):
        """
        Performs the calculations for a discrete step of the controller

        :param currentCV: 1d-array with 3 entries, one for each phase in abc. The feedback values for current
        :param voltageCV:  1d-array with 3 entries, one for each phase in abc. The feedback values for voltage

        :return: Modulation index for the inverter in abc
        """

        instPow = -inst_power(voltageCV, currentCV)
        freq = self._PdroopController.step(instPow)
        # Get the next phase rotation angle to implement
        self.phase = phase = self._phaseDDS.step(freq)

        instQ = -inst_reactive(voltageCV, currentCV)
        voltage = self._QdroopController.step(instQ)

        # Transform the feedback to the dq0 frame
        CVIdq0 = abc_to_dq0(currentCV, phase)
        CVVdq0 = abc_to_dq0(voltageCV, phase)

        # If available, calulate load current using observer
        iabc_out_etimate = np.empty(N_PHASE)
        if self._observer is None:
            iabc_out_etimate = np.zeros(N_PHASE)
        else:
            for j in range(N_PHASE):
                iabc_out_etimate[j] = self._observer[j].cal_estimate(
                    y=[currentCV[j], voltageCV[j]], u=self._lastMabc[j])

        i_dq0_out_estimat = abc_to_dq0(iabc_out_etimate, phase)

        # Voltage controller calculations
        VSP = voltage
        # Voltage SP in dq0 (static for the moment)
        SPVdq0 = np.array([VSP, 0, 0])
        SPVabc = dq0_to_abc(SPVdq0, phase)
        SPIdq0 = self._voltagePI.step(SPVdq0, CVVdq0, i_dq0_out_estimat)

        SPIabc = dq0_to_abc(SPIdq0, phase)

        # Current controller calculations
        MVdq0 = self._currentPI.step(SPIdq0, CVIdq0)
        MVabc = dq0_to_abc(MVdq0,
                           phase)  # Transform the MVs back to the abc frame
        self._lastMabc = MVabc
        # Add intern measurment
        self._last_meas = [
            phase, instPow, instQ, freq, *SPVdq0, *SPVabc, *SPIdq0, *SPIabc,
            *CVVdq0, *CVIdq0, *i_dq0_out_estimat, *iabc_out_etimate, *MVdq0,
            *MVabc
        ]

        return MVabc
    def calculate(self):
        super().calculate()
        instPow = -inst_power(self.v, self.i)
        freq = self.pdroop_ctl.step(instPow)
        # Get the next phase rotation angle to implement
        phase = self.dds.step(freq)

        instQ = -inst_reactive(self.v, self.i)
        v_refd = self.qdroop_ctl.step(instQ)
        v_refdq0 = np.array([v_refd, 0, 0]) * self.v_ref

        return dict(i_ref=dq0_to_abc(self.i_ref, phase), v_ref=dq0_to_abc(v_refdq0, phase))
Example #5
0
    def rew_fun_funnel(self, cols: List[str], data: np.ndarray, risk) -> float:
        """
        Defines the reward function for the environment. Uses the observations and set-points to evaluate the quality of
        the used parameters.
        Takes current and voltage measurements and set-points to calculate the mean-root control error and uses a
        logarithmic barrier function in case of violating the current limit. Barrier function is adjustable using
        parameter mu.

        :param cols: list of variable names of the data
        :param data: observation data from the environment (ControlVariables, e.g. currents and voltages)
        :return: Error as negative reward
        """
        self.set_idx(cols)
        idx = self._idx

        phase = data[idx[
            1]]  # phase from the master controller needed for transformation
        vabc_master = data[idx[3]]  # 3 phase currents at LC inductors
        vdq0_master = data[idx[5]]

        # set points (sp)
        vsp_dq0_master = data[idx[4]]  # setting dq voltage reference
        vsp_abc_master = dq0_to_abc(
            vsp_dq0_master,
            phase)  # convert dq set-points into three-phase abc coordinates

        # calculate
        err = vdq0_master - vsp_dq0_master

        if (abs(err) > self.funnel).any():
            # E2 + Offset
            error = (np.sum((np.abs(
                (vsp_abc_master - vabc_master)) / self.v_limit)**0.5,
                            axis=0) + 20) / self.max_episode_steps
        else:
            # E1 <! E2 and E1 << Offset
            error = np.sum((np.abs(
                (vsp_abc_master - vabc_master)) / self.v_limit)**2,
                           axis=0) / self.max_episode_steps

        return -error.squeeze()
    def control(self, currentCV: np.ndarray, voltageCV: np.ndarray, **kwargs):
        instPow = -inst_power(voltageCV, currentCV)
        freq = self._PdroopController.step(instPow)
        # Get the next phase rotation angle to implement
        phase = self._phaseDDS.step(freq)

        instQ = -inst_reactive(voltageCV, currentCV)
        voltage = self._QdroopController.step(instQ)

        VSP = voltage * 1.732050807568877
        # Voltage SP in dq0 (static for the moment)
        SPVdq0 = np.array([VSP, 0, 0])

        # Get the voltage SPs in abc vector
        # print("SPVdq0: {}, phase: {}".format(SPVdq0,phase))
        SPV = dq0_to_abc(SPVdq0, phase)

        # print("QInst: {}, Volt {}".format(instQ,VSP))
        SPI = self._voltagePI.step(SPV, voltageCV)

        # Average voltages from modulation indices created by current controller
        return self._currentPI.step(SPI, currentCV)
    def control(self, currentCV: np.ndarray, voltageCV: np.ndarray, **kwargs):
        """
        Performs the calculations for a discrete step of the controller

        :param currentCV: 1d-array with 3 entries, one for each phase in abc. The feedback values for current
        :param voltageCV:  1d-array with 3 entries, one for each phase in abc. The feedback values for voltage

        :return: Modulation index for the inverter in abc
        """

        instPow = -inst_power(voltageCV, currentCV)
        freq = self._PdroopController.step(instPow)
        # Get the next phase rotation angle to implement
        phase = self._phaseDDS.step(freq)

        instQ = -inst_reactive(voltageCV, currentCV)
        voltage = self._QdroopController.step(instQ)

        # Transform the feedback to the dq0 frame
        CVIdq0 = abc_to_dq0(currentCV, phase)
        CVVdq0 = abc_to_dq0(voltageCV, phase)

        # Voltage controller calculations
        VSP = voltage
        # Voltage SP in dq0 (static for the moment)
        SPVdq0 = np.array([VSP, 0, 0])
        SPIdq0 = self._voltagePI.step(SPVdq0, CVVdq0)

        # Current controller calculations
        MVdq0 = self._currentPI.step(SPIdq0, CVIdq0)

        # Add intern measurment
        self.history.append([
            phase, *SPVdq0, *SPIdq0, *CVVdq0, *CVIdq0, *MVdq0, instPow, instQ,
            freq
        ])

        # Transform the MVs back to the abc frame
        return dq0_to_abc(MVdq0, phase)
 def calculate(self):
     super().calculate()
     # Get the next phase rotation angle to implement
     phase = self.dds.step(self.f_nom)
     return dict(i_ref=dq0_to_abc(self.i_ref, phase))
 def calculate(self):
     super().calculate()
     _, _, phase = self.pll.step(self.v)
     return dict(i_ref=dq0_to_abc(self.i_ref, phase))