def control(self, currentCV: np.ndarray, voltageCV: np.ndarray, idq0SP: np.ndarray = np.zeros(3), **kwargs): """ Performs the calculations for a discrete step of the controller Droop-control is started if Vgrid_rms exceeds 200 V, to avoid oscillation with the grid forming inverter :param currentCV: 1d-array with 3 entries, one for each phase. The feedback values for current :param voltageCV: 1d-array with 3 entries, one for each phase. The feedback values for voltage :param idq0SP: The peak current setpoints in the dq0 frame (Additional power output to droop, if == 0, than only droop is applied :return: Modulation indices for the current sourcing inverter in ABC """ # Calulate P&Q for slave instPow = -inst_power(voltageCV, currentCV) instQ = -inst_reactive(voltageCV, currentCV) Vinst = inst_rms(voltageCV) # Get current phase information from the voltage measurement self._prev_cossine, self._prev_freq, self._prev_theta = self._pll.step( voltageCV) # Transform the current feedback to the DQ0 frame self._lastIDQ = abc_to_dq0_cos_sin(currentCV, *self._prev_cossine) droop = np.zeros(2) if Vinst > self.lower_droop_voltage_threshold: # Determine the droop power setpoints droopPI = (self._PdroopController.step(self._prev_freq) / inst_rms(voltageCV)) # Determine the droop reactive power set points droopQI = (self._QdroopController.step(Vinst) / Vinst) droop = np.array([ droopPI, droopQI ]) / 3 # devide by 3 due to here dq, but we want to set the e.g. # d-setpoint in the sum of the phases abc droop = droop * 1.4142135623730951 # RMS to Peak droop = np.clip(droop, -self._i_limit, self._i_limit) idq0SP = idq0SP + np.array([-droop[0], +droop[1], 0]) # Calculate the control applied to the DQ0 currents # action space is limited to [-1,1] MVdq0 = self._currentPI.step(idq0SP, self._lastIDQ) # Transform the outputs from the controllers (dq0) to abc # also divide by SQRT(2) to ensure the transform is limited to [-1,1] MVabc = dq0_to_abc_cos_sin(MVdq0, *self._prev_cossine) self._last_meas = [ self._prev_theta, instPow, instQ, self._prev_freq, *self._lastIDQ, *idq0SP, *MVdq0, *MVabc ] return MVabc
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))
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)