Ejemplo n.º 1
0
/* compute boat speed from given power level, true wind angle and true wind speed */
double BoatPlan::Speed(double W, double VW)
{
    W = positive_degrees(W);
    if(VW < 0 || VW > MAX_KNOTS)
        return NAN;

    double W1 = floor(W/DEGREE_STEP)*DEGREE_STEP;
    double W2 = ceil(W/DEGREE_STEP)*DEGREE_STEP;

    /* get headings nearby each other */
    while(W1 - W2 > 180)
        W2 += 360;
    while(W2 - W1 > 180)
        W1 += 360;

    int W1i = positive_degrees(W1)/DEGREE_STEP;
    int W2i = positive_degrees(W2)/DEGREE_STEP;

    int VW1i = ClosestVWi(VW), VW2i = VW1i+1;
    double VW1 = wind_speeds[VW1i], VW2 = wind_speeds[VW2i];

    double VB11 = speed[VW1i][W1i].VB;
    double VB12 = speed[VW1i][W2i].VB;
    double VB21 = speed[VW2i][W1i].VB;
    double VB22 = speed[VW2i][W2i].VB;

    double VB1 = interp_value(VW, VW1, VW2, VB11, VB21);
    double VB2 = interp_value(VW, VW1, VW2, VB12, VB22);

    double VB = interp_value(W, W1, W2, VB1, VB2);
    return VB;
}
Ejemplo n.º 2
0
/* find true wind speed from boat speed and true wind direction, because often at high
   winds the polar inverts and boat speed is lower, we can specify the max VW to search */
double BoatPlan::TrueWindSpeed(double VB, double W, double maxVW)
{
    W = positive_degrees(W);
    unsigned int W1i = degree_step_index[(int)floor(W)], W2i;
    if(W1i == degree_steps.size()-1)
        W2i = 0;
    else
        W2i = W1i++;
    double W1 = degree_steps[W1i], W2 = degree_steps[W2i];

    double VB1min = INFINITY, VW1min = NAN, VB1max = 0, VW1max = NAN;
    double VB2min = INFINITY, VW2min = NAN, VB2max = 0, VW2max = NAN;

    for(unsigned int VWi = 0; VWi < wind_speeds.size(); VWi++) {
        if(wind_speeds[VWi].VW > maxVW)
            break;

        SailingWindSpeed &ws = wind_speeds[VWi];
        double VB1 = ws.speeds[W1i].VB;
        if(VB1 > VB && VB1 < VB1min) VB1min = VB1, VW1min = ws.VW;
        if(VB1 < VB && VB1 > VB1max) VB1max = VB1, VW1max = ws.VW;

        double VB2 = ws.speeds[W2i].VB;
        if(VB2 > VB && VB2 < VB2min) VB2min = VB2, VW2min = ws.VW;
        if(VB2 < VB && VB2 > VB2max) VB2max = VB2, VW2max = ws.VW;
    }

    double VBmin = interp_value(W, W1, W2, VB1min, VB2min);
    double VWmin = interp_value(W, W1, W2, VW1min, VW2min);
    double VBmax = interp_value(W, W1, W2, VB1max, VB2max);
    double VWmax = interp_value(W, W1, W2, VW1max, VW2max);

    return interp_value(VB, VBmin, VBmax, VWmin, VWmax);
}
Ejemplo n.º 3
0
/* compute boat speed from true wind angle and true wind speed
 */
