Added POlar Linear Interpolation #story[1186]

main
Fan-Wu Yang 8 years ago
parent 34cfe48df0
commit 71dcc8ee6c

@ -104,6 +104,7 @@ public class Event {
this.xmlFileType = XMLFileType.Contents; this.xmlFileType = XMLFileType.Contents;
this.boatPolars = PolarParser.parse("mock/polars/acc_polars.csv"); this.boatPolars = PolarParser.parse("mock/polars/acc_polars.csv");
PolarParser.parseNewPolars("mock/polars/acc_polars.csv");
//Parse the XML files into data sources. //Parse the XML files into data sources.

@ -3,6 +3,7 @@ package mock.dataInput;
import mock.exceptions.InvalidPolarFileException; import mock.exceptions.InvalidPolarFileException;
import mock.model.NewPolars;
import mock.model.Polars; import mock.model.Polars;
import shared.model.Bearing; import shared.model.Bearing;
@ -89,7 +90,6 @@ public class PolarParser {
Bearing angle = Bearing.fromDegrees(angleDegrees); Bearing angle = Bearing.fromDegrees(angleDegrees);
double boatSpeedKnots = Double.parseDouble(row[i + 1]); double boatSpeedKnots = Double.parseDouble(row[i + 1]);
polarTable.addEstimate(windSpeedKnots, angle, boatSpeedKnots); polarTable.addEstimate(windSpeedKnots, angle, boatSpeedKnots);
polarTable.addPolars(windSpeedKnots, angle, boatSpeedKnots);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new InvalidPolarFileException("Could not convert (Row,Col): (" + rowNumber + "," + i +") = " + row[i] + " to a double.", e); throw new InvalidPolarFileException("Could not convert (Row,Col): (" + rowNumber + "," + i +") = " + row[i] + " to a double.", e);
@ -105,4 +105,91 @@ public class PolarParser {
return polarTable; return polarTable;
} }
/**
* Given a filename, this function parses it and generates a Polar object, which can be queried for polar information.
* @param filename The filename to load and read data from (loaded as a resource).
* @return A Polar table containing data from the given file.
*/
public static void parseNewPolars(String filename) throws InvalidPolarFileException {
NewPolars newPolars = new NewPolars();
//Open the file for reading.
InputStream fileStream = PolarParser.class.getClassLoader().getResourceAsStream(filename);
if (fileStream == null) {
throw new InvalidPolarFileException("Could not open polar data file: " + filename);
}
//Wrap it with buffered input stream to set encoding and buffer.
InputStreamReader in = null;
try {
in = new InputStreamReader(fileStream, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InvalidPolarFileException("Unsupported encoding: UTF-8", e);
}
BufferedReader inputStream = new BufferedReader(in);
//We expect the polar data file to have the column headings:
// Tws, Twa0, Bsp0, Twa1, Bsp1, UpTwa, UpBsp, Twa2, Bsp2, Twa3, Bsp3, Twa4, Bsp4, Twa5, Bsp5, Twa6, Bsp6, DnTwa, DnBsp, Twa7, Bsp7
//and to have 7 rows of data.
//Angles are expected to be in degrees, and velocities in knots.
//We read data rows, and split them into arrays of elements.
ArrayList<String[]> dataRows = new ArrayList<>(7);
try {
//Heading row.
//We skip the heading row by reading it.
String headingRow = inputStream.readLine();
//Data rows.
while (inputStream.ready()) {
//Read line.
String dataRow = inputStream.readLine();
//Split line.
String[] dataElements = dataRow.split(",");
//Add to collection.
dataRows.add(dataElements);
}
} catch (IOException e) {
throw new InvalidPolarFileException("Could not read from polar data file: " + filename, e);
}
//Finished reading in data, now we need to construct polar rows and table from it.
//For each row...
int rowNumber = 0;
for (String[] row : dataRows) {
//For each pair of columns (the pair is angle, speed).
//We start at column 1 since column 0 is the wind speed column.
for (int i = 1; i < row.length; i += 2) {
//Add angle+speed=velocity estimate to polar table.
try {
//Add the polar value to the polar table
double windSpeedKnots = Double.parseDouble(row[0]);
double angleDegrees = Double.parseDouble(row[i]);
Bearing angle = Bearing.fromDegrees(angleDegrees);
double boatSpeedKnots = Double.parseDouble(row[i + 1]);
newPolars.addPolars(windSpeedKnots, angle, boatSpeedKnots);
} catch (NumberFormatException e) {
throw new InvalidPolarFileException("Could not convert (Row,Col): (" + rowNumber + "," + i +") = " + row[i] + " to a double.", e);
}
}
//Increment row number.
rowNumber++;
}
newPolars.linearInterpolatePolars();
}
} }

