7a29ce8a6879859cb6282361135b125e41dcbe7a
[debian/openrocket] / 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         /** Source for seed numbers. */\r
19         private static final Random seedSource = new Random();\r
20         \r
21         /** Pink noise alpha parameter. */\r
22         private static final double ALPHA = 5.0 / 3.0;\r
23         \r
24         /** Number of poles to use in the pink noise IIR filter. */\r
25         private static final int POLES = 2;\r
26         \r
27         /** The standard deviation of the generated pink noise with the specified number of poles. */\r
28         private static final double STDDEV = 2.252;\r
29         \r
30         /** Time difference between random samples. */\r
31         private static final double DELTA_T = 0.05;\r
32         \r
33 \r
34         private double average = 0;\r
35         private double standardDeviation = 0;\r
36         \r
37         private int seed;\r
38         \r
39         private PinkNoise randomSource = null;\r
40         private double time1;\r
41         private double value1, value2;\r
42         \r
43         \r
44         /**\r
45          * Construct a new wind simulator with a random starting seed value.\r
46          */\r
47         public PinkNoiseWindModel() {\r
48                 synchronized (seedSource) {\r
49                         seed = seedSource.nextInt();\r
50                 }\r
51         }\r
52         \r
53         \r
54 \r
55         /**\r
56          * Return the average wind speed.\r
57          * \r
58          * @return the average wind speed.\r
59          */\r
60         public double getAverage() {\r
61                 return average;\r
62         }\r
63         \r
64         /**\r
65          * Set the average wind speed.  This method will also modify the\r
66          * standard deviation such that the turbulence intensity remains constant.\r
67          * \r
68          * @param average the average wind speed to set\r
69          */\r
70         public void setAverage(double average) {\r
71                 double intensity = getTurbulenceIntensity();\r
72                 this.average = Math.max(average, 0);\r
73                 setTurbulenceIntensity(intensity);\r
74         }\r
75         \r
76         \r
77 \r
78         /**\r
79          * Return the standard deviation from the average wind speed.\r
80          * \r
81          * @return the standard deviation of the wind speed\r
82          */\r
83         public double getStandardDeviation() {\r
84                 return standardDeviation;\r
85         }\r
86         \r
87         /**\r
88          * Set the standard deviation of the average wind speed.\r
89          * \r
90          * @param standardDeviation the standardDeviation to set\r
91          */\r
92         public void setStandardDeviation(double standardDeviation) {\r
93                 this.standardDeviation = Math.max(standardDeviation, 0);\r
94         }\r
95         \r
96         \r
97         /**\r
98          * Return the turbulence intensity (standard deviation / average).\r
99          * \r
100          * @return  the turbulence intensity\r
101          */\r
102         public double getTurbulenceIntensity() {\r
103                 if (MathUtil.equals(average, 0)) {\r
104                         if (MathUtil.equals(standardDeviation, 0))\r
105                                 return 0;\r
106                         else\r
107                                 return 1000;\r
108                 }\r
109                 return standardDeviation / average;\r
110         }\r
111         \r
112         /**\r
113          * Set the standard deviation to match the turbulence intensity.\r
114          * \r
115          * @param intensity   the turbulence intensity\r
116          */\r
117         public void setTurbulenceIntensity(double intensity) {\r
118                 setStandardDeviation(intensity * average);\r
119         }\r
120         \r
121         \r
122 \r
123 \r
124 \r
125         public int getSeed() {\r
126                 return seed;\r
127         }\r
128         \r
129         public void setSeed(int seed) {\r
130                 if (this.seed == seed)\r
131                         return;\r
132                 this.seed = seed;\r
133         }\r
134         \r
135         \r
136 \r
137         public Coordinate getWindVelocity(double time, double altitude) {\r
138                 if (time < 0) {\r
139                         throw new IllegalArgumentException("Requesting wind speed at t=" + time);\r
140                 }\r
141                 \r
142                 if (randomSource == null) {\r
143                         randomSource = new PinkNoise(ALPHA, POLES, new Random(seed));\r
144                         time1 = 0;\r
145                         value1 = randomSource.nextValue();\r
146                         value2 = randomSource.nextValue();\r
147                 }\r
148                 \r
149                 if (time < time1) {\r
150                         reset();\r
151                         return getWindVelocity(time, altitude);\r
152                 }\r
153                 \r
154                 while (time1 + DELTA_T < time) {\r
155                         value1 = value2;\r
156                         value2 = randomSource.nextValue();\r
157                         time1 += DELTA_T;\r
158                 }\r
159                 \r
160                 double a = (time - time1) / DELTA_T;\r
161                 \r
162                 double speed = average + (value1 * (1 - a) + value2 * a) * standardDeviation / STDDEV;\r
163                 // TODO: MEDIUM: Make wind direction configurable\r
164                 return new Coordinate(speed, 0, 0);\r
165         }\r
166         \r
167         \r
168         private void reset() {\r
169                 randomSource = null;\r
170         }\r
171         \r
172         \r
173 \r
174         @Override\r
175         public int getModID() {\r
176                 return (int) (average * 1000 + standardDeviation);\r
177         }\r
178         \r
179 }\r