Files
GoldenCheetah/src/RealtimeController.cpp
Mark Liversedge 68bac4f654 Tweak Virtual Power
If cadence is zero when calculating power then we
should set power to zero. Speed will not be zero
when freewheeling and therefore the calculation
will overstate power output.

Secondly, the NullController (for testing) did
not call the realtimeController post process
function. It does now so we can test the virtual
power calculation.
2011-10-26 22:18:37 +01:00

135 lines
4.7 KiB
C++

/*
* Copyright (c) 2009 Mark Liversedge (liversedge@gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "RealtimeController.h"
#include "TrainTool.h"
#include "RealtimeData.h"
#include "Units.h"
// Abstract base class for Realtime device controllers
RealtimeController::RealtimeController(TrainTool *parent, DeviceConfiguration *dc) : parent(parent), dc(dc)
{
if (dc != NULL)
{
// Save a copy of the dc
devConf = *dc;
this->dc = &devConf;
} else {
this->dc = NULL;
}
// setup algorithm
processSetup();
}
int RealtimeController::start() { return 0; }
int RealtimeController::restart() { return 0; }
int RealtimeController::pause() { return 0; }
int RealtimeController::stop() { return 0; }
bool RealtimeController::discover(char *) { return false; }
bool RealtimeController::doesPull() { return false; }
bool RealtimeController::doesPush() { return false; }
bool RealtimeController::doesLoad() { return false; }
void RealtimeController::getRealtimeData(RealtimeData &) { }
void RealtimeController::pushRealtimeData(RealtimeData &) { } // update realtime data with current values
void
RealtimeController::processRealtimeData(RealtimeData &rtData)
{
if (!dc) return; // no config
// setup the algorithm or lookup tables
// for the device postprocessing type
switch(dc->postProcess) {
case 0 : // nothing!
break;
case 1 : // Kurt Kinetic - Cyclone
{
double mph = rtData.getSpeed() * MILES_PER_KM;
// using the algorithm from http://www.kurtkinetic.com/powercurve.php
rtData.setWatts((6.481090) * mph + (0.020106) * (mph*mph*mph));
}
break;
case 2 : // Kurt Kinetic - Road Machine
{
double mph = rtData.getSpeed() * MILES_PER_KM;
// using the algorithm from http://www.kurtkinetic.com/powercurve.php
rtData.setWatts((5.244820) * mph + (0.01968) * (mph*mph*mph));
}
break;
case 3 : // Cyclops Fluid 2
{
double mph = rtData.getSpeed() * MILES_PER_KM;
// using the algorithm from:
// http://thebikegeek.blogspot.com/2009/12/while-we-wait-for-better-and-better.html
rtData.setWatts((0.0115*(mph*mph*mph)) - ((0.0137)*(mph*mph)) + ((8.9788)*(mph)));
}
break;
case 4 : // BT-ATS - BT Advanced Training System
{
// v is expressed in revs/second
double v = rtData.getWheelRpm()/60.0;
// using the algorithm from Steven Sansonetti of BT:
// This is a 3rd order polynomial, where P = av3 + bv2 + cv + d
// where:
double a = 2.90390167E-01; // ( 0.290390167)
double b = - 4.61311774E-02; // ( -0.0461311774)
double c = 5.92125507E-01; // (0.592125507)
double d = 0.0;
rtData.setWatts(a*v*v*v + b*v*v +c*v + d);
}
case 5 : // Lemond Revolution
{
double V = rtData.getSpeed() * 0.277777778;
// Tom Anhalt spent a lot of time working this all out
// for the data / analysis see: http://wattagetraining.com/forum/viewtopic.php?f=2&t=335
rtData.setWatts((0.21*pow(V,3))+(4.25*V));
}
break;
default : // unknown - do nothing
break;
}
// if calculating but no cadence then power must be set to zero
if (dc->postProcess && !rtData.getCadence()) rtData.setWatts(0);
}
// for future devices, we may need to setup algorithmic tables etc
void
RealtimeController::processSetup()
{
if (!dc) return; // no config
// setup the algorithm or lookup tables
// for the device postProcessing type
switch(dc->postProcess) {
case 0 : // nothing!
break;
case 1 : // TODO Kurt Kinetic - use an algorithm...
case 2 : // TODO Kurt Kinetic - use an algorithm...
break;
case 3 : // TODO Cyclops Fluid 2 - use an algorithm
break;
case 4 : // TODO BT-ATS - BT Advanced Training System - use an algorithm
break;
default : // unknown - do nothing
break;
}
}