double Polar::Speed(double W, double VW, bool bound)
{
    if(VW < 0)
        return NAN;

    if(!degree_steps.size() || !wind_speeds.size())
        return NAN;

    W = positive_degrees(W);

    // assume symmetric
    if(W > 180)
        W = 360 - W;

    if(W < degree_steps[0] || W > degree_steps[degree_steps.size()-1])
        return NAN;

    if(bound)
        if(VW < wind_speeds[0].VW || VW > wind_speeds[wind_speeds.size()-1].VW)
            return NAN;

    unsigned int W1i = degree_step_index[(int)floor(W)];
    unsigned int W2i = degree_steps.size() == 1 ? 0 : W1i+1;

    double W1 = degree_steps[W1i], W2 = degree_steps[W2i];

    int VW1i, VW2i;
    ClosestVWi(VW, VW1i, VW2i);
    if(VW1i == (int)wind_speeds.size() - 1)
        VW2i = VW1i;
    else
        VW2i = VW1i + 1;

    SailingWindSpeed &ws1 = wind_speeds[VW1i], &ws2 = wind_speeds[VW2i];
    double VW1 = ws1.VW, VW2 = ws2.VW;

    double VB11 = ws1.speeds[W1i], VB12 = ws1.speeds[W2i];
    double VB21 = ws2.speeds[W1i], VB22 = ws2.speeds[W2i];

    double VB1 = interp_value(VW, VW1, VW2, VB11, VB21);
    double VB2 = interp_value(VW, VW1, VW2, VB12, VB22);

    double VB  = interp_value(W, W1, W2, VB1, VB2);

    if(VB < 0) // with faulty polars, extrapolation, sometimes results in negative boat speed
        return 0;

    return VB;
}
Ejemplo n.º 4
0
SailingVMG BoatPlan::GetVMG(double VW)
{
    int VW2i = ClosestVWi(VW), VW1i = VW2i > 0 ? VW2i - 1 : 0;
    SailingVMG vmg, vmg1 = VMG[VW1i], vmg2 = VMG[VW2i];
    double VW1 = wind_speeds[VW1i], VW2 = wind_speeds[VW2i];

    vmg.PortTackUpWind = DEGREE_STEP * interp_value
        (VW, VW1, VW2, vmg1.PortTackUpWind, vmg2.PortTackUpWind);
    vmg.StarboardTackUpWind = DEGREE_STEP * interp_value
        (VW, VW1, VW2, vmg1.StarboardTackUpWind, vmg2.StarboardTackUpWind);
    vmg.PortTackDownWind = DEGREE_STEP * interp_value
        (VW, VW1, VW2, vmg1.PortTackDownWind, vmg2.PortTackDownWind);
    vmg.StarboardTackDownWind = DEGREE_STEP * interp_value
        (VW, VW1, VW2, vmg1.StarboardTackDownWind, vmg2.StarboardTackDownWind);
    return vmg;
}
Ejemplo n.º 5
0
double BoatSpeedTable::InterpolateSpeed(double VW, double W)
{
    BoatSpeedTableEntry *minW = NULL, *maxW = NULL;
    for(std::vector<BoatSpeedTableEntry>::iterator it = table.begin(); it != table.end(); ++it) {
        if((*it).W >= W && (!maxW || maxW->W > (*it).W))
            maxW = &(*it);

        if((*it).W <= W && (!minW || minW->W < (*it).W))
            minW = &(*it);
    }

    int minVWind = -1, maxVWind = -1;
    for(unsigned int i=0; i<windspeeds.size(); i++) {
        if(windspeeds[i] >= VW && (maxVWind == -1 || windspeeds[maxVWind] > windspeeds[i]))
            maxVWind = i;

        if(windspeeds[i] <= VW && (minVWind == -1 || windspeeds[minVWind] < windspeeds[i]))
            minVWind = i;
    }

    if(!minW || !maxW || minVWind == -1 || maxVWind == -1)
        return 0;

    double x1, x2, y1, y2;
    x1 = windspeeds[minVWind];
    x2 = windspeeds[maxVWind];
    y1 = minW->boatspeed[minVWind];
    y2 = minW->boatspeed[maxVWind];
    double minWBoatspeed = interp_value(VW, x1, x2, y1, y2);

    y1 = maxW->boatspeed[minVWind];
    y2 = maxW->boatspeed[maxVWind];
    double maxWBoatspeed = interp_value(VW, x1, x2, y1, y2);

    x1 = minW->W;
    x2 = maxW->W;
    y1 = minWBoatspeed;
    y2 = maxWBoatspeed;

    return interp_value(W, x1, x2, y1, y2);
}
Ejemplo n.º 6
0
/* compute boat speed from true wind angle and true wind speed

   Maybe this should use rectangular coordinate interpolation when the speed
   is outside the VMG zone.
 */
double BoatPlan::Speed(double W, double VW)
{
    if(VW < 0)
        return NAN;

    W = positive_degrees(W);
    unsigned int W1i = degree_step_index[(int)floor(W)], W2i;
    double W1 = degree_steps[W1i], W2;
    if(W1i == degree_steps.size()-1) {
        W2i = 0;
        W2 = 360 + degree_steps[0];
    } else {
        W2i = W1i+1;
        W2 = degree_steps[W2i];
    }

    int VW1i, VW2i;
    ClosestVWi(VW, VW1i, VW2i);
    if(VW1i == wind_speeds.size() - 1)
        VW2i = VW1i;
    else
        VW2i = VW1i + 1;

    SailingWindSpeed &ws1 = wind_speeds[VW1i], &ws2 = wind_speeds[VW2i];
    double VW1 = ws1.VW, VW2 = ws2.VW;

    double VB11 = ws1.speeds[W1i].VB, VB12 = ws1.speeds[W2i].VB;
    double VB21 = ws2.speeds[W1i].VB, VB22 = ws2.speeds[W2i].VB;

    double VB1 = interp_value(VW, VW1, VW2, VB11, VB21);
    double VB2 = interp_value(VW, VW1, VW2, VB12, VB22);

    double VB  = interp_value(W, W1, W2, VB1, VB2);

    if(VB < 0) // with faulty polars, extrapolation, sometimes results in negative boat speed
        return 0;

    return VB;
}
Ejemplo n.º 7
0
/* find true wind speed from boat speed and true wind direction, because often at high
   winds the polar inverts and boat speed is lower, we can specify the max VW to search */
