Wind Turbine Blade Optimization
This example shows how to adjust the twist and chord length along a wind turbine blade to optimize power output. It combines a Simscape™ Driveline™ test harness model with the fminsearch
optimization function. The wind turbine model uses blade element momentum (BEM) theory, including wake rotation. By putting the test harness into Fast Restart, you can enable rapid optimization iterations. In this case, the optimization increases the power output from 4.3 MW to 5.9 MW. Other products available for performing this type of optimization with Simscape Driveline models include the Optimization Toolbox™ and Simulink® Design Optimization™. These products provide predefined functions to manipulate and analyze blocks using either GUIs or a command line approach.
Create the Test Harness
model = 'WindTurbineBladeOptimization';
open_system(model);
The test harness applies a steady wind speed and maintains the collective blade pitch at 0 deg. To expedite iterations, the model excludes the rotor inertia and a more detailed driveline. The Velocity Source absorbs the generated power. For numerical robustness when iterating over parameters in the relatively stiff test harness, the rotor starts from rest and gradually ramps up to the target rotor speed over 5 seconds. Fast Restart mode avoids recompiling the model between iterations, further speeding up the optimization process. The Wind Turbine block outputs a thrust measurement, while sensors measure the rotor speed and power.
Define Fixed Parameters
This example sets the turbine diameter at 126 meters, rated wind speed at 11.4 m/s, and target tip speed ratio at 7. The tip speed ratio is defined as
where:
is the rotor radius.
is the rotor angular velocity.
is the incident air velocity.
Design.rotorDiameter = 126; % [m] Design.rotorRadius = Design.rotorDiameter / 2; % [m] Design.TSRtarget = 7; % [-] Harness.windSpeed = 11.4; % [m/s] Harness.rotorSpeed = Design.TSRtarget * Harness.windSpeed / Design.rotorRadius * 60/(2*pi); % [rpm]
This example also fixes the air foil type distribution along the blades. The distribution is based on the report by Jason Jonkman, “Definition of a 5-MW Reference Wind Turbine for Offshore System Development.” National Renewable Energy Lab (NREL), Golden, CO (United States), No. NREL/TP-500-38060 (2009). This airfoil distribution matches the default parameters of the Wind Turbine block.
Radial Location Normalized by Rotor Radius | Airfoil Name |
0.11 | Round root with Cd = 0.35 |
0.17 | DU40 airfoil with aspect ratio of 17 |
0.23 | DU35 airfoil with aspect ratio of 17 |
0.37 | DU30 airfoil with aspect ratio of 17 |
0.5 | DU25 airfoil with aspect ratio of 17 |
0.63 | DU21 airfoil with aspect ratio of 17 |
1 | NACA64 airfoil with aspect ratio of 17 |
Retrieve and plot the block's airfoil data.
blk = [model '/Wind Turbine']; Data.radius_TLU = eval( get_param(blk, 'radial_TLU') ) * Design.rotorRadius; % [m] Data.alpha_TLU = eval( get_param(blk, 'alpha_TLU') ); % [deg] Data.Cl_TLU = eval( get_param(blk, 'Cl_TLU') ); % [-] Data.Cd_TLU = eval( get_param(blk, 'Cd_TLU') ); % [-] figure; plot(Data.alpha_TLU, Data.Cl_TLU); title('Lift Coefficient versus Angle of Attack') xlabel('\alpha') ylabel('C_l') legend('Round root', 'DU40', 'DU35', 'DU30', 'DU25', 'DU21', 'NACA64');
figure; plot(Data.alpha_TLU, Data.Cd_TLU); title('Drag Coefficient versus Angle of Attack') xlabel('\alpha') ylabel('C_d') legend('Round root', 'DU40', 'DU35', 'DU30', 'DU25', 'DU21', 'NACA64')
Calculate Initial Values for Twist and Chord Length
For an ideal blade without wake rotation or drag, the optimal twist and chord length along the blades is
where
is the radial location.
is the speed ratio at the radial location.
is the optimal angle of relative wind.
is the optimal twist.
is the angle of attack where Cd/Cl is minimal.
is the lift coefficient at the optimal angle of attack.
is the optimal chord length.
is the number of blades in the rotor.
These expressions are derived in Manwell, J. F., J. G. McGowan, and A. L. Rogers. Wind Energy Explained: Theory, Design and Application. 1st ed. Wiley. 2009.
For the chosen airfoils, the ratio of drag coefficient to lift coefficient (Cd/Cl) is minimal at an angle of attack of 10 deg. This example optimizes the blade chord length and twist angle at six radial locations. To ensure a smooth aerodynamic surface and maintain structural integrity, the optimization constrains all chord lengths to be between 1.5 and 5 meters and limits the change in twist between radial sections to less than 5 deg.
Calculate and plot the initial values for twist and chord length along the blades.
Opt.Init.alpha = 10 * pi / 180; % Initial value for angle of attack [rad] Design.B = 3; % Number of blades [-] Opt.numRadialLocationsToOptimize = 6; % Number of radial sections to optimize % Initialize vectors Opt.Init.twist = zeros(1, Opt.numRadialLocationsToOptimize); % Vector of initial value for twist [deg] Opt.Init.chord = zeros(1, Opt.numRadialLocationsToOptimize); % Vector of initial value for chord length [m] for i=1:Opt.numRadialLocationsToOptimize Opt.Init.r = Data.radius_TLU(i+1); Opt.Init.lambda_r = Design.TSRtarget * Opt.Init.r / Design.rotorRadius; % Local tip speed ratio [-] Opt.Init.phi = atan(2 / (3 * Opt.Init.lambda_r) ); % Angle of relative twist [rad] Opt.Init.twist(i) = 180 / pi * (Opt.Init.phi - Opt.Init.alpha); % [deg] Opt.Init.Cl = interp1(Data.alpha_TLU, Data.Cl_TLU(:,i), Opt.Init.alpha); % Lift coefficient [-] Opt.Init.chord(i) = 8 * pi * Opt.Init.r * sin(Opt.Init.phi) / (Design.B * Opt.Init.Cl * 3 * Opt.Init.lambda_r); % [m] end % Set twist at round root equal to neighboring twist Opt.Init.twist = [Opt.Init.twist(1) Opt.Init.twist]; % Adjust twist based on maximum permitted change in twist between radial sections Design.twistMaxDiff = 5; % Maximum permitted change in twist between radial sections [deg] for i = 2:length(Opt.Init.twist) if Opt.Init.twist(i) > Opt.Init.twist(i-1) + Design.twistMaxDiff Opt.Init.twist(i) = Opt.Init.twist(i-1) + Design.twistMaxDiff; elseif Opt.Init.twist(i) < Opt.Init.twist(i-1) - Design.twistMaxDiff Opt.Init.twist(i) = Opt.Init.twist(i-1) - Design.twistMaxDiff; end end % Limits to chord Design.chordMax = 5; % Maximum permitted chord length [m] Design.chordMin = 1.5; % Minimum permitted chord length [m] % Assign maximum permitted chord to the root Opt.Init.chord = [Design.chordMax Opt.Init.chord]; % Limit the chord lengths Opt.Init.chord(Opt.Init.chord > Design.chordMax) = Design.chordMax; Opt.Init.chord(Opt.Init.chord < Design.chordMin) = Design.chordMin; % Plot the initial twist and chord lengths figure; plot(Data.radius_TLU, Opt.Init.twist); ylabel('Twist (deg)'); xlabel('Radius (m)'); title('Initial Blade Twist');
figure; plot(Data.radius_TLU, Opt.Init.chord); ylabel('Chord Length (m)'); xlabel('Radius (m)'); title('Initial Blade Chord Lengths');
Run the Optimization
Since blade element momentum theory does not include a radial component of fluid flow, airflow through each radial section is independent. This allows twist and chord length at each section to be optimized independently. To expedite the optimization process, this example optimizes the twist and chord length of all sections simultaneously. To further speed up the optimization, the model uses Fast Restart mode and the Wind Turbine Blade twist vector, θ_tw(r) and Normalized chord length vector, c(r)/R are run-time parameters. These settings enable optimization iterations to vary the parameter values without recompiling the model.
The function WindTurbineBladeOptimizationRun
defines an objective function. This function runs the test harness and uses the negative of the simulated power as the optimization cost. The fminsearch
function tries to minimize the cost, thereby maximizing the wind turbine power. WindTurbineBladeOptimizationRun
also limits the change in twist between radial sections and limits the chord length to be between the chosen minimum and maximum values.
The plot below updates during the optimization. The function value represents the negated power value in units of MW at each optimization iteration. The plot shows that the initial power is 4.3 MW and the optimized power reaches 5.9 MW after 60 iterations.
Run the optimization.
set_param(model,'FastRestart','on') % Call the Optimization functions [Opt.Final.twist, Opt.Final.chord] = WindTurbineBladeOptimizationRun... (Opt.Init.twist, Opt.Init.chord, Design.twistMaxDiff, Design.chordMin, Design.chordMax, model);
Plot the Optimized Values of Twist and Chord Length
Plot the optimized values of twist and chord length along the blade. Compare these optimized values to the initial values. The optimized blade twist is higher than the initial blade twist. The optimized chord length is smaller than the initial chord length at larger radius locations.
figure; plot(Data.radius_TLU, Opt.Init.twist, Data.radius_TLU, Opt.Final.twist); ylabel('Twist (deg)'); xlabel('Radius (m)'); legend('Initial', 'Optimized') title('Blade Twist');
figure; plot(Data.radius_TLU, Opt.Init.chord, Data.radius_TLU, Opt.Final.chord); ylabel('Chord Length (m)'); xlabel('Radius (m)'); legend('Initial', 'Optimized') title('Blade Chord Length');
Generate Power and Thrust Coefficient Plots
Use the test harness to generate plots of power and thrust coefficient versus tip speed ratio. This allows you to compare the wind turbine performance before and after the optimization. The nondimensional power and thrust coefficients are
where:
is the power coefficient.
is the thrust coefficient.
is the generated power.
is the generated thrust.
is the air density.
is the swept rotor area.
is the incident air velocity.
The test harness outputs instantaneous power, thrust and rotor speed. Adjust the harness's steady rotor speed to simulate the wind turbine's behavior at higher tip speed ratios. The generated figures show that the optimized wind turbine has a higher power coefficient and lower thrust coefficient for all tip speed ratios.
Harness.rotorSpeed = 2 * Design.TSRtarget * Harness.windSpeed / Design.rotorRadius * 60/(2*pi); % [rpm] rho = eval( get_param(blk, 'rho_air') ); % Air density [kg/m^3] Area = pi * Design.rotorRadius^2; % Rotor swept area [m^2] % Generate data for initial twist and chord lengths twist = Opt.Init.twist; chord = Opt.Init.chord; out= sim(model); Opt.Init.power = out.yout(:,1); % [MW] Opt.Init.thrust = out.yout(:,2); % [kN] Opt.Init.rotorSpeed = out.yout(:,3) * 2 * pi / 60; % [rad/s] Opt.Init.Cp = Opt.Init.power * 10^6 / (0.5 * rho * Area * Harness.windSpeed^3); Opt.Init.Ct = Opt.Init.thrust * 10^3 / (0.5 * rho * Area * Harness.windSpeed^2); Opt.Init.TSR = Design.rotorRadius * Opt.Init.rotorSpeed / Harness.windSpeed; % Generate data for optimized twist and chord lengths twist = Opt.Final.twist; chord = Opt.Final.chord; out= sim(model); Opt.Final.power = out.yout(:,1); % [MW] Opt.Final.thrust = out.yout(:,2); % [kN] Opt.Final.rotorSpeed = out.yout(:,3) * 2 * pi / 60; % [rad/s] Opt.Final.Cp = Opt.Final.power * 10^6 / (0.5 * rho * Area * Harness.windSpeed^3); Opt.Final.Ct = Opt.Final.thrust * 10^3 / (0.5 * rho * Area * Harness.windSpeed^2); Opt.Final.TSR = Design.rotorRadius * Opt.Final.rotorSpeed / Harness.windSpeed; figure; plot(Opt.Init.TSR, Opt.Init.Cp, Opt.Final.TSR, Opt.Final.Cp); xlabel('Tip Speed Ratio') ylabel('C_P') legend('Initial', 'Optimized');
figure; plot(Opt.Init.TSR, Opt.Init.Ct, Opt.Final.TSR, Opt.Final.Ct); xlabel('Tip Speed Ratio') ylabel('C_T') legend('Initial', 'Optimized');