Files
GoldenCheetah/src/StressCalculator.cpp
Mark Liversedge d0b009c922 Data Filter (Part 3 of 3)
Last part of the search/filter functionality;

* SearchBox now incorporates filter and search
  with a new widget. We can update this widget
  to include more fancy UI/Interactions without
  having to change the ride list or charts etc.

* Added search/filter widget to the relevant charts
  and screens; Metrics, TreeMap, CP, Histogram,
  Activity Log, Ride list (refactored out of MainWindow)

* Added namedsearches.xml and adding/selecting them
  from a drop down menu on the search box.

* Fixed some performance bugs related to duplicate
  signals and redraw/reprocessing. Also ensured that
  CLucene remains optional -- but means no search or
  filter functionality unless it is available.
2012-11-05 15:44:01 +00:00

213 lines
6.4 KiB
C++

#include "StressCalculator.h"
#include "MetricAggregator.h"
#include "RideMetric.h"
#include "RideItem.h"
#include "MainWindow.h"
#include <stdio.h>
#include <QSharedPointer>
#include <QProgressDialog>
StressCalculator::StressCalculator (
QString cyclist,
QDateTime startDate,
QDateTime endDate,
double initialSTS = 0,
double initialLTS = 0,
int shortTermDays = 7,
int longTermDays = 42) :
startDate(startDate), endDate(endDate), shortTermDays(shortTermDays),
longTermDays(longTermDays),
initialSTS(initialSTS), initialLTS(initialLTS), lastDaysIndex(-1)
{
// calc SB for today or tomorrow?
showSBToday = appsettings->cvalue(cyclist, GC_SB_TODAY).toInt();
days = startDate.daysTo(endDate);
// make vectors 1 larger in case there is a ride for today.
// see calculateStress()
stsvalues.resize(days+2);
ltsvalues.resize(days+2);
sbvalues.resize(days+2);
xdays.resize(days+2);
list.resize(days+2);
ltsramp.resize(days+2);
stsramp.resize(days+2);
lte = (double)exp(-1.0/longTermDays);
ste = (double)exp(-1.0/shortTermDays);
}
double StressCalculator::max(void) {
double max = 0.0;
for(int i = 0; i < days; i++) {
if (stsvalues[i] > max) max = stsvalues[i];
if (ltsvalues[i] > max) max = ltsvalues[i]; // unlikely..
if (sbvalues[i] > max) max = sbvalues[i]; // really unlikely.
}
return max;
}
double StressCalculator::min(void) {
double min = 100.0;
for(int i = 0; i < days; i++) {
if (sbvalues[i] < min) min = sbvalues[i];
if (ltsvalues[i] < min) min = ltsvalues[i]; // unlikely..
if (stsvalues[i] < min) min = stsvalues[i]; // really unlikely
}
return min;
}
void StressCalculator::calculateStress(MainWindow *main, QString, const QString &metric, bool isfilter, QStringList filter)
{
// get all metric data from the year 1900 - 3000
QList<SummaryMetrics> results;
// get metrics
results = main->metricDB->getAllMetricsFor(QDateTime(QDate(1900,1,1)), QDateTime(QDate(3000,1,1)));
if (isfilter) {
// remove any we don't have filtered
QList<SummaryMetrics> filteredresults;
foreach (SummaryMetrics x, results) {
if (filter.contains(x.getFileName()))
filteredresults << x;
}
results = filteredresults;
}
if (results.count() == 0) return; // no ride files found
// set start and enddate to maximum maximum required date range
// remember the date range required so we can truncate afterwards
QDateTime startDateNeeded = startDate;
QDateTime endDateNeeded = endDate;
startDate = startDate < results[0].getRideDate() ? startDate : results[0].getRideDate();
endDate = endDate > results[results.count()-1].getRideDate() ? endDate : results[results.count()-1].getRideDate();
int maxarray = startDate.daysTo(endDate) +2; // from zero plus tomorrows SB!
stsvalues.resize(maxarray);
ltsvalues.resize(maxarray);
sbvalues.resize(maxarray);
xdays.resize(maxarray);
list.resize(maxarray);
ltsramp.resize(maxarray);
stsramp.resize(maxarray);
for (int i=0; i<results.count(); i++)
addRideData(results[i].getForSymbol(metric), results[i].getRideDate());
// ensure the last day is covered ...
addRideData(0.0, endDate);
// now truncate the data series to the requested date range
int firstindex = startDate.daysTo(startDateNeeded);
int lastindex = startDate.daysTo(endDateNeeded)+2; // for today and tomorrow SB
// zap the back
if (lastindex < maxarray) {
stsvalues.remove(lastindex, maxarray-lastindex);
ltsvalues.remove(lastindex, maxarray-lastindex);
sbvalues.remove(lastindex, maxarray-lastindex);
xdays.remove(lastindex, maxarray-lastindex);
list.remove(lastindex, maxarray-lastindex);
stsramp.remove(lastindex, maxarray-lastindex);
ltsramp.remove(lastindex, maxarray-lastindex);
}
// now zap the front
if (firstindex) {
stsvalues.remove(0, firstindex);
ltsvalues.remove(0, firstindex);
ltsramp.remove(0, firstindex);
stsramp.remove(0, firstindex);
sbvalues.remove(0, firstindex);
xdays.remove(0, firstindex);
list.remove(0, firstindex);
}
// reapply the requested date range
startDate = startDateNeeded;
endDate = endDateNeeded;
days = startDate.daysTo(endDate) + 1; // include today
}
/*
* calculate each day's STS and LTS. The daily BS values are in
* the list. if there aren't enough days in the list yet, we fake
* the missing days using the supplied initial value for each day.
* STS and LTS are calculated up to but not including todays' ride.
* if there are two rides per day the second one is added to the first
* so the BS/day is correct.
*/
void StressCalculator::addRideData(double BS, QDateTime rideDate) {
int daysIndex = startDate.daysTo(rideDate);
// fill in any missing days before today
int d;
for (d = lastDaysIndex + 1; d < daysIndex ; d++) {
list[d] = 0.0; // no ride
calculate(d);
}
// ignore stuff from before start date
if(daysIndex < 0) return;
// today
list[daysIndex] += BS;
calculate(daysIndex);
lastDaysIndex = daysIndex;
}
/*
* calculate stress (in Bike Score units) using
* stress = today's BS * (1 - exp(-1/days)) + yesterday's stress * exp(-1/days)
* where days is the time period of concern- 7 for STS and 42 for LTS.
*
* exp(-1/days) for short and long term is calculated when the
* class is instantiated.
*
*/
void StressCalculator::calculate(int daysIndex) {
double lastLTS, lastSTS;
// LTS
if (daysIndex == 0)
lastLTS = initialLTS;
else
lastLTS = ltsvalues[daysIndex-1];
ltsvalues[daysIndex] = (list[daysIndex] * (1.0 - lte)) + (lastLTS * lte);
// STS
if (daysIndex == 0)
lastSTS = initialSTS;
else
lastSTS = stsvalues[daysIndex-1];
stsvalues[daysIndex] = (list[daysIndex] * (1.0 - ste)) + (lastSTS * ste);
// SB (stress balance) long term - short term
// XXX FIXED BUG WHERE SB WAS NOT SHOWN ON THE NEXT DAY!
if (daysIndex == 0) sbvalues[daysIndex]=0;
sbvalues[daysIndex+(showSBToday ? 0 : 1)] = ltsvalues[daysIndex] - stsvalues[daysIndex] ;
// xdays
xdays[daysIndex] = daysIndex+1;
// ramp
if (daysIndex > 0) {
stsramp[daysIndex] = stsvalues[daysIndex] - stsvalues[daysIndex-1];
ltsramp[daysIndex] = ltsvalues[daysIndex] - ltsvalues[daysIndex-1];
}
}