double BoatPlan::TrueWindSpeed(double VB, double W, double maxVW)
{
    int W1 = floor(W/DEGREE_STEP)*DEGREE_STEP;
    int W2 = ceil(W/DEGREE_STEP)*DEGREE_STEP;

    /* get headings nearby */
    while(W1 - W2 > 180)
        W2 += 360;
    while(W2 - W1 > 180)
        W1 += 360;

    W1 = positive_degrees(W1);
    W2 = positive_degrees(W2);

    int W1i = W1/DEGREE_STEP, W2i = W2/DEGREE_STEP;

    double VB1min = INFINITY, VW1min = NAN, VB1max = 0, VW1max = NAN;
    double VB2min = INFINITY, VW2min = NAN, VB2max = 0, VW2max = NAN;

    for(int VWi = 0; VWi < num_wind_speeds; VWi++) {
        if(wind_speeds[VWi] > maxVW)
            break;

        double VB1 = speed[VWi][W1i].VB;
        if(VB1 > VB && VB1 < VB1min) VB1min = VB1, VW1min = wind_speeds[VWi];
        if(VB1 < VB && VB1 > VB1max) VB1max = VB1, VW1max = wind_speeds[VWi];

        double VB2 = speed[VWi][W2i].VB;
        if(VB2 > VB && VB2 < VB2min) VB2min = VB2, VW2min = wind_speeds[VWi];
        if(VB2 < VB && VB2 > VB2max) VB2max = VB2, VW2max = wind_speeds[VWi];
    }

    double VBmin = interp_value(W, W1, W2, VB1min, VB2min);
    double VWmin = interp_value(W, W1, W2, VW1min, VW2min);
    double VBmax = interp_value(W, W1, W2, VB1max, VB2max);
    double VWmax = interp_value(W, W1, W2, VW1max, VW2max);

    return interp_value(VB, VBmin, VBmax, VWmin, VWmax);
}
Ejemplo n.º 8
0
/* find true wind speed from boat speed and true wind direction, because often at high
   winds the polar inverts and boat speed is lower, we can specify the max VW to search */
double Polar::TrueWindSpeed(double VB, double W, double maxVW)
{
    if(!degree_steps.size())
        return NAN;

    W = positive_degrees(W);
    // assume symmetric
    if(W > 180)
        W = 360 - W;

    unsigned int W1i = degree_step_index[(int)floor(W)];
    unsigned int W2i = degree_steps.size() == 1 ? 0 : W1i+1;

    double W1 = degree_steps[W1i], W2 = degree_steps[W2i];

    double VB1min = INFINITY, VW1min = NAN, VB1max = 0, VW1max = NAN;
    double VB2min = INFINITY, VW2min = NAN, VB2max = 0, VW2max = NAN;

    for(unsigned int VWi = 0; VWi < wind_speeds.size(); VWi++) {
        if(wind_speeds[VWi].VW > maxVW)
            break;

        SailingWindSpeed &ws = wind_speeds[VWi];
        double VB1 = ws.speeds[W1i];
        if(VB1 > VB && VB1 < VB1min) VB1min = VB1, VW1min = ws.VW;
        if(VB1 < VB && VB1 > VB1max) VB1max = VB1, VW1max = ws.VW;

        double VB2 = ws.speeds[W2i];
        if(VB2 > VB && VB2 < VB2min) VB2min = VB2, VW2min = ws.VW;
        if(VB2 < VB && VB2 > VB2max) VB2max = VB2, VW2max = ws.VW;
    }

    double VBmin = interp_value(W, W1, W2, VB1min, VB2min);
    double VWmin = interp_value(W, W1, W2, VW1min, VW2min);
    double VBmax = interp_value(W, W1, W2, VB1max, VB2max);
    double VWmax = interp_value(W, W1, W2, VW1max, VW2max);

    return interp_value(VB, VBmin, VBmax, VWmin, VWmax);
}
Ejemplo n.º 9
0
SailingVMG BoatPlan::GetVMGTrueWind(double VW)
{
    int VW1i, VW2i;
    ClosestVWi(VW, VW1i, VW2i);

    SailingWindSpeed &ws1 = wind_speeds[VW1i], &ws2 = wind_speeds[VW2i];
    double VW1 = ws1.VW, VW2 = ws2.VW;
    SailingVMG vmg, vmg1 = ws1.VMG, vmg2 = ws2.VMG;

    for(int i=0; i<4; i++)
        vmg.values[i] = interp_value(VW, VW1, VW2, vmg1.values[i], vmg2.values[i]);

    return vmg;
}