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 /** Random value with which to XOR the random seed value */
\r
19 private static final int SEED_RANDOMIZATION = 0x7343AA03;
\r
23 /** Pink noise alpha parameter. */
\r
24 private static final double ALPHA = 5.0 / 3.0;
\r
26 /** Number of poles to use in the pink noise IIR filter. */
\r
27 private static final int POLES = 2;
\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
32 /** Time difference between random samples. */
\r
33 private static final double DELTA_T = 0.05;
\r
36 private double average = 0;
\r
37 private double standardDeviation = 0;
\r
39 private final int seed;
\r
41 private PinkNoise randomSource = null;
\r
42 private double time1;
\r
43 private double value1, value2;
\r
47 * Construct a new wind simulation with a specific seed value.
\r
48 * @param seed the seed value.
\r
50 public PinkNoiseWindModel(int seed) {
\r
51 this.seed = seed ^ SEED_RANDOMIZATION;
\r
57 * Return the average wind speed.
\r
59 * @return the average wind speed.
\r
61 public double getAverage() {
\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
69 * @param average the average wind speed to set
\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
80 * Return the standard deviation from the average wind speed.
\r
82 * @return the standard deviation of the wind speed
\r
84 public double getStandardDeviation() {
\r
85 return standardDeviation;
\r
89 * Set the standard deviation of the average wind speed.
\r
91 * @param standardDeviation the standardDeviation to set
\r
93 public void setStandardDeviation(double standardDeviation) {
\r
94 this.standardDeviation = Math.max(standardDeviation, 0);
\r
99 * Return the turbulence intensity (standard deviation / average).
\r
101 * @return the turbulence intensity
\r
103 public double getTurbulenceIntensity() {
\r
104 if (MathUtil.equals(average, 0)) {
\r
105 if (MathUtil.equals(standardDeviation, 0))
\r
110 return standardDeviation / average;
\r
114 * Set the standard deviation to match the turbulence intensity.
\r
116 * @param intensity the turbulence intensity
\r
118 public void setTurbulenceIntensity(double intensity) {
\r
119 setStandardDeviation(intensity * average);
\r
127 public Coordinate getWindVelocity(double time, double altitude) {
\r
129 throw new IllegalArgumentException("Requesting wind speed at t=" + time);
\r
132 if (randomSource == null) {
\r
133 randomSource = new PinkNoise(ALPHA, POLES, new Random(seed));
\r
135 value1 = randomSource.nextValue();
\r
136 value2 = randomSource.nextValue();
\r
139 if (time < time1) {
\r
141 return getWindVelocity(time, altitude);
\r
144 while (time1 + DELTA_T < time) {
\r
146 value2 = randomSource.nextValue();
\r
150 double a = (time - time1) / DELTA_T;
\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
158 private void reset() {
\r
159 randomSource = null;
\r
165 public int getModID() {
\r
166 return (int) (average * 1000 + standardDeviation);
\r