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
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;
}
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
/* 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.º 6
0
/* eta is a measure of efficiency of the boat, from .01 for racing boats to .5 for
   heavy cruisers */
void BoatPlan::ComputeBoatSpeeds(Boat &boat, PolarMethod method, int speed)
{
//    fileFileName = _T("");
    if(/*polarmethod == FROM_FILE ||*/
       wind_speeds.size() != num_computed_wind_speeds ||
       degree_steps.size() != computed_degree_count) {
        wind_speeds.clear();
        degree_steps.clear();

        for(unsigned int Wi = 0; Wi < computed_degree_count; Wi++)
            degree_steps.push_back(computed_degree_step*Wi);
        UpdateDegreeStepLookup();

        for(unsigned int VWi = 0; VWi < num_computed_wind_speeds; VWi++) {
            wind_speeds.push_back(SailingWindSpeed(computed_wind_speeds[VWi]));

            wind_speeds[VWi].speeds.clear();
            for(unsigned int Wi = 0; Wi < computed_degree_count; Wi++)
                wind_speeds[VWi].speeds.push_back(SailingWindSpeed::SailingSpeed(0, degree_steps[Wi]));
        }
    }

    // for IMF computation
    double SADR = boat.SailAreaDisplacementRatio();
    double lwl_ft = boat.lwl_ft;
    double hull_speed = boat.HullSpeed();

    int VW1i, VW2i;
    if(speed == -1) // all speeds
        VW1i = 0, VW2i = wind_speeds.size() - 1;
    else
        ClosestVWi(speed, VW1i, VW2i);

    for(int VWi = VW1i; VWi <= VW2i; VWi++) {
        for(unsigned int Wi = 0; Wi <= computed_degree_count/2; Wi++) {
            double VW = wind_speeds[VWi].VW;
            double W = Wi * computed_degree_step;

            double B, VB, A, VA;
            switch(method) {
            case TRANSFORM:
                BoatSteadyState(deg2rad(W), VW, B, VB, A, VA, boat);
                break;
            case IMF:
            {
                if(fabsf(W) < 30)
                    VB = 0;
                else {
                    double base_speed  = 2.62 + .066*SADR + .051*lwl_ft;
                    double b = 1 / sqrt(VW + 3);
                    VB = base_speed*(sin(deg2rad(W)/2) + b*cos(deg2rad(W))) * sqrt(20*VW) / 8;
                    if(VB > hull_speed)
                        VB = hull_speed;
                }
            }
            default:
                printf("BoatPlan::ComputeBoatSpeeds called with invalid method: %d\n", method);
                return;
            }

            Set(Wi, VWi, VB, W);
            if(W != 0) // assume symmetric performance
                Set(computed_degree_count-Wi, VWi, VB, DEGREES-W);
        }

        CalculateVMG(VWi);
    }

    polarmethod = method;
}