create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / models / wind / PinkNoiseWindModel.java
1 package net.sf.openrocket.models.wind;\r
2 \r
3 import java.util.Random;\r
4 \r
5 import net.sf.openrocket.util.Coordinate;\r
6 import net.sf.openrocket.util.MathUtil;\r
7 import net.sf.openrocket.util.PinkNoise;\r
8 \r
9 /**\r
10  * A wind simulator that generates wind speed as pink noise from a specified average wind speed\r
11  * and standard deviance.  Currently the wind is always directed in the direction of the negative\r
12  * X-axis.  The simulated wind is unaffected by the altitude.\r
13  * \r
14  * @author Sampo Niskanen <sampo.niskanen@iki.fi>\r
15  */\r
16 public class PinkNoiseWindModel implements WindModel {\r
17         \r
18         /** Random value with which to XOR the random seed value */\r
19         private static final int SEED_RANDOMIZATION = 0x7343AA03;\r
20         \r
21 \r
22 \r
23         /** Pink noise alpha parameter. */\r
24         private static final double ALPHA = 5.0 / 3.0;\r
25         \r
26         /** Number of poles to use in the pink noise IIR filter. */\r
27         private static final int POLES = 2;\r
28         \r
29         /** The standard deviation of the generated pink noise with the specified number of poles. */\r
30         private static final double STDDEV = 2.252;\r
31         \r
32         /** Time difference between random samples. */\r
33         private static final double DELTA_T = 0.05;\r
34         \r
35 \r
36         private double average = 0;\r
37         private double standardDeviation = 0;\r
38         \r
39         private final int seed;\r
40         \r
41         private PinkNoise randomSource = null;\r
42         private double time1;\r
43         private double value1, value2;\r
44         \r
45         \r
46         /**\r
47          * Construct a new wind simulation with a specific seed value.\r
48          * @param seed  the seed value.\r
49          */\r
50         public PinkNoiseWindModel(int seed) {\r
51                 this.seed = seed ^ SEED_RANDOMIZATION;\r
52         }\r
53         \r
54         \r
55 \r
56         /**\r
57          * Return the average wind speed.\r
58          * \r
59          * @return the average wind speed.\r
60          */\r
61         public double getAverage() {\r
62                 return average;\r
63         }\r
64         \r
65         /**\r
66          * Set the average wind speed.  This method will also modify the\r
67          * standard deviation such that the turbulence intensity remains constant.\r
68          * \r
69          * @param average the average wind speed to set\r
70          */\r
71         public void setAverage(double average) {\r
72                 double intensity = getTurbulenceIntensity();\r
73                 this.average = Math.max(average, 0);\r
74                 setTurbulenceIntensity(intensity);\r
75         }\r
76         \r
77         \r
78 \r
79         /**\r
80          * Return the standard deviation from the average wind speed.\r
81          * \r
82          * @return the standard deviation of the wind speed\r
83          */\r
84         public double getStandardDeviation() {\r
85                 return standardDeviation;\r
86         }\r
87         \r
88         /**\r
89          * Set the standard deviation of the average wind speed.\r
90          * \r
91          * @param standardDeviation the standardDeviation to set\r
92          */\r
93         public void setStandardDeviation(double standardDeviation) {\r
94                 this.standardDeviation = Math.max(standardDeviation, 0);\r
95         }\r
96         \r
97         \r
98         /**\r
99          * Return the turbulence intensity (standard deviation / average).\r
100          * \r
101          * @return  the turbulence intensity\r
102          */\r
103         public double getTurbulenceIntensity() {\r
104                 if (MathUtil.equals(average, 0)) {\r
105                         if (MathUtil.equals(standardDeviation, 0))\r
106                                 return 0;\r
107                         else\r
108                                 return 1000;\r
109                 }\r
110                 return standardDeviation / average;\r
111         }\r
112         \r
113         /**\r
114          * Set the standard deviation to match the turbulence intensity.\r
115          * \r
116          * @param intensity   the turbulence intensity\r
117          */\r
118         public void setTurbulenceIntensity(double intensity) {\r
119                 setStandardDeviation(intensity * average);\r
120         }\r
121         \r
122         \r
123 \r
124 \r
125 \r
126         @Override\r
127         public Coordinate getWindVelocity(double time, double altitude) {\r
128                 if (time < 0) {\r
129                         throw new IllegalArgumentException("Requesting wind speed at t=" + time);\r
130                 }\r
131                 \r
132                 if (randomSource == null) {\r
133                         randomSource = new PinkNoise(ALPHA, POLES, new Random(seed));\r
134                         time1 = 0;\r
135                         value1 = randomSource.nextValue();\r
136                         value2 = randomSource.nextValue();\r
137                 }\r
138                 \r
139                 if (time < time1) {\r
140                         reset();\r
141                         return getWindVelocity(time, altitude);\r
142                 }\r
143                 \r
144                 while (time1 + DELTA_T < time) {\r
145                         value1 = value2;\r
146                         value2 = randomSource.nextValue();\r
147                         time1 += DELTA_T;\r
148                 }\r
149                 \r
150                 double a = (time - time1) / DELTA_T;\r
151                 \r
152                 double speed = average + (value1 * (1 - a) + value2 * a) * standardDeviation / STDDEV;\r
153                 // TODO: MEDIUM: Make wind direction configurable\r
154                 return new Coordinate(speed, 0, 0);\r
155         }\r
156         \r
157         \r
158         private void reset() {\r
159                 randomSource = null;\r
160         }\r
161         \r
162         \r
163 \r
164         @Override\r
165         public int getModID() {\r
166                 return (int) (average * 1000 + standardDeviation);\r
167         }\r
168         \r
169 }\r