mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
PeakPowerIndex, UserChartData and Overview Fixups
.. working with user charts to plot configured CP versus the trend
in power indexes led to some new code and a few fixups:
* new metric PeakPowerIndex is the best PowerIndex value for the
ride based upon power mean maximal data. It is not computed for
intervals.
* overview chart default config shows the PeakPowerIndex instead
of Power Model which was blank and unimplemented.
* the overview chart was not in the window registry, it must have
been removed by accident in a cut and paste incident
* the 'activity' function is userchartdata was not called, the code
was not included (it iterates over samples, but not activities)
This commit is contained in:
@@ -200,7 +200,7 @@ OverviewWindow::setConfiguration(QString config)
|
||||
newCard(tr("Intensity"), 3, 0, 9, Card::METRIC, "coggan_if");
|
||||
newCard(tr("Power"), 3, 1, 5, Card::METRIC, "average_power");
|
||||
newCard(tr("Power Zones"), 3, 2, 11, Card::ZONE, RideFile::watts);
|
||||
newCard(tr("Power Model"), 3, 3, 17);
|
||||
newCard(tr("Peak Power Index"), 3, 3, 17, Card::METRIC, "peak_power_index");
|
||||
|
||||
// column 4
|
||||
newCard(tr("Distance"), 4, 0, 9, Card::METRIC, "total_distance");
|
||||
|
||||
@@ -153,7 +153,7 @@ UserChart::setRide(RideItem *item)
|
||||
|
||||
// re-create program (may be edited)
|
||||
if (series.user1 != NULL) delete static_cast<UserChartData*>(series.user1);
|
||||
series.user1 = new UserChartData(context, this, series.string1);
|
||||
series.user1 = new UserChartData(context, this, series.string1, rangemode);
|
||||
connect(static_cast<UserChartData*>(series.user1)->program, SIGNAL(annotateLabel(QStringList&)), this, SLOT(annotateLabel(QStringList&)));
|
||||
|
||||
// cast so we can work with it
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
#include "RideMetric.h"
|
||||
#include "UserChartData.h"
|
||||
#include "DataFilter.h"
|
||||
#include "Athlete.h"
|
||||
|
||||
UserChartData::UserChartData(Context *context, UserChart *parent, QString script) : context(context), script(script)
|
||||
UserChartData::UserChartData(Context *context, UserChart *parent, QString script, bool rangemode) : context(context), script(script), rangemode(rangemode)
|
||||
{
|
||||
// compile the program - built in a context that can close.
|
||||
program = new DataFilter(NULL, context, script);
|
||||
@@ -70,13 +71,36 @@ UserChartData::compute(RideItem *item, Specification spec, DateRange dr)
|
||||
}
|
||||
|
||||
// process samples, if there are any and a function exists
|
||||
if (!spec.isEmpty(item->ride()) && fsample) {
|
||||
RideFileIterator it(item->ride(), spec);
|
||||
if (rangemode) {
|
||||
if (factivity) {
|
||||
|
||||
while(it.hasNext()) {
|
||||
struct RideFilePoint *point = it.next();
|
||||
root->eval(rt, fsample, 0, 0, const_cast<RideItem*>(item), point, NULL, spec, dr);
|
||||
FilterSet fs;
|
||||
fs.addFilter(context->isfiltered, context->filters);
|
||||
fs.addFilter(context->ishomefiltered, context->homeFilters);
|
||||
Specification spec;
|
||||
spec.setFilterSet(fs);
|
||||
|
||||
// loop through rides for daterange
|
||||
foreach(RideItem *ride, context->athlete->rideCache->rides()) {
|
||||
|
||||
if (!dr.pass(ride->dateTime.date())) continue; // relies upon the daterange being passed to eval...
|
||||
if (!spec.pass(ride)) continue; // relies upon the daterange being passed to eval...
|
||||
|
||||
|
||||
root->eval(rt, factivity, 0, 0, const_cast<RideItem*>(ride), NULL, NULL, spec, dr);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!spec.isEmpty(item->ride()) && fsample) {
|
||||
RideFileIterator it(item->ride(), spec);
|
||||
|
||||
while(it.hasNext()) {
|
||||
struct RideFilePoint *point = it.next();
|
||||
root->eval(rt, fsample, 0, 0, const_cast<RideItem*>(item), point, NULL, spec, dr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// finalise computation
|
||||
|
||||
@@ -31,7 +31,7 @@ class UserChartData : public QObject {
|
||||
public:
|
||||
|
||||
// new program
|
||||
UserChartData(Context *context, UserChart *parent, QString script);
|
||||
UserChartData(Context *context, UserChart *parent, QString script, bool rangemode);
|
||||
~UserChartData();
|
||||
|
||||
// Compute from samples
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
|
||||
// script and "compiled" program
|
||||
QString script;
|
||||
bool rangemode;
|
||||
DataFilter *program;
|
||||
Leaf *root;
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ GcWindowRegistry* GcWindows;
|
||||
void
|
||||
GcWindowRegistry::initialize()
|
||||
{
|
||||
static GcWindowRegistry GcWindowsInit[34] = {
|
||||
static GcWindowRegistry GcWindowsInit[35] = {
|
||||
// name GcWinID
|
||||
{ VIEW_HOME|VIEW_DIARY, tr("User Chart"),GcWindowTypes::UserTrends },
|
||||
{ VIEW_HOME|VIEW_DIARY, tr("Trends"),GcWindowTypes::LTM },
|
||||
@@ -90,6 +90,7 @@ GcWindowRegistry::initialize()
|
||||
//{ VIEW_HOME|VIEW_DIARY, tr("Performance Manager"),GcWindowTypes::PerformanceManager },
|
||||
{ VIEW_ANALYSIS, tr("User Chart "),GcWindowTypes::UserAnalysis },
|
||||
{ VIEW_HOME|VIEW_DIARY, tr("User Defined"),GcWindowTypes::UserTrends },
|
||||
{ VIEW_ANALYSIS, tr("Overview"),GcWindowTypes::Overview },
|
||||
{ VIEW_ANALYSIS|VIEW_INTERVAL, tr("Summary"),GcWindowTypes::RideSummary },
|
||||
{ VIEW_ANALYSIS, tr("Details"),GcWindowTypes::MetadataWindow },
|
||||
{ VIEW_ANALYSIS, tr("Summary and Details"),GcWindowTypes::Summary },
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "Banister.h"
|
||||
|
||||
#include "RideMetric.h"
|
||||
#include "RideFileCache.h"
|
||||
#include "Athlete.h"
|
||||
#include "Context.h"
|
||||
#include "Settings.h"
|
||||
@@ -650,4 +651,62 @@ class PowerIndex : public RideMetric {
|
||||
RideMetric *clone() const { return new PowerIndex(*this); }
|
||||
};
|
||||
|
||||
static bool countAdded = RideMetricFactory::instance().addMetric(PowerIndex());
|
||||
class PeakPowerIndex : public RideMetric {
|
||||
Q_DECLARE_TR_FUNCTIONS(PeakPowerIndex)
|
||||
public:
|
||||
|
||||
PeakPowerIndex()
|
||||
{
|
||||
setSymbol("peak_power_index");
|
||||
setInternalName("PeakPowerIndex");
|
||||
setPrecision(1);
|
||||
setType(Peak); // not even sure aggregation makes sense
|
||||
}
|
||||
void initialize() {
|
||||
setName(tr("PeakPowerIndex"));
|
||||
setMetricUnits(tr("%"));
|
||||
setImperialUnits(tr("%"));
|
||||
setDescription(tr("Peak Power Index"));
|
||||
}
|
||||
|
||||
void compute(RideItem *item, Specification spec, const QHash<QString,RideMetric*> &) {
|
||||
|
||||
// no ride or no samples or is interval (metric only valid for a ride)
|
||||
if (spec.isEmpty(item->ride()) || spec.secsStart() != -1) {
|
||||
setValue(RideFile::NIL);
|
||||
setCount(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate for this interval/ride
|
||||
double peakpix = 0;
|
||||
if (item->ride()->areDataPresent()->watts) {
|
||||
|
||||
QVector<float>vector;
|
||||
MeanMaxComputer thread1(item->ride(), vector, RideFile::watts);
|
||||
thread1.run();
|
||||
thread1.wait();
|
||||
|
||||
// calculate peak power index, starting from 3 mins, 0=out of bounds
|
||||
for (int secs=180; secs<vector.count(); secs++) {
|
||||
double pix = powerIndex(vector[secs], secs, item->isRun);
|
||||
if (pix > peakpix) {
|
||||
peakpix=pix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// we could convert to linear work time model before
|
||||
// indexing, but they cancel out so no value in doing so
|
||||
setValue(peakpix);
|
||||
setCount(1);
|
||||
}
|
||||
|
||||
MetricClass classification() const { return Undefined; }
|
||||
MetricValidity validity() const { return Unknown; }
|
||||
RideMetric *clone() const { return new PeakPowerIndex(*this); }
|
||||
};
|
||||
|
||||
static bool countAdded = RideMetricFactory::instance().addMetric(PowerIndex()) &&
|
||||
RideMetricFactory::instance().addMetric(PeakPowerIndex());
|
||||
|
||||
@@ -161,7 +161,8 @@
|
||||
// 151 14 May 2019 Ale Martinez Added Time Recording and use it in Time in Zone Percentage
|
||||
// 152 20 May 2019 Ale Martinez Fixed Time in Zone Percentages to aggregate properly
|
||||
// 153 8 Dec 2019 Mark Liversedge Regenerate after v3.5 RC2/RC2X re-issue
|
||||
int DBSchemaVersion = 153;
|
||||
// 154 18 Apr 2020 Mark Liversedge Added PeakPowerIndex (only for full rides)
|
||||
int DBSchemaVersion = 154;
|
||||
|
||||
RideMetricFactory *RideMetricFactory::_instance;
|
||||
QVector<QString> RideMetricFactory::noDeps;
|
||||
|
||||
Reference in New Issue
Block a user