@ -363,7 +363,7 @@ public class MockRace extends Race {
// Bearing.fromDegrees(0d), // Bearing.fromDegrees(0d),
// Bearing.fromDegrees(359.99999d)); // Bearing.fromDegrees(359.99999d));
VMG newVMG = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing()); VMG newVMG = NewPolars.setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
System.out.println(newVMG); System.out.println(newVMG);
//If the new vmg improves velocity, use it. //If the new vmg improves velocity, use it.
if (improvesVelocity(boat, newVMG)) { if (improvesVelocity(boat, newVMG)) {
@ -380,7 +380,11 @@ public class MockRace extends Race {
// Bearing.fromDegrees(boat.getBearing().degrees() - 1), // Bearing.fromDegrees(boat.getBearing().degrees() - 1),
// Bearing.fromDegrees(boat.getBearing().degrees() + 1)); // Bearing.fromDegrees(boat.getBearing().degrees() + 1));
//VMG vmg = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing()); //VMG vmg = boat.getPolars().setBestVMG(this.getWindDirection(), this.getWindSpeed(), boat.getBearing());
VMG vmg = new VMG(Math.cos (boat.getBearing().radians() - this.getWindDirection().radians()) * this.getWindSpeed() * 4, boat.getBearing()) ; VMG vmg = new VMG(NewPolars.calculateSpeed(
this.getWindDirection(),
this.getWindSpeed(),
boat.getBearing()
), boat.getBearing()) ;
if (vmg.getSpeed() > 0) { if (vmg.getSpeed() > 0) {
boat.setCurrentSpeed(vmg.getSpeed()); boat.setCurrentSpeed(vmg.getSpeed());
} }

@ -0,0 +1,151 @@
package mock.model;
import shared.model.Bearing;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Created by fwy13 on 4/09/17.
*/
public class NewPolars {
//true wind speed, <true wind angle, best boat angle>
private static Map<Double, TreeMap<Double, Double>> polars = new TreeMap<>();
public static NewPolars newPolars = null;
public NewPolars(){
newPolars = this;
}
public static void addPolars(double trueWindSpeed, Bearing trueWindAngle, double boatSpeed){
double tws = trueWindSpeed;
double bs = boatSpeed;
double twa = trueWindAngle.degrees();
if (!polars.containsKey(tws)){
polars.put(tws, new TreeMap<>());
}
polars.get(tws).put(twa, bs);
}
public static void linearInterpolatePolars(){
// double maxTWS = 0;
// for (double key: polars.keySet()){
// if (maxTWS < key){
// maxTWS = key;
// }
// }
TreeMap<Double, Double> prevTWS = null;
for (TreeMap<Double, Double> tws: polars.values()){
if (prevTWS == null){
prevTWS = tws;
continue;
}
double previousTWA = -1;
TreeMap<Double, Double> iterableTWS = new TreeMap<>(tws);
for (double twa: iterableTWS.keySet()){
if (previousTWA == -1){
previousTWA = twa;
continue;
}
double twaDiff = twa - previousTWA;
double speedDiff = iterableTWS.get(twa) - iterableTWS.get(previousTWA);
double prevSpeed = iterableTWS.get(previousTWA);
double diff = speedDiff/twaDiff;
for (double i = previousTWA; i < twa; i ++){
double mult = i - previousTWA;
double newSpeed = diff * mult + prevSpeed;
System.out.println(newS);
tws.put(i, newSpeed);
}
}
}
}
private static double getClosest(double value, Set<Double> set){
double closestVal = 0;
double smallestDiff = Double.MAX_VALUE;
for (double d: set){
double diff = Math.abs(value - d);
if (diff < smallestDiff){
closestVal = d;
smallestDiff = diff;
}
}
return closestVal;
}
/**
* Determines which quadrant degrees are in
* 0/360 Degrees
* Quadrant 4 | Quadrant 1
* -----------------------
* Quadrant 3 | Quadrant 2
* @param degrees
* @return
*/
private static int getQuadrant(double degrees){
return ((int) degrees % 360) / 90 + 1;
}
private static double getBestSpeedInQuadrant(int quad, Map<Double, Double> set){
double quadVal = (double)((quad - 1) % 2);// this is as the hash map only has values 0 - 180
double min = quadVal* 90;
double max = (quadVal + 1) * 90;
double maxAngle = 0;
double maxSpeed = 0;
for (Double s: set.keySet()){
if (s >= min && s < max){
if (set.get(s) > maxSpeed){
maxAngle = s;
maxSpeed = set.get(s);
}
}
}
if (quad > 2){
maxAngle += 180;
}
return maxAngle;
}
/**
*
* @param trueWindAngle
* @param trueWindSpeed
* @param boatAngle
* @return
*/
public static VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
//speed
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
//not using true vmg, using general concept
double angle = Math.abs(trueWindAngle.degrees() - boatAngle.degrees());
int quad = getQuadrant(boatAngle.degrees());
double bestAngle = getBestSpeedInQuadrant(quad, polars.get(closestSpeed));
Bearing vmgAngle = Bearing.fromDegrees((bestAngle) % 360);
double boatSpeed = polars.get(closestSpeed).get(bestAngle);
return new VMG(boatSpeed, Bearing.fromDegrees(vmgAngle.degrees() + trueWindAngle.degrees()));
}
public static double calculateSpeed(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
//speed
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
double angleDiff = Math.abs(trueWindAngle.degrees() - boatAngle.degrees()) % 180;
double closestAngle = getClosest(angleDiff, polars.get(closestSpeed).keySet());
double boatSpeed = polars.get(closestSpeed).get(closestAngle);
return boatSpeed;
}
}

@ -22,8 +22,6 @@ public class Polars {
*/ */
private HashMap<Double, List<Bearing>> polarAngles = new HashMap<>(); private HashMap<Double, List<Bearing>> polarAngles = new HashMap<>();
//true wind speed, <true wind angle, best boat angle>
private Map<Double, HashMap<Double, Double>> polars = new TreeMap<>();
@ -77,85 +75,6 @@ public class Polars {
} }
public void addPolars(double trueWindSpeed, Bearing trueWindAngle, double boatSpeed){
double tws = trueWindSpeed;
double bs = boatSpeed;
double twa = trueWindAngle.degrees();
if (!polars.containsKey(tws)){
polars.put(tws, new HashMap<>());
}
polars.get(tws).put(twa, bs);
}
private static double getClosest(double value, Set<Double> set){
double closestVal = 0;
double smallestDiff = Double.MAX_VALUE;
for (double d: set){
double diff = Math.abs(value - d);
if (diff < smallestDiff){
closestVal = d;
smallestDiff = diff;
}
}
return closestVal;
}
/**
* Determines which quadrant degrees are in
* 0/360 Degrees
* Quadrant 4 | Quadrant 1
* -----------------------
* Quadrant 3 | Quadrant 2
* @param degrees
* @return
*/
private static int getQuadrant(double degrees){
return ((int) degrees % 360) / 90 + 1;
}
private static double getBestSpeedInQuadrant(int quad, HashMap<Double, Double> set){
double quadVal = (double)((quad - 1) % 2);// this is as the hash map only has values 0 - 180
double min = quadVal* 90;
double max = (quadVal + 1) * 90;
double maxAngle = 0;
double maxSpeed = 0;
for (Double s: set.keySet()){
if (s >= min && s < max){
if (set.get(s) > maxSpeed){
maxAngle = s;
maxSpeed = set.get(s);
}
}
}
if (quad > 2){
maxAngle += 180;
}
return maxAngle;
}
/**
*
* @param trueWindAngle
* @param trueWindSpeed
* @param boatAngle
* @return
*/
public VMG setBestVMG(Bearing trueWindAngle, double trueWindSpeed, Bearing boatAngle){
//speed
double closestSpeed = getClosest(trueWindSpeed, polars.keySet());
//not using true vmg, using general concept
double angle = Math.abs(trueWindAngle.degrees() - boatAngle.degrees());
int quad = getQuadrant(boatAngle.degrees());
double bestAngle = getBestSpeedInQuadrant(quad, polars.get(closestSpeed));
Bearing vmgAngle = Bearing.fromDegrees((bestAngle + trueWindSpeed) % 360);
double boatSpeed = Math.abs(trueWindSpeed * Math.cos(vmgAngle.radians())) * 4;
return new VMG(boatSpeed, vmgAngle);
}
/** /**
* Calculates the VMG for a given wind angle, wind speed, and angle to destination. Will only return VMGs that have a true bearing (angle) within a given bound - this is to ensure that you can calculate VMGs without going out of bounds. * Calculates the VMG for a given wind angle, wind speed, and angle to destination. Will only return VMGs that have a true bearing (angle) within a given bound - this is to ensure that you can calculate VMGs without going out of bounds.
* <br> * <br>

Loading…
Cancel
Save