Skip to content

Commit

Permalink
Merge pull request WISDEM#46 from dzalkind/error_catching
Browse files Browse the repository at this point in the history
Error catching
  • Loading branch information
nikhar-abbas committed Jun 2, 2021
2 parents e53ff37 + 8f0a93c commit af9337b
Show file tree
Hide file tree
Showing 11 changed files with 1,760 additions and 539 deletions.
20 changes: 20 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Description and Purpose

## Type of change
What types of change is it?
_Select the appropriate type(s) that describe this PR_

- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (non-backwards-compatible fix or feature)
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no API changes)
- [ ] Documentation update
- [ ] Maintenance update
- [ ] Other (please describe)

## Github issues addressed, if one exists

## Examples/Testing, if applicable


62 changes: 62 additions & 0 deletions .github/workflows/CI_rosco.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: CI_rosco-toolbox

# We run CI on push commits on all branches
on: [push, pull_request]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
name: Build (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: ["ubuntu-latest", "macOS-latest", "windows-latest"]
python-version: ["3.8"]

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Setup environment
uses: conda-incubator/setup-miniconda@v2
with:
miniconda-version: "latest"
channels: conda-forge, general
auto-update-conda: true
python-version: 3.8
environment-file: environment.yml

# Install compilers
- name: Add dependencies linux
if: false == contains( matrix.os, 'windows')
shell: pwsh
run: |
conda install -y compilers
- name: Add dependencies windows
if: true == contains( matrix.os, 'windows')
shell: bash -l {0}
run: |
conda install -y m2w64-toolchain
# Install ROSCO linux
- name: Compile ROSCO linux
if: false == contains( matrix.os, 'windows')
shell: pwsh
run: |
mkdir build
cd build
cmake ..
make install
# Install ROSCO windows
- name: Compile ROSCO windows
if: true == contains( matrix.os, 'windows')
shell: pwsh
run: |
mkdir build
cd build
cmake .. -G "MinGW Makefiles"
make install
3 changes: 3 additions & 0 deletions environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
channels:
- conda-forge
- defaults
1 change: 1 addition & 0 deletions src/Constants.f90
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ MODULE Constants
REAL(8), PARAMETER :: PI = 3.14159265359 ! Mathematical constant pi
INTEGER(4), PARAMETER :: NP_1 = 1 ! First rotational harmonic
INTEGER(4), PARAMETER :: NP_2 = 2 ! Second rotational harmonic
CHARACTER(*), PARAMETER :: NewLine = ACHAR(10) ! The delimiter for New Lines [ Windows is CHAR(13)//CHAR(10); MAC is CHAR(13); Unix is CHAR(10) {CHAR(13)=\r is a line feed, CHAR(10)=\n is a new line}]
END MODULE Constants
108 changes: 98 additions & 10 deletions src/ControllerBlocks.f90
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,71 @@ MODULE ControllerBlocks
IMPLICIT NONE

CONTAINS
! -----------------------------------------------------------------------------------
! Calculate setpoints for primary control actions
SUBROUTINE ComputeVariablesSetpoints(CntrPar, LocalVar, objInst)
USE ROSCO_Types, ONLY : ControlParameters, LocalVariables, ObjectInstances
USE Constants
! Allocate variables
TYPE(ControlParameters), INTENT(INOUT) :: CntrPar
TYPE(LocalVariables), INTENT(INOUT) :: LocalVar
TYPE(ObjectInstances), INTENT(INOUT) :: objInst

REAL(8) :: VS_RefSpd ! Referece speed for variable speed torque controller, [rad/s]
REAL(8) :: PC_RefSpd ! Referece speed for pitch controller, [rad/s]
REAL(8) :: Omega_op ! Optimal TSR-tracking generator speed, [rad/s]
! temp
! REAL(8) :: VS_TSRop = 7.5

! ----- Calculate yaw misalignment error -----
LocalVar%Y_MErr = LocalVar%Y_M + CntrPar%Y_MErrSet ! Yaw-alignment error

! ----- Pitch controller speed and power error -----
! Implement setpoint smoothing
IF (LocalVar%SS_DelOmegaF < 0) THEN
PC_RefSpd = CntrPar%PC_RefSpd - LocalVar%SS_DelOmegaF
ELSE
PC_RefSpd = CntrPar%PC_RefSpd
ENDIF

LocalVar%PC_SpdErr = PC_RefSpd - LocalVar%GenSpeedF ! Speed error
LocalVar%PC_PwrErr = CntrPar%VS_RtPwr - LocalVar%VS_GenPwr ! Power error

! ----- Torque controller reference errors -----
! Define VS reference generator speed [rad/s]
IF ((CntrPar%VS_ControlMode == 2) .OR. (CntrPar%VS_ControlMode == 3)) THEN
VS_RefSpd = (CntrPar%VS_TSRopt * LocalVar%We_Vw_F / CntrPar%WE_BladeRadius) * CntrPar%WE_GearboxRatio
VS_RefSpd = saturate(VS_RefSpd,CntrPar%VS_MinOMSpd, CntrPar%VS_RefSpd)
ELSE
VS_RefSpd = CntrPar%VS_RefSpd
ENDIF

! Implement setpoint smoothing
IF (LocalVar%SS_DelOmegaF > 0) THEN
VS_RefSpd = VS_RefSpd - LocalVar%SS_DelOmegaF
ENDIF

! Force zero torque in shutdown mode
IF (LocalVar%SD) THEN
VS_RefSpd = CntrPar%VS_MinOMSpd
ENDIF

! Force minimum rotor speed
VS_RefSpd = max(VS_RefSpd, CntrPar%VS_MinOmSpd)

! TSR-tracking reference error
IF ((CntrPar%VS_ControlMode == 2) .OR. (CntrPar%VS_ControlMode == 3)) THEN
LocalVar%VS_SpdErr = VS_RefSpd - LocalVar%GenSpeedF
ENDIF

! Define transition region setpoint errors
LocalVar%VS_SpdErrAr = VS_RefSpd - LocalVar%GenSpeedF ! Current speed error - Region 2.5 PI-control (Above Rated)
LocalVar%VS_SpdErrBr = CntrPar%VS_MinOMSpd - LocalVar%GenSpeedF ! Current speed error - Region 1.5 PI-control (Below Rated)

! Region 3 minimum pitch angle for state machine
LocalVar%VS_Rgn3Pitch = LocalVar%PC_MinPit + CntrPar%PC_Switch

END SUBROUTINE ComputeVariablesSetpoints
!-------------------------------------------------------------------------------------------------------------------------------
SUBROUTINE StateMachine(CntrPar, LocalVar)
! State machine, determines the state of the wind turbine to specify the corresponding control actions
Expand Down Expand Up @@ -101,11 +166,11 @@ SUBROUTINE StateMachine(CntrPar, LocalVar)
END IF
END SUBROUTINE StateMachine
!-------------------------------------------------------------------------------------------------------------------------------
SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar)
SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar, ErrVar)
! Wind Speed Estimator estimates wind speed at hub height. Currently implements two types of estimators
! WE_Mode = 0, Filter hub height wind speed as passed from servodyn using first order low pass filter with 1Hz cornering frequency
! WE_Mode = 1, Use Inversion and Inveriance filter as defined by Ortege et. al.
USE ROSCO_Types, ONLY : LocalVariables, ControlParameters, ObjectInstances, PerformanceData, DebugVariables
USE ROSCO_Types, ONLY : LocalVariables, ControlParameters, ObjectInstances, PerformanceData, DebugVariables, ErrorVariables
IMPLICIT NONE

