Java Based Controller Interface The Java based controller interface enable users to implement their own external wind turbine control systems. At the interface level, the control system must be a class which implements the interface no.sintef.ocean.control.wind.WindTurbineController. This interface is located in the jar-file HLALib.jar which is provided in the SIMA, SIMO or RIFLEX installation package. See the example below for details on how to locate this file and to compile a controller. Excluding control logic, the overall layout of the control system class will typically look like this: package my.external.controller; import no.sintef.ocean.control.wind.Feedback; import no.sintef.ocean.control.wind.Measurements; import no.sintef.ocean.control.wind.Parameters; import no.sintef.ocean.control.wind.WindTurbineController; public class ExternalWindTurbineController implements WindTurbineController { @Override public void init(Parameters parameters) { // ... } @Override public void step(Measurements measurements, Feedback feedback) { // ... } @Override public void finish() { // ... } } The three methods that need to be implemented are: void init(Parameters parameters) This method is invoked once before the simulation starts. It takes a single argument of type Parameters which contains methods for retrieving data that does not change during the simulation. void step(Measurements measurements, Feedback feedback) This method is invoked once for each time step in the simulation and is expected to provide setpoints for generator torque, blade pitch and - if configured - yaw angle for the turbine by calling the relevant methods on the Feedback argument. Current measurement signals are provided in the Measurements argument. void finish() This method is called once at the end of the simulation. It can for example be used to close any log files opened by the controller. 1. Parameters Interface These values are provided to the controller during initialization and does not change during the simulation. /** * The values provided by this interface are passed to the controller during * initialization and does not change during the simulation */ public interface Parameters { /** * @return the name of the wind turbine which this controller is attached to */ String getTurbineName(); /** * @return the sample time this controller will be stepped with */ double getSampleTime(); /** * @return the configuration string associated with this controller. Often, * this will be the filepath to a configuration file. */ String getConfigurationString(); /** * @return the number of turbine blades on the turbine controlled by this * controller */ int getNumBlades(); } 2. Measurements Interface This interface is used by the control system to retrieve data about the current state of the simulation. /** * Measurements of turbine properties. * * For a RIFLEX wind turbine the shaft measurement system is used for the hub * position, velocity and acceleration measurements and may be chosen for the * additional nodal measurements. This coordinate system is determined from the * stress-free orientation of the shaft element where the electrical torque is * applied: * - the local z-axis is vertical, * - the local x-is the horizontal projection of the element’s x axis * - the local y-axis is oriented so that the x-, y- and z-axes are a * right-handed coordinate system (i.e. the y-axis is the vector cross * product of the local z- and x-aces) * * If the stress-free orientation of the shaft is in the global X-Z plane, the * shaft measurement coordinate system will coincide with the global coordinate * system. * * NOTE: For a RIFLEX wind turbine it is not recommended to use the exported * accelerations directly in an external wind turbine controller. Instead, the * external controller should itself derive an improved estimate of the * accelerations based on the displacement values from several time steps. The * inaccuracies are a result of the Newton-Raphson iteration methods used in * the time domain simulation. */ public interface Measurements { /** * @return current rotational speed of rotor [rad/T] */ public double getOmega(); /** * @return blade pitch angle in radians for blade number i [rad] * @param i blade number to get pitch angle for, starting at 0 */ public double getPitchAngle(int i); /** * @return blade root bending moment about local x-axis for blade number * i [F*L] * @param i blade number to get pitch angle for, starting at 0 */ public double getBladeRootBMX(int i); /** * @return blade root bending moment about local y-axis for blade number * i [F*L] * @param i blade number to get pitch angle for, starting at 0 */ public double getBladeRootBMY(int i); /** * @return blade root bending moment about local z-axis for blade number * i [F*L] * @param i blade number to get pitch angle for, starting at 0 */ public double getBladeRootBMZ(int i); /** * @return blade root aerodynamic torque for blade number i [F*L] * @param i blade number to get pitch angle for, starting at 0 */ public double getBladeRootAeroTor(int i); /** * For a RIFLEX wind turbine: * Returns dynamic displacement and rotation from final static * position / orientation for the node at the second end of the shaft * flex-joint. Values are in the shaft measurement system is used. * * For a SIMO wind turbine: * Returns the global position of the hub body. * * @return turbine position including translations [L] and rotations [rad] */ public double[] getPosition(); /** * For a RIFLEX wind turbine: * Returns velocity for the node at the second end of the shaft flex-joint. * Values are in the shaft measurement system. * * For a SIMO wind turbine: * Returns the hub velocity in the body-local coordinate system * * @return turbine velocity including translations [L/T] and * rotations [rad/T] */ public double[] getVelocity(); /** * For a RIFLEX wind turbine: * Returns accelerations for the node at the second end of the shaft * flex-joint. Values are in the shaft measurement system. Please see the * warning above regarding the low accuracy of the exported accelerations. * * For a SIMO wind turbine: * Currently not used. * * @return turbine accelerations including translations [L/T^2] and * rotations [rad/T^2] */ public double[] getAcceleration(); /** * @return three component hub wind velocity given in the global coordinate * system */ public double[] getHubWindVelocity(); /** * @return number of nodes with additional measurements */ public int getNnodMeas(); /** * For a RIFLEX wind turbine: * Returns nodal measurements for measurement i. 18 values for each node: * - 3 displacements [L]. * - 3 rotations relative to the stress-free configuration [rad]. * - 6 velocities [L/T] or [rad/T]. * - 6 accelerations [L/T^2] or [rad/T^2]. The rotations (R1,R2,R3) are * taken in the order R3, R2, R1 ; i.e. first rotation around the * global z-axis, then around the local (rotated) y-axis and then * finally around the local (rotated) x-axis. Global or shaft * measurement system as selected by input. * Please see the warning above regarding the low accuracy of the exported * accelerations. * * For a SIMO wind turbine: * Currently not used. * * @return additional measurements for node measurement i * (0, 1, ... nnodMeas-1) */ public double[] getAddNodeMeas (int i); /** * @return number of elements with additional measurements */ public int getNelMeas(); /** * For a RIFLEX wind turbine: * Returns element measurements for the specified measurement i. 10 values * for each element, all given in the local element system: * - Effective tension [F] * - Torsional moment [FL] * - My-moment end 1 and 2 [FL] * - Mz-moment end 1 and 2 [FL] * - Qy-shear force end 1 and 2 [F] * - Qz-shear force end 1 and 2 [F] * * For a SIMO wind turbine: * Currently not used. * @return additional measurements for element measurement i * (0, 1, ... nelMeas-1) */ public double[] getAddNelMeas (int i); /** * @return the current yaw misalignment. Angle between shaft direction and * wind direction in shaft system local xy-plane. Seen from above, * the positive direction is counter-clockwise. [rad] */ public double getYawErr(); /** * @return the Azimuth angle.The angular position of blade 1 [rad], * where 0 is with blade 1 pointing upwards. */ public double getAzimuthAngle(); } 3. Feedback Interface This interface is used by the control system to return values to the simulation. For each method setting a value there’s a corresponding get-method which will return the current value. /** * This interface is used by the control system to return values to the * simulation. For each method setting a value there's a corresponding * get-method which will return the current value. */ public interface Feedback { /** * Set the torque reference * @param value torque reference */ public void setTorqueReference(double value); /** * @return the current torque reference */ public double getTorqueReference(); /** * Set pitch angle reference for blade i * @param i blade number, starting at 0 for the first blade * @param value pitch angle reference */ public void setPitchAngleReference(int i, double value); /** * @return the current pitch angle reference for blade i * @param i blade number, starting at 0 for the first blade */ public double getPitchAngleReference(int i); /** * Set gear shaft rotational speed for result presentation * @param value gear shaft rotational speed */ public void setGearShaftOmega(double value); /** * @return the current gear shaft rotational speed */ public double getGearShaftOmega(); /** * Set generated power for result presentation * @param value generated power */ public void setGeneratedPower(double value); /** * @return the current generated power */ public double getGeneratedPower(); /** * Set the current yaw control feedback [rad/s] * @param value current yaw control feedback */ public void setYawCntrl(double value); /** * @return the current yaw control feedback [rad/s] */ public double getYawCntrl(); } 4. Errors in the Control System If an error occurs in the control system and the control system is unable to proceed with the simulation it should throw an exception. Note that the exception need to be an unchecked exception. The easiest is to use RuntimeException, for example: throw new RuntimeException("Provide a message explaining what went wrong here"); 5. Compiling an External Control System Before an external control system can be used in a simulation the source file(s) need to be compiled into a .jar-file. There are multiple methods of doing this, but in any case a Java Development Kit (JDK) must be installed first. See the section below for an example on how to do this using the Eclipse IDE. The interfaces used by the control system is located in the file HLALib.jar which is located inside the SIMA, SIMO, or RIFLEX installation: For a SIMA installation it is located in <path to SIMA>\plugins\no.marintkek.sima.hla.lib_<version number>\lib\HLAlib.jar, where <path to SIMA> is the installation location of SIMA on the computer and <version number> is a unique version number which changes with each SIMA version. For a SIMO/RIFLEX standalone installation it is located in the installation folder on the same level as the Simo and/or Riflex folders. 6. Using other (non-Java) External Control Systems Other controllers compiled to a shared libray (DLL) may be used. To use such a control system in SIMA, a Java control system must be implemented which in turn uses functions from the shared library to do the actual computations. Functions from a shared library can be accessed from Java by utilizing Java Native Access (JNA). See https://github.com/java-native-access/jna for more details. 7. Migrating From The Old Controller Interface Starting with SIMA version 4.3.0 (SIMO and RIFLEX version 4.24.0) the Java controller interface has changed compared to previous versions. New features will now be added to this interface and not the old. Old control systems will continue to work, but if you are making changes to a control system it is recommended to update to the new interface. The changes required are minor and is described below. Excluding the actual control logic, an external control system using the old interface will generally look like this: package my.external.controller; import no.marintek.wind.control.Feedback; import no.marintek.wind.control.IController; import no.marintek.wind.control.Measurements; public class ExternalWindTurbineController implements IController { @Override public void init(double dt, int nblades, String config) { // ... } @Override public void step(Measurements measurements, Feedback feedback) { // ... } @Override public void finish() { // ... } } With the new interfaces, the control system should now look like this: package my.external.controller; import no.sintef.ocean.control.wind.Feedback; (1) import no.sintef.ocean.control.wind.Measurements; import no.sintef.ocean.control.wind.Parameters; (2) import no.sintef.ocean.control.wind.WindTurbineController; (3) public class ExternalWindTurbineController implements WindTurbineController { (4) @Override public void init(Parameters parameters) { (5) double dt = parameters.getSampleTime(); (6) int nblades = parameters.getNumBlades(); String config = parameters.getConfigurationString(); // ... } @Override public void step(Measurements measurements, Feedback feedback) { // ... } @Override public void finish() { // ... } } The changes are: 1 Package name in imports are changed from no.marintek.wind.control to no.sintef.ocean.control.wind 2 An import of no.sintef.ocean.control.wind.Parameters is added 3 The import of no.marintek.wind.control.IController is changed to no.sintef.ocean.control.wind.WindTurbineController 4 The controller class now implements WindTurbineController instead of IController 5 The init method now takes a single argument, Parameters parameters 6 The old arguments dt, nblades and config can now be retrieved by method calls on parameters 7.1. Example: Compiling Using the Eclipse IDE Eclipse is an Integrated Development Environment (IDE) for Java and can be downloaded here: https://www.eclipse.org/eclipseide/. This example will go through compiling the source code for the control system used in the example Floating Wind Turbine with External Controller. It is also possible to use other IDEs like IntelliJ IDEA or to compile the code directly using the Java compiler. When loading the example, the source code for the control system is loaded in the Storage Task along with the model. To load the RIFLEX model and the source code, go to Help → Examples → Wind Turbine → Floating Wind Turbine with External Controller. The source code is located in source folder in the Storage Task WindTurbineExternalControlSystem. Right-click on the Storage Task and choose explore to see where the files are located on the computer. Start Eclipse and import the control system source code into Eclipse by going to File → Import → General → Existing Projects into Workspace. Browse to the location of the source folder in the Storage Task with the example. Set up external libraries for the project by right-clicking on it in the Eclipse project explorer (left hand panel) and go to Build Path → Configure Build Path. Under _Libraries, choose Classpath and click on Add external JARs. Locate the file HLALib.jar which is supplied with the SIMA installation. In the same window, go to Java Compiler, select Enable project specific settings and set Compiler compliance level to 1.8. In order to use the control system in SIMA it must first be compiled into a jar-file. Right click on the project and choose Export → JAR file. Choose a name and location of the jar-file and click finish. If the export was successful you now have a control system jar-file which can be used in SIMA. Every time changes are made to the external control system source code, step 4 need to be repeated. In SIMA, find the wind turbine inside the task WindTurbineWithExternalControlSystem by going to Model → Slender System → Wind turbines and open the controller tab. Check the external option. In the Jar File field, locate the jar-file created from Eclipse. The Class Name must be chosen from the dropdown menu. In the field Configuration it is possible to give a text file with input to the control system. The path to this file is passed to the init-method external control system. It is up to the external control system to define and read the contents of this file. Generic Internal Controller External Bladed Style Controller