Skip to content

Commit

Permalink
Wind farm power setpoint tracking controller (#29)
Browse files Browse the repository at this point in the history
* rename actuator disk interface for generality with passing power setpoints and enable interface functionality.

* Initial skeleton for power tracking controller.

* first tests added.

* ruff, typos.

* Passing through yaw angles as well (at null value).

* Open-loop setpoint distribution.

* Rename to distributing for this version.'

* References pass through interface; tested."

* placeholder for feedback-based power tracking controller.

* Tracking control loop runs; not yet tested.

* Test proportional control operation.

* Slightly more thorough test.

* Running simulations back to back.

* plotting; use output_file option in input_dict.

* ruff.

* Follow externally-provided reference.

* Upload data files for examples.

* Update tests to reflect external_signals key on hercules_dict.

* Better tuning (after transients.

* Allow proportional gain to be set externally and test that expected behavior results.

* Update documentation.

* Update plots, trajectory.

* Update documentation of example.

* More consistent tracking of hercules time in plot output.

* Update readme.

* Clarify setpoint default unit; comment out code for integral action to avoid confusion.
  • Loading branch information
misi9170 authored Feb 27, 2024
1 parent 729f4b0 commit c979999
Show file tree
Hide file tree
Showing 24 changed files with 1,145 additions and 30 deletions.
11 changes: 8 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ slices
# Data files
*.csv
*.log
examples/*/logstandin
examples/*/loghercules
examples/*/logfloris
examples/*/logstandin*
examples/*/loghercules*
examples/*/logfloris*

# Exceptions
!examples/lookup-based_wake_steering_florisstandin/amr_standin_data.csv
!examples/wind_farm_power_tracking_florisstandin/amr_standin_data.csv
!examples/wind_farm_power_tracking_florisstandin/wind_power_reference_data.csv

# macOS files
.DS_Store
Expand Down
32 changes: 28 additions & 4 deletions docs/controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,39 @@ method of `ControllerBase`.

### LookupBasedWakeSteeringController
Yaw controller that implements wake steering based on a lookup table.
Requires a df_opt object produced by a FLORIS yaw optimization routine. See example
Requires a `df_opt` object produced by a FLORIS yaw optimization routine. See example
lookup-based_wake_steering_florisstandin for example usage.

Currently, yaw angles are set based purely on the (local turbine) wind direction. The lookup table
is sampled at a hardcoded wind speed of 8 m/s. This will be updated in future when an interface is
developed for a simulator that provides wind turbine wind speeds also.

### WakeSteeringROSCOStandin
May be combined into a universal simple wake steeringcontroller.
Not yet developed. May be combined into a universal simple LookupBasedWakeSteeringController.

### HerculesWindBatteryController
TO WRITE
### WindBatteryController
Placeholder for a controller that manages both a wind power plant and colocated
battery.

### WindFarmPowerDistributingController

Wind farm-level power controller that simply distributes a farm-level power
reference between wind turbines evenly, without checking whether turbines are
able to produce power at the requested level. Not expected to perform well when
wind turbines are waked or cannot produce the desired power for other reasons.
However, is a useful comparison case for the WindFarmPowerTrackingController
(described below).

### WindFarmPowerTrackingController

Closed-loop wind farm-level power controller that distributes a farm-level
power reference among the wind turbines in a farm and adjusts the requests made
from each turbine depending on whether the power reference has been met.
Developed under the [A2e2g project](https://github.com/NREL/a2e2g), with
further details provided in
[Sinner et al.](https://pubs.aip.org/aip/jrse/article/15/5/053304/2913100).

Integral action, as well as gain scheduling based on turbine saturation, has been disabled as
simple proportional control appears sufficient currently. However, these may be enabled at a
later date if needed. The `proportional_gain` for the controller may be provided on instantiation,
and defaults to `proportional_gain = 1`.
18 changes: 17 additions & 1 deletion docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ of certain controllers and interfaces.
### lookup-based_wake_steering_florisstandin
2-turbine example of lookup-based wake steering control, run using Hercules with the FLORIS standin
in place of AMR-Wind for exposition purposes. To run this example, navigate to the
examples/lookup-based_wake_steering_florisstandin and then run the following.
examples/lookup-based_wake_steering_florisstandin folder and then run the following.
```
python construct_yaw_offsets.py
```
Expand All @@ -32,4 +32,20 @@ python plot_output_data.py
This should produce the following plot.
![Results of lookup-based_wake_steering_florisstandin example](
graphics/lookup-table-example-plot.png
)

## wind_farm_power_tracking_florisstandin
2-turbine example of wind-farm-level power reference tracking, run using Hercules with the FLORIS
standin in place of AMR-Wind for exposition purposes. To run this example, navigate to the
examples/wind_farm_power_tracking_florisstandin folder and run the following:
```
./bash_script.sh
```

This will run both a closed-loop controller, which compensates for underproduction at individual
turbines, and an open-loop controller, which simply distributes the farm-wide reference evenly
amongst the turbines of the farm without feedback. The resulting trajectories are plotted,
producing:
![Results of wind_farm_power_tracking_florisstandin example](
graphics/wf-power-tracking-plot.png
)
Binary file added docs/graphics/wf-power-tracking-plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions docs/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ These methods will all be called in the `step()` method of `ControllerBase`.

## Available interfaces

### HerculesADYawInterface
### HerculesADInterface
For direct python communication with Hercules. This should be instantiated
in a runscript that is running Hercules; used to generate a `controller` from
the WHOC controllers submodule; and that `controller` should be passed to the
Hercules `Emulator` upon its instantiation.
Hercules `Emulator` upon its instantiation. Support transmitting yaw angles
and power setpoints to wind turbines.

### ROSCO_ZMQInterface
For sending and receiving communications from one or more ROSCO instances
Expand Down
201 changes: 201 additions & 0 deletions examples/lookup-based_wake_steering_florisstandin/amr_standin_data.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
,time,amr_wind_speed,amr_wind_direction
0,0.0,8.0,260.0
1,0.5,8.0,260.0
2,1.0,8.0,260.0
3,1.5,8.0,260.0
4,2.0,8.0,260.0
5,2.5,8.0,260.0
6,3.0,8.0,260.0
7,3.5,8.0,260.0
8,4.0,8.0,260.0
9,4.5,8.0,260.0
10,5.0,8.0,260.0
11,5.5,8.0,260.0
12,6.0,8.0,260.0
13,6.5,8.0,260.0
14,7.0,8.0,260.0
15,7.5,8.0,260.0
16,8.0,8.0,260.0
17,8.5,8.0,260.0
18,9.0,8.0,260.0
19,9.5,8.0,260.0
20,10.0,8.0,260.0
21,10.5,8.0,260.0
22,11.0,8.0,260.0
23,11.5,8.0,260.0
24,12.0,8.0,260.0
25,12.5,8.0,260.0
26,13.0,8.0,260.0
27,13.5,8.0,260.0
28,14.0,8.0,260.0
29,14.5,8.0,260.0
30,15.0,8.0,260.0
31,15.5,8.0,260.0
32,16.0,8.0,260.0
33,16.5,8.0,260.0
34,17.0,8.0,260.0
35,17.5,8.0,260.0
36,18.0,8.0,260.0
37,18.5,8.0,260.0
38,19.0,8.0,260.0
39,19.5,8.0,260.0
40,20.0,8.0,260.0
41,20.5,8.0,260.0
42,21.0,8.0,260.0
43,21.5,8.0,260.0
44,22.0,8.0,260.0
45,22.5,8.0,260.0
46,23.0,8.0,260.0
47,23.5,8.0,260.0
48,24.0,8.0,260.0
49,24.5,8.0,260.0
50,25.0,8.0,260.0
51,25.5,8.0,260.0
52,26.0,8.0,260.0
53,26.5,8.0,260.0
54,27.0,8.0,260.0
55,27.5,8.0,260.0
56,28.0,8.0,260.0
57,28.5,8.0,260.0
58,29.0,8.0,260.0
59,29.5,8.0,260.0
60,30.0,8.0,260.0
61,30.5,8.0,260.126582278481
62,31.0,8.0,260.253164556962
63,31.5,8.0,260.37974683544303
64,32.0,8.0,260.50632911392404
65,32.5,8.0,260.63291139240505
66,33.0,8.0,260.75949367088606
67,33.5,8.0,260.88607594936707
68,34.0,8.0,261.0126582278481
69,34.5,8.0,261.1392405063291
70,35.0,8.0,261.26582278481015
71,35.5,8.0,261.39240506329116
72,36.0,8.0,261.5189873417722
73,36.5,8.0,261.6455696202532
74,37.0,8.0,261.7721518987342
75,37.5,8.0,261.8987341772152
76,38.0,8.0,262.0253164556962
77,38.5,8.0,262.1518987341772
78,39.0,8.0,262.27848101265823
79,39.5,8.0,262.40506329113924
80,40.0,8.0,262.53164556962025
81,40.5,8.0,262.65822784810126
82,41.0,8.0,262.7848101265823
83,41.5,8.0,262.9113924050633
84,42.0,8.0,263.0379746835443
85,42.5,8.0,263.1645569620253
86,43.0,8.0,263.2911392405063
87,43.5,8.0,263.4177215189873
88,44.0,8.0,263.54430379746833
89,44.5,8.0,263.67088607594934
90,45.0,8.0,263.7974683544304
91,45.5,8.0,263.9240506329114
92,46.0,8.0,264.0506329113924
93,46.5,8.0,264.17721518987344
94,47.0,8.0,264.30379746835445
95,47.5,8.0,264.43037974683546
96,48.0,8.0,264.55696202531647
97,48.5,8.0,264.6835443037975
98,49.0,8.0,264.8101265822785
99,49.5,8.0,264.9367088607595
100,50.0,8.0,265.0632911392405
101,50.5,8.0,265.1898734177215
102,51.0,8.0,265.3164556962025
103,51.5,8.0,265.44303797468353
104,52.0,8.0,265.56962025316454
105,52.5,8.0,265.69620253164555
106,53.0,8.0,265.82278481012656
107,53.5,8.0,265.9493670886076
108,54.0,8.0,266.0759493670886
109,54.5,8.0,266.2025316455696
110,55.0,8.0,266.32911392405066
111,55.5,8.0,266.45569620253167
112,56.0,8.0,266.5822784810127
113,56.5,8.0,266.7088607594937
114,57.0,8.0,266.8354430379747
115,57.5,8.0,266.9620253164557
116,58.0,8.0,267.0886075949367
117,58.5,8.0,267.2151898734177
118,59.0,8.0,267.34177215189874
119,59.5,8.0,267.46835443037975
120,60.0,8.0,267.59493670886076
121,60.5,8.0,267.72151898734177
122,61.0,8.0,267.8481012658228
123,61.5,8.0,267.9746835443038
124,62.0,8.0,268.1012658227848
125,62.5,8.0,268.2278481012658
126,63.0,8.0,268.3544303797468
127,63.5,8.0,268.4810126582278
128,64.0,8.0,268.60759493670884
129,64.5,8.0,268.7341772151899
130,65.0,8.0,268.8607594936709
131,65.5,8.0,268.9873417721519
132,66.0,8.0,269.11392405063293
133,66.5,8.0,269.24050632911394
134,67.0,8.0,269.36708860759495
135,67.5,8.0,269.49367088607596
136,68.0,8.0,269.62025316455697
137,68.5,8.0,269.746835443038
138,69.0,8.0,269.873417721519
139,69.5,8.0,270.0
140,70.0,8.0,278.8202617298383
141,70.5,8.0,272.00078604183614
142,71.0,8.0,274.8936899205287
143,71.5,8.0,281.2044659960073
144,72.0,8.0,279.3377899507498
145,72.5,8.0,265.11361060061796
146,73.0,8.0,274.75044208762796
147,73.5,8.0,269.2432139585115
148,74.0,8.0,269.48390574103223
149,74.5,8.0,272.0529925096919
150,75.0,8.0,270.7202178558044
151,75.5,8.0,277.2713675348149
152,76.0,8.0,273.80518862573496
153,76.5,8.0,270.60837508246414
154,77.0,8.0,272.2193161637271
155,77.5,8.0,271.6683716368713
156,78.0,8.0,277.470395365788
157,78.5,8.0,268.974208681171
158,79.0,8.0,271.5653385082545
159,79.5,8.0,265.72952130349137
160,80.0,8.0,257.2350509208296
161,80.5,8.0,273.26809297720183
162,81.0,8.0,274.3221809942975
163,81.5,8.0,266.28917489796777
164,82.0,8.0,281.348773119938
165,82.5,8.0,262.7281716270062
166,83.0,8.0,270.2287925865072
167,83.5,8.0,269.0640807498708
168,84.0,8.0,277.6638960717923
169,84.5,8.0,277.3467938495014
170,85.0,8.0,270.77473712848456
171,85.5,8.0,271.8908125980109
172,86.0,8.0,265.56107126184946
173,86.5,8.0,260.0960176588804
174,87.0,8.0,268.2604392533692
175,87.5,8.0,270.7817448455199
176,88.0,8.0,276.1514534036386
177,88.5,8.0,276.0118992439221
178,89.0,8.0,268.06336591296025
179,89.5,8.0,268.4884862471233
180,90.0,8.0,264.7572351746645
181,90.5,8.0,262.8999103141051
182,91.0,8.0,261.46864904687493
183,91.5,8.0,279.75387697615895
184,92.0,8.0,267.45173909124173
185,92.5,8.0,267.80962849194407
186,93.0,8.0,263.7360231997504
187,93.5,8.0,273.88745177915956
188,94.0,8.0,261.93051076221025
189,94.5,8.0,268.93629859893014
190,95.0,8.0,265.5226671940316
191,95.5,8.0,271.9345124892963
192,96.0,8.0,267.4459743121556
193,96.5,8.0,264.09683907938796
194,97.0,8.0,269.85908885830673
195,97.5,8.0,272.1416593526521
196,98.0,8.0,270.3325861119158
197,98.5,8.0,271.5123594886989
198,99.0,8.0,266.8283895315952
199,99.5,8.0,268.1862941700643
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
from hercules.py_sims import PySims
from hercules.utilities import load_yaml
from whoc.controllers.lookup_based_wake_steering_controller import LookupBasedWakeSteeringController
from whoc.interfaces.hercules_actuator_disk_yaw_interface import HerculesADYawInterface
from whoc.interfaces.hercules_actuator_disk_interface import HerculesADInterface

input_dict = load_yaml(sys.argv[1])

# Load the optimal yaw angle lookup table for controller us
df_opt = pd.read_pickle("yaw_offsets.pkl")

interface = HerculesADYawInterface(input_dict)
interface = HerculesADInterface(input_dict)
controller = LookupBasedWakeSteeringController(interface, input_dict, df_yaw=df_opt)

py_sims = PySims(input_dict)
Expand Down
Loading

0 comments on commit c979999

Please sign in to comment.