! Inputs
Expand All @@ -114,6 +179,8 @@ SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar)
TYPE(ObjectInstances), INTENT(INOUT) :: objInst
TYPE(PerformanceData), INTENT(INOUT) :: PerfData
TYPE(DebugVariables), INTENT(INOUT) :: DebugVar
TYPE(ErrorVariables), INTENT(INOUT) :: ErrVar

! Allocate Variables
REAL(8) :: F_WECornerFreq ! Corner frequency (-3dB point) for first order low pass filter for measured hub height wind speed [Hz]

Expand Down Expand Up @@ -143,6 +210,9 @@ SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar)
REAL(8) :: R_m ! Measurement noise covariance [(rad/s)^2]

REAL(8), DIMENSION(3,1), SAVE :: B

CHARACTER(*), PARAMETER :: RoutineName = 'WindSpeedEstimator'

! ---- Debug Inputs ------
DebugVar%WE_b = LocalVar%PC_PitComTF*R2D
DebugVar%WE_w = LocalVar%RotSpeedF
Expand All @@ -152,7 +222,10 @@ SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar)

! Inversion and Invariance Filter implementation
IF (CntrPar%WE_Mode == 1) THEN
LocalVar%WE_VwIdot = CntrPar%WE_Gamma/CntrPar%WE_Jtot*(LocalVar%VS_LastGenTrq*CntrPar%WE_GearboxRatio - AeroDynTorque(LocalVar, CntrPar, PerfData))
! Compute AeroDynTorque
Tau_r = AeroDynTorque(LocalVar, CntrPar, PerfData, ErrVar)

LocalVar%WE_VwIdot = CntrPar%WE_Gamma/CntrPar%WE_Jtot*(LocalVar%VS_LastGenTrq*CntrPar%WE_GearboxRatio - Tau_r)
LocalVar%WE_VwI = LocalVar%WE_VwI + LocalVar%WE_VwIdot*LocalVar%DT
LocalVar%WE_Vw = LocalVar%WE_VwI + CntrPar%WE_Gamma*LocalVar%RotSpeedF

Expand Down Expand Up @@ -180,11 +253,13 @@ SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar)

ELSE
! Find estimated operating Cp and system pole
A_op = interp1d(CntrPar%WE_FOPoles_v,CntrPar%WE_FOPoles,v_h)
A_op = interp1d(CntrPar%WE_FOPoles_v,CntrPar%WE_FOPoles,v_h,ErrVar)

! TEST INTERP2D
lambda = LocalVar%RotSpeed * CntrPar%WE_BladeRadius/v_h
Cp_op = interp2d(PerfData%Beta_vec,PerfData%TSR_vec,PerfData%Cp_mat, LocalVar%BlPitch(1)*R2D, lambda )

