void compute(const RideFile *ride, const Zones *, int, const HrZones *, int, const QHash<QString,RideMetric*> &, const Context *) { // LNP only makes sense for running and it needs recIntSecs > 0 if (!ride->isRun() || ride->recIntSecs() == 0) { setValue(0.0); setCount(0); return; } // unconst naughty boy, get athlete's data RideFile *uride = const_cast<RideFile*>(ride); double weight = uride->getWeight(); double height = uride->getHeight(); int rollingwindowsize120 = 120 / ride->recIntSecs(); int rollingwindowsize30 = 30 / ride->recIntSecs(); double total = 0.0; int count = 0; // no point doing a rolling average if the // sample rate is greater than the rolling average // window!! if (rollingwindowsize30 > 1) { QVector<double> rollingSpeed(rollingwindowsize120); QVector<double> rollingSlope(rollingwindowsize120); QVector<double> rollingPower(rollingwindowsize30); int index120 = 0; int index30 = 0; double sumSpeed = 0.0; double sumSlope = 0.0; double sumPower = 0.0; double initial_speed = 0.0; // loop over the data and convert to a rolling // average for the given windowsize for (int i=0; i<ride->dataPoints().size(); i++) { double speed = ride->dataPoints()[i]->kph/3.6; sumSpeed += speed; sumSpeed -= rollingSpeed[index120]; rollingSpeed[index120] = speed; double speed120 = sumSpeed/std::min(count+1, rollingwindowsize120); // speed rolling average double slope = ride->dataPoints()[i]->slope/100.0; sumSlope += slope; sumSlope -= rollingSlope[index120]; rollingSlope[index120] = slope; double slope120 = sumSlope/std::min(count+1, rollingwindowsize120); // slope rolling average // running power based on 120sec averages double watts = running_power(weight, height, speed120, slope120, speed120*ride->recIntSecs(), initial_speed); initial_speed = speed120; sumPower += watts; sumPower -= rollingPower[index30]; rollingPower[index30] = watts; total += pow(sumPower/std::min(count+1, rollingwindowsize30), 4); // raise rolling average to 4th power count ++; // move index on/round index120 = (index120 >= rollingwindowsize120-1) ? 0 : index120+1; index30 = (index30 >= rollingwindowsize30-1) ? 0 : index30+1; } } if (count) { lnp = pow(total/count, 0.25); secs = count * ride->recIntSecs(); } else { lnp = secs = 0; } setValue(lnp); setCount(secs); }
void compute(RideItem *item, Specification spec, const QHash<QString,RideMetric*> &) { // no ride or no samples if (spec.isEmpty(item->ride()) || !item->isRun || item->ride()->recIntSecs() == 0) { setValue(RideFile::NIL); setCount(0); return; } double weight = item->ride()->getWeight(); double height = item->ride()->getHeight(); int rollingwindowsize120 = 120 / item->ride()->recIntSecs(); int rollingwindowsize30 = 30 / item->ride()->recIntSecs(); double total = 0.0; int count = 0; // no point doing a rolling average if the // sample rate is greater than the rolling average // window!! if (rollingwindowsize30 > 1) { QVector<double> rollingSpeed(rollingwindowsize120); QVector<double> rollingSlope(rollingwindowsize120); QVector<double> rollingPower(rollingwindowsize30); int index120 = 0; int index30 = 0; double sumSpeed = 0.0; double sumSlope = 0.0; double sumPower = 0.0; double initial_speed = 0.0; // loop over the data and convert to a rolling // average for the given windowsize RideFileIterator it(item->ride(), spec); while (it.hasNext()) { struct RideFilePoint *point = it.next(); double speed = point->kph/3.6; sumSpeed += speed; sumSpeed -= rollingSpeed[index120]; rollingSpeed[index120] = speed; double speed120 = sumSpeed/std::min(count+1, rollingwindowsize120); // speed rolling average double slope = point->slope/100.0; sumSlope += slope; sumSlope -= rollingSlope[index120]; rollingSlope[index120] = slope; double slope120 = sumSlope/std::min(count+1, rollingwindowsize120); // slope rolling average // running power based on 120sec averages double watts = running_power(weight, height, speed120, slope120, speed120*item->ride()->recIntSecs(), initial_speed); initial_speed = speed120; sumPower += watts; sumPower -= rollingPower[index30]; rollingPower[index30] = watts; total += pow(sumPower/std::min(count+1, rollingwindowsize30), 4); // raise rolling average to 4th power count ++; // move index on/round index120 = (index120 >= rollingwindowsize120-1) ? 0 : index120+1; index30 = (index30 >= rollingwindowsize30-1) ? 0 : index30+1; } } if (count) { lnp = pow(total/count, 0.25); secs = count * item->ride()->recIntSecs(); } else { lnp = secs = 0; } setValue(lnp); setCount(secs); }