create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / utils / MotorCorrelation.java
1 package net.sf.openrocket.utils;
2
3 import java.io.FileInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import net.sf.openrocket.file.motor.GeneralMotorLoader;
10 import net.sf.openrocket.file.motor.MotorLoader;
11 import net.sf.openrocket.logging.LogLevel;
12 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
13 import net.sf.openrocket.motor.Motor;
14 import net.sf.openrocket.motor.MotorDigest;
15 import net.sf.openrocket.motor.MotorInstance;
16 import net.sf.openrocket.motor.ThrustCurveMotor;
17 import net.sf.openrocket.startup.Application;
18 import net.sf.openrocket.util.BugException;
19 import net.sf.openrocket.util.MathUtil;
20
21 public class MotorCorrelation {
22         
23         /**
24          * Return a measure of motor similarity.  The measure is a value between 0.0 and 1.0.
25          * The larger the value, the more similar the motor thrust curves are, for value 1.0 they
26          * are identical.
27          * <p>
28          * This method takes into account the thrust curve shape, average thrust, burn time and
29          * total impulse of the motor.  The similarity is the minimum of all of these.
30          * 
31          * @param motor1        the first motor
32          * @param motor2        the second motor
33          * @return                      the similarity of the two motors
34          */
35         public static double similarity(Motor motor1, Motor motor2) {
36                 double d;
37                 
38                 d = crossCorrelation(motor1, motor2);
39                 d = Math.min(d, diff(motor1.getAverageThrustEstimate(), motor2.getAverageThrustEstimate()));
40                 d = Math.min(d, 2 * diff(motor1.getBurnTimeEstimate(), motor2.getBurnTimeEstimate()));
41                 d = Math.min(d, diff(motor1.getTotalImpulseEstimate(), motor2.getTotalImpulseEstimate()));
42                 
43                 return d;
44         }
45         
46         
47         private static double diff(double a, double b) {
48                 double min = Math.min(a, b);
49                 double max = Math.max(a, b);
50                 
51                 if (MathUtil.equals(max, 0))
52                         return 1.0;
53                 return min / max;
54         }
55         
56         
57         /**
58          * Compute the cross-correlation of the thrust curves of the two motors.  The result is
59          * a double between 0 and 1 (inclusive).  The closer the return value is to one the more
60          * similar the thrust curves are.
61          * 
62          * @param motor1        the first motor.
63          * @param motor2        the second motor.
64          * @return                      the scaled cross-correlation of the two thrust curves.
65          */
66         public static double crossCorrelation(Motor motor1, Motor motor2) {
67                 MotorInstance m1 = motor1.getInstance();
68                 MotorInstance m2 = motor2.getInstance();
69                 
70                 AtmosphericConditions cond = new AtmosphericConditions();
71                 
72                 double t;
73                 double auto1 = 0;
74                 double auto2 = 0;
75                 double cross = 0;
76                 for (t = 0; t < 1000; t += 0.01) {
77                         m1.step(t, 0, cond);
78                         m2.step(t, 0, cond);
79                         
80                         double t1 = m1.getThrust();
81                         double t2 = m2.getThrust();
82                         
83                         if (t1 < 0 || t2 < 0) {
84                                 throw new BugException("Negative thrust, t1=" + t1 + " t2=" + t2);
85                         }
86                         
87                         auto1 += t1 * t1;
88                         auto2 += t2 * t2;
89                         cross += t1 * t2;
90                 }
91                 
92                 double auto = Math.max(auto1, auto2);
93                 
94                 if (MathUtil.equals(auto, 0)) {
95                         return 1.0;
96                 }
97                 
98                 return cross / auto;
99         }
100         
101         
102
103
104         public static void main(String[] args) {
105                 Application.setLogOutputLevel(LogLevel.WARN);
106                 
107                 MotorLoader loader = new GeneralMotorLoader();
108                 List<Motor> motors = new ArrayList<Motor>();
109                 List<String> files = new ArrayList<String>();
110                 
111                 // Load files
112                 for (String file : args) {
113                         List<Motor> m = null;
114                         try {
115                                 InputStream stream = new FileInputStream(file);
116                                 m = loader.load(stream, file);
117                                 stream.close();
118                         } catch (IOException e) {
119                                 e.printStackTrace();
120                                 System.exit(1);
121                         }
122                         if (m != null) {
123                                 motors.addAll(m);
124                                 for (int i = 0; i < m.size(); i++)
125                                         files.add(file);
126                         }
127                 }
128                 
129                 // Output motor digests
130                 final int count = motors.size();
131                 for (int i = 0; i < count; i++) {
132                         System.out.println(files.get(i) + ": " + ((ThrustCurveMotor) motors.get(i)).getDigest());
133                 }
134                 
135                 // Cross-correlate every pair
136                 for (int i = 0; i < count; i++) {
137                         for (int j = i + 1; j < count; j++) {
138                                 System.out.println(files.get(i) + " " + files.get(j) + " : " +
139                                                 crossCorrelation(motors.get(i), motors.get(j)));
140                         }
141                 }
142                 
143         }
144         
145 }