Cp_op = interp2d(PerfData%Beta_vec,PerfData%TSR_vec,PerfData%Cp_mat, LocalVar%BlPitch(1)*R2D, lambda, ErrVar)

Cp_op = max(0.0,Cp_op)

! Update Jacobian
Expand All @@ -200,7 +275,7 @@ SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar)
Q(3,3) = (2.0**2.0)/600.0

! Prediction update
Tau_r = AeroDynTorque(LocalVar,CntrPar,PerfData)
Tau_r = AeroDynTorque(LocalVar, CntrPar, PerfData, ErrVar)
a = PI * v_m/(2.0*L)
dxh(1,1) = 1.0/CntrPar%WE_Jtot * (Tau_r - CntrPar%WE_GearboxRatio * LocalVar%VS_LastGenTrqF)
dxh(2,1) = -a*v_t
Expand Down Expand Up @@ -236,6 +311,11 @@ SUBROUTINE WindSpeedEstimator(LocalVar, CntrPar, objInst, PerfData, DebugVar)
LocalVar%WE_Vw = LPFilter(LocalVar%HorWindV, LocalVar%DT, F_WECornerFreq, LocalVar%iStatus, .FALSE., objInst%instLPF)
ENDIF

! Add RoutineName to error message
IF (ErrVar%aviFAIL < 0) THEN
ErrVar%ErrMsg = RoutineName//':'//TRIM(ErrVar%ErrMsg)
ENDIF

END SUBROUTINE WindSpeedEstimator
!-------------------------------------------------------------------------------------------------------------------------------
SUBROUTINE SetpointSmoother(LocalVar, CntrPar, objInst)
Expand All @@ -255,7 +335,7 @@ SUBROUTINE SetpointSmoother(LocalVar, CntrPar, objInst)
! ------ Setpoint Smoothing ------
IF ( CntrPar%SS_Mode == 1) THEN
! Find setpoint shift amount
DelOmega = ((LocalVar%PC_PitComT - CntrPar%PC_MinPit)/0.524) * CntrPar%SS_VSGain - ((LocalVar%VS_GenPwr - LocalVar%VS_LastGenTrq))/CntrPar%VS_RtPwr * CntrPar%SS_PCGain ! Normalize to 30 degrees for now
DelOmega = ((LocalVar%PC_PitComT - LocalVar%PC_MinPit)/0.524) * CntrPar%SS_VSGain - ((CntrPar%VS_RtPwr - LocalVar%VS_LastGenPwr))/CntrPar%VS_RtPwr * CntrPar%SS_PCGain ! Normalize to 30 degrees for now
DelOmega = DelOmega * CntrPar%PC_RefSpd
! Filter
LocalVar%SS_DelOmegaF = LPFilter(DelOmega, LocalVar%DT, CntrPar%F_SSCornerFreq, LocalVar%iStatus, .FALSE., objInst%instLPF)
Expand All @@ -265,20 +345,28 @@ SUBROUTINE SetpointSmoother(LocalVar, CntrPar, objInst)

END SUBROUTINE SetpointSmoother
!-------------------------------------------------------------------------------------------------------------------------------
REAL FUNCTION PitchSaturation(LocalVar, CntrPar, objInst, DebugVar)
REAL FUNCTION PitchSaturation(LocalVar, CntrPar, objInst, DebugVar, ErrVar)
! PitchSaturation defines a minimum blade pitch angle based on a lookup table provided by DISCON.IN
! SS_Mode = 0, No setpoint smoothing
! SS_Mode = 1, Implement pitch saturation
USE ROSCO_Types, ONLY : LocalVariables, ControlParameters, ObjectInstances, DebugVariables
USE ROSCO_Types, ONLY : LocalVariables, ControlParameters, ObjectInstances, DebugVariables, ErrorVariables
IMPLICIT NONE
! Inputs
TYPE(ControlParameters), INTENT(IN) :: CntrPar
TYPE(LocalVariables), INTENT(INOUT) :: LocalVar
TYPE(ObjectInstances), INTENT(INOUT) :: objInst
TYPE(DebugVariables), INTENT(INOUT) :: DebugVar
TYPE(ErrorVariables), INTENT(INOUT) :: ErrVar

CHARACTER(*), PARAMETER :: RoutineName = 'PitchSaturation'

! Define minimum blade pitch angle as a function of estimated wind speed
PitchSaturation = interp1d(CntrPar%PS_WindSpeeds, CntrPar%PS_BldPitchMin, LocalVar%WE_Vw_F)
PitchSaturation = interp1d(CntrPar%PS_WindSpeeds, CntrPar%PS_BldPitchMin, LocalVar%WE_Vw_F, ErrVar)

! Add RoutineName to error message
IF (ErrVar%aviFAIL < 0) THEN
ErrVar%ErrMsg = RoutineName//':'//TRIM(ErrVar%ErrMsg)
ENDIF

END FUNCTION PitchSaturation
!-------------------------------------------------------------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit af9337b

Please sign in to comment.