ROSCO-MATLAB Implementation
Moderator: Bonnie.Jonkman
-
Bartosz.Stachowicz
- Posts: 27
- Joined: Wed Jul 29, 2020 4:37 am
- Organization: Politechnika Gdanska
- Location: Gdansk
Re: ROSCO-MATLAB Implementation
Dear Nikhar Abbas,
In the paper you shared in this thread replying to KumaraRaja.Eedara you are mentioning the minimum rotor speed constraint. How is it estimated/derived for the 15MW NREL turbine?
BS
In the paper you shared in this thread replying to KumaraRaja.Eedara you are mentioning the minimum rotor speed constraint. How is it estimated/derived for the 15MW NREL turbine?
BS
-
Nikhar.Abbas
- Posts: 30
- Joined: Wed Apr 29, 2020 7:11 pm
- Organization: National Renewable Energy Lab
- Location: Boulder, CO
Re: ROSCO-MATLAB Implementation
Hi Bartosz,
The minimum rotor speed is simply from the definition of the IEA 15MW wind turbine here:
https://www.nrel.gov/docs/fy20osti/75698.pdf
Nikhar
The minimum rotor speed is simply from the definition of the IEA 15MW wind turbine here:
https://www.nrel.gov/docs/fy20osti/75698.pdf
Nikhar
-
Shubham.Baisthakur
- Posts: 11
- Joined: Thu Jan 07, 2021 11:40 pm
- Organization: Trinity College Dublin
- Location: Ireland
Re: ROSCO-MATLAB Implementation
Hello Nikhar,
What is the main purpose of the DISCON.dll and DISCON.f90 file? Are these files only used to communicate with the openFAST? Also, what is the significance of the avrSWAP variable, which is repeatedly used in the ROSCO source code?
While implementing ROSCO in MATLAB, is it possible to bypass these files? Since I have an indigenously developed wind turbine model, I won't have to interface the controller with openFAST.
Thanks,
Shubham
What is the main purpose of the DISCON.dll and DISCON.f90 file? Are these files only used to communicate with the openFAST? Also, what is the significance of the avrSWAP variable, which is repeatedly used in the ROSCO source code?
While implementing ROSCO in MATLAB, is it possible to bypass these files? Since I have an indigenously developed wind turbine model, I won't have to interface the controller with openFAST.
Thanks,
Shubham
-
Nikhar.Abbas
- Posts: 30
- Joined: Wed Apr 29, 2020 7:11 pm
- Organization: National Renewable Energy Lab
- Location: Boulder, CO
Re: ROSCO-MATLAB Implementation
Hi Shubham,
DISCON.dll is the compiled binary file that OpenFAST (or any other simulator) calls to run ROSCO. DISCON.f90 is the "top-level" script in ROSCO that contains the primary DISCON routine. This routine calls all of the internal submodules, functions, etc., that make ROSCO run as it does. Finally, the avrSWAP is an array that is passed between ROSCO and the calling wind turbine simulator (e.g. OpenFAST) containing all of the controller's inputs/outputs. The structure of the avrSWAP is "bladed-style" - meaning that each entry in the array is consistent with DNV-GL Bladed's array structure (e.g., avrSWAP(2) contains the time variable, always).
For your purposes, I don't think any of these are particularly necessary. You might want to to draw from the structure of DISCON.f90 to understand the order of calls that happens in ROSCO, though.
Cheers,
Nikhar
DISCON.dll is the compiled binary file that OpenFAST (or any other simulator) calls to run ROSCO. DISCON.f90 is the "top-level" script in ROSCO that contains the primary DISCON routine. This routine calls all of the internal submodules, functions, etc., that make ROSCO run as it does. Finally, the avrSWAP is an array that is passed between ROSCO and the calling wind turbine simulator (e.g. OpenFAST) containing all of the controller's inputs/outputs. The structure of the avrSWAP is "bladed-style" - meaning that each entry in the array is consistent with DNV-GL Bladed's array structure (e.g., avrSWAP(2) contains the time variable, always).
For your purposes, I don't think any of these are particularly necessary. You might want to to draw from the structure of DISCON.f90 to understand the order of calls that happens in ROSCO, though.
Cheers,
Nikhar
-
Shubham.Baisthakur
- Posts: 11
- Joined: Thu Jan 07, 2021 11:40 pm
- Organization: Trinity College Dublin
- Location: Ireland
Re: ROSCO-MATLAB Implementation
Hello Nikhar,
Thanks for the reply. Although, there's one more issue.
A part of the ComputeVariablesSetPoint subroutine reads
However, as per the DISCON.IN file, VS_ControlMode can never have a value equal to 3.
Is this a bug or serves some other purpose?
Thanks,
Shubham
Thanks for the reply. Although, there's one more issue.
A part of the ComputeVariablesSetPoint subroutine reads
Code: Select all
! ----- 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 However, as per the DISCON.IN file, VS_ControlMode can never have a value equal to 3.
Code: Select all
1 ! VS_ControlMode - Generator torque control mode in above rated conditions {0: constant torque, 1: constant power, 2: TSR tracking PI control}
Is this a bug or serves some other purpose?
Thanks,
Shubham
-
Nikhar.Abbas
- Posts: 30
- Joined: Wed Apr 29, 2020 7:11 pm
- Organization: National Renewable Energy Lab
- Location: Boulder, CO
Re: ROSCO-MATLAB Implementation
Hi Shubham,
It looks like the descriptors in that DISCON.IN file are out of date - sorry about that. `VS_ControlMode = 3` corresponds to TSR tracking control below rated, and constant power above rated.
The most recent descriptions can be found here:
https://rosco-toolbox.readthedocs.io/en ... on-in-file
The details of this are discussed in the WES pre-print about ROSCO here:
https://wes.copernicus.org/preprints/wes-2021-19/
Cheers,
Nikhar
It looks like the descriptors in that DISCON.IN file are out of date - sorry about that. `VS_ControlMode = 3` corresponds to TSR tracking control below rated, and constant power above rated.
The most recent descriptions can be found here:
https://rosco-toolbox.readthedocs.io/en ... on-in-file
The details of this are discussed in the WES pre-print about ROSCO here:
https://wes.copernicus.org/preprints/wes-2021-19/
Cheers,
Nikhar
-
Shubham.Baisthakur
- Posts: 11
- Joined: Thu Jan 07, 2021 11:40 pm
- Organization: Trinity College Dublin
- Location: Ireland
Re: ROSCO-MATLAB Implementation
Hello Nikhar,
Thanks for the prompt reply. I really appreciate all the help.
Cheers,
Shubham
Thanks for the prompt reply. I really appreciate all the help.
Cheers,
Shubham
-
Shubham.Baisthakur
- Posts: 11
- Joined: Thu Jan 07, 2021 11:40 pm
- Organization: Trinity College Dublin
- Location: Ireland
Re: ROSCO-MATLAB Implementation
Hello Nikhar,
I have attached the code for the PIController function.
As per my understanding, as all the values of the FirstCall array are initialized as 1, the control will never transfer to the second part of the loop (the else part). Is this right, or I am missing some point?
Thanks,
Shubham
I have attached the code for the PIController function.
Code: Select all
REAL FUNCTION PIController(error, kp, ki, minValue, maxValue, DT, I0, reset, inst)
! PI controller, with output saturation
IMPLICIT NONE
! Allocate Inputs
REAL(8), INTENT(IN) :: error
REAL(8), INTENT(IN) :: kp
REAL(8), INTENT(IN) :: ki
REAL(8), INTENT(IN) :: minValue
REAL(8), INTENT(IN) :: maxValue
REAL(8), INTENT(IN) :: DT
INTEGER(4), INTENT(INOUT) :: inst
REAL(8), INTENT(IN) :: I0
LOGICAL, INTENT(IN) :: reset
! Allocate local variables
INTEGER(4) :: i ! Counter for making arrays
REAL(8) :: PTerm ! Proportional term
REAL(8), DIMENSION(99), SAVE :: ITerm = (/ (real(9999.9), i = 1,99) /) ! Integral term, current.
REAL(8), DIMENSION(99), SAVE :: ITermLast = (/ (real(9999.9), i = 1,99) /) ! Integral term, the last time this controller was called. Supports 99 separate instances.
INTEGER(4), DIMENSION(99), SAVE :: FirstCall = (/ (1, i=1,99) /) ! First call of this function?
! Initialize persistent variables/arrays, and set initial condition for integrator term
IF ((FirstCall(inst) == 1) .OR. reset) THEN
ITerm(inst) = I0
ITermLast(inst) = I0
FirstCall(inst) = 0
PIController = I0
ELSE
PTerm = kp*error
ITerm(inst) = ITerm(inst) + DT*ki*error
ITerm(inst) = saturate(ITerm(inst), minValue, maxValue)
PIController = saturate(PTerm + ITerm(inst), minValue, maxValue)
ITermLast(inst) = ITerm(inst)
END IF
inst = inst + 1
END FUNCTION PIControllerAs per my understanding, as all the values of the FirstCall array are initialized as 1, the control will never transfer to the second part of the loop (the else part). Is this right, or I am missing some point?
Thanks,
Shubham
-
Nikhar.Abbas
- Posts: 30
- Joined: Wed Apr 29, 2020 7:11 pm
- Organization: National Renewable Energy Lab
- Location: Boulder, CO
Re: ROSCO-MATLAB Implementation
Hi Shubham,
FirstCall(inst) is set to zero in the first part of the for loop. Because of this, all subsequent calls of the function will go to the second part of the loop unless reset=True.
Nikhar
FirstCall(inst) is set to zero in the first part of the for loop. Because of this, all subsequent calls of the function will go to the second part of the loop unless reset=True.
Nikhar
-
Shubham.Baisthakur
- Posts: 11
- Joined: Thu Jan 07, 2021 11:40 pm
- Organization: Trinity College Dublin
- Location: Ireland
Re: ROSCO-MATLAB Implementation
Hello Nikhar,
Correct me if I am wrong. Here inst is used to access the value of a particular cell of the FirstCall array. Since towards the end of the subroutine, the inst variable is modified as inst = inst+1, so on every to call to the subroutine the inst value will be different. So effectively, everytime we will be checking a different location of the FirstCall array with 1.
Thanks,
Shubham
Correct me if I am wrong. Here inst is used to access the value of a particular cell of the FirstCall array. Since towards the end of the subroutine, the inst variable is modified as inst = inst+1, so on every to call to the subroutine the inst value will be different. So effectively, everytime we will be checking a different location of the FirstCall array with 1.
Thanks,
Shubham
-
Nikhar.Abbas
- Posts: 30
- Joined: Wed Apr 29, 2020 7:11 pm
- Organization: National Renewable Energy Lab
- Location: Boulder, CO
Re: ROSCO-MATLAB Implementation
Hi Shubham,
Each time the controller is called, the SetParameters subroutine is subsequently called. This happens here:
https://github.com/NREL/ROSCO/blob/e53f ... ON.F90#L64
Then, in the SetParameters subroutine, the filter and controller instances are re-set to 1:
https://github.com/NREL/ROSCO/blob/e53f ... s.f90#L512
So, basically, each time the DISCON routine is called, the instance variable is reset to one. This effectively "counts" the order at which the filters, pi-controllers, etc. are called. So, in the PIController function, the `FirstCall` gets filled as many times as the PIController function is called, with each entry corresponding to the order in which it is called. Hopefully this makes sense, it is a little confusing.
This behavior exists because of the way the memory needs to be stored for FORTRAN implementation (and could probably be done in a cleaner way). For your MATLAB implementation, though, I don't think you should do this, as function calls and full routines do not allocate memory in MATLAB in the way that FORTRAN does.
Cheers,
Nikhar
Each time the controller is called, the SetParameters subroutine is subsequently called. This happens here:
https://github.com/NREL/ROSCO/blob/e53f ... ON.F90#L64
Then, in the SetParameters subroutine, the filter and controller instances are re-set to 1:
https://github.com/NREL/ROSCO/blob/e53f ... s.f90#L512
So, basically, each time the DISCON routine is called, the instance variable is reset to one. This effectively "counts" the order at which the filters, pi-controllers, etc. are called. So, in the PIController function, the `FirstCall` gets filled as many times as the PIController function is called, with each entry corresponding to the order in which it is called. Hopefully this makes sense, it is a little confusing.
This behavior exists because of the way the memory needs to be stored for FORTRAN implementation (and could probably be done in a cleaner way). For your MATLAB implementation, though, I don't think you should do this, as function calls and full routines do not allocate memory in MATLAB in the way that FORTRAN does.
Cheers,
Nikhar
Who is online
Users browsing this forum: No registered users and 1 guest