1 package net.sf.openrocket.models.wind;
\r
3 import java.util.Random;
\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
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
14 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
\r
16 public class PinkNoiseWindModel implements WindModel {
\r
18 /** Source for seed numbers, may be overridden by get/setSeed(). */
\r
19 private static final Random seedSource = new Random();
\r
21 /** Pink noise alpha parameter. */
\r
22 private static final double ALPHA = 5.0 / 3.0;
\r
24 /** Number of poles to use in the pink noise IIR filter. */
\r
25 private static final int POLES = 2;
\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
30 /** Time difference between random samples. */
\r
31 private static final double DELTA_T = 0.05;
\r
34 private double average = 0;
\r
35 private double standardDeviation = 0;
\r
39 private PinkNoise randomSource = null;
\r
40 private double time1;
\r
41 private double value1, value2;
\r
45 * Construct a new wind simulator with a random starting seed value.
\r
47 public PinkNoiseWindModel() {
\r
48 synchronized (seedSource) {
\r
49 seed = seedSource.nextInt();
\r
56 * Return the average wind speed.
\r
58 * @return the average wind speed.
\r
60 public double getAverage() {
\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
68 * @param average the average wind speed to set
\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
79 * Return the standard deviation from the average wind speed.
\r
81 * @return the standard deviation of the wind speed
\r
83 public double getStandardDeviation() {
\r
84 return standardDeviation;
\r
88 * Set the standard deviation of the average wind speed.
\r
90 * @param standardDeviation the standardDeviation to set
\r
92 public void setStandardDeviation(double standardDeviation) {
\r
93 this.standardDeviation = Math.max(standardDeviation, 0);
\r
98 * Return the turbulence intensity (standard deviation / average).
\r
100 * @return the turbulence intensity
\r
102 public double getTurbulenceIntensity() {
\r
103 if (MathUtil.equals(average, 0)) {
\r
104 if (MathUtil.equals(standardDeviation, 0))
\r
109 return standardDeviation / average;
\r
113 * Set the standard deviation to match the turbulence intensity.
\r
115 * @param intensity the turbulence intensity
\r
117 public void setTurbulenceIntensity(double intensity) {
\r
118 setStandardDeviation(intensity * average);
\r
125 public int getSeed() {
\r
129 public void setSeed(int seed) {
\r
130 if (this.seed == seed)
\r
138 public Coordinate getWindVelocity(double time, double altitude) {
\r
140 throw new IllegalArgumentException("Requesting wind speed at t=" + time);
\r
143 if (randomSource == null) {
\r
144 randomSource = new PinkNoise(ALPHA, POLES, new Random(seed));
\r
146 value1 = randomSource.nextValue();
\r
147 value2 = randomSource.nextValue();
\r
150 if (time < time1) {
\r
152 return getWindVelocity(time, altitude);
\r
155 while (time1 + DELTA_T < time) {
\r
157 value2 = randomSource.nextValue();
\r
161 double a = (time - time1) / DELTA_T;
\r
163 double speed = average + (value1 * (1 - a) + value2 * a) * standardDeviation / STDDEV;
\r
164 // TODO: MEDIUM: Make wind direction configurable
\r
165 return new Coordinate(speed, 0, 0);
\r
169 private void reset() {
\r
170 randomSource = null;
\r
176 public int getModID() {
\r
177 return (int) (average * 1000 + standardDeviation);
\r