Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tests for bike power functions #2174

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
678facc
#2174 Added tests for bike power functions
drmason789 Mar 1, 2024
15d2753
#2174 restrict the samples when exploring the boundaries of the power…
drmason789 Mar 1, 2024
bf4bf1e
Merge remote-tracking branch 'remotes/origin/master' into bike_power_…
drmason789 Mar 7, 2024
c74fe53
#2174 moved erg test functionality into the new Erg folder from other PR
drmason789 Mar 7, 2024
6fc5022
Merge remote-tracking branch 'remotes/origin/master' into bike_power_…
drmason789 Mar 19, 2024
d9c9f29
Merge remote-tracking branch 'remotes/origin/master' into bike_power_…
drmason789 Mar 25, 2024
e335ac2
#2174 added minmax type and introduced minimum and maximum resistance…
drmason789 Mar 25, 2024
2ab31e8
#2174 avoid template in cpp
drmason789 Mar 26, 2024
6d76f98
#2174 added bike cadence limits.
drmason789 Mar 26, 2024
26d2aac
#2174
drmason789 Mar 26, 2024
439570b
#2174
drmason789 Mar 27, 2024
d2be67c
#2174 removed typo
drmason789 Mar 27, 2024
ce54799
#2174 consistent interface for bike::wattsFromResistance
drmason789 Mar 27, 2024
6e018a1
#2174 added tests for conversion to and from resistance and Peloton r…
drmason789 Mar 27, 2024
55cb801
#2174 increase use of minmax<T> in test code. Some work to make Pelot…
drmason789 Mar 29, 2024
30dfa77
Merge branch 'cagnulein:master' into bike_power_tests
drmason789 Mar 29, 2024
a561444
Merge branch 'cagnulein:master' into bike_power_tests
drmason789 Apr 2, 2024
2ca3644
#2174 replaced powerFromResistanceRequest with wattsFromResistance
drmason789 Apr 2, 2024
da9ebd8
Merge branch 'bike_power_tests' of https://github.com/drmason789/qdom…
drmason789 Apr 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/devices/apexbike/apexbike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,7 @@ void apexbike::update() {
}

if (requestResistance != -1) {
if (requestResistance > max_resistance)
requestResistance = max_resistance;
else if (requestResistance <= 0)
requestResistance = 1;
requestResistance = this->resistanceLimits().clip(requestResistance);

if (requestResistance != currentResistance().value()) {
qDebug() << QStringLiteral("writing resistance ") + QString::number(requestResistance);
Expand Down
4 changes: 3 additions & 1 deletion src/devices/apexbike/apexbike.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ class apexbike : public bike {
apexbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset, double bikeResistanceGain);
bool connected() override;

minmax<resistance_t> resistanceLimits() override {return minmax<resistance_t>(1,32);}

private:
const resistance_t max_resistance = 32;

void btinit();
void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false,
bool wait_for_response = false);
Expand Down
69 changes: 64 additions & 5 deletions src/devices/bike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,22 @@ void bike::changeInclination(double grade, double percentage) {
}

// originally made for renphobike, but i guess it could be very generic
uint16_t bike::powerFromResistanceRequest(resistance_t requestResistance) {
uint16_t bike::wattsFromResistance(resistance_t resistance) {
auto minMaxR = this->resistanceLimits();
if(resistance<=minMaxR.min())
return 0;

// this bike has resistance level to N.m so the formula is Power (kW) = Torque (N.m) x Speed (RPM) / 9.5488
double cadence = RequestedCadence.value();
double cadence = this->RequestedCadence.value();
if (cadence <= 0)
cadence = Cadence.value();
return (requestResistance * cadence) / 9.5488;

if(cadence <= this->cadenceLimits().min())
return 0;

resistance = minMaxR.clip(resistance);

return (resistance * this->cadenceLimits().clip(cadence)) / 9.5488;
}

void bike::changeRequestedPelotonResistance(int8_t resistance) { RequestedPelotonResistance = resistance; }
Expand Down Expand Up @@ -103,8 +113,57 @@ uint8_t bike::fanSpeed() { return FanSpeed; }
bool bike::connected() { return false; }
uint16_t bike::watts() { return 0; }
metric bike::pelotonResistance() { return m_pelotonResistance; }
resistance_t bike::pelotonToBikeResistance(int pelotonResistance) { return pelotonResistance; }
resistance_t bike::resistanceFromPowerRequest(uint16_t power) { return power / 10; } // in order to have something

resistance_t bike::pelotonToBikeResistance(int pelotonResistance) {

auto minMaxR = this->resistanceLimits();

auto pr0 = bikeResistanceToPeloton(minMaxR.min());

if(pelotonResistance<=pr0)
return minMaxR.min();

for (resistance_t i = 1+minMaxR.min(); i < minMaxR.max(); i++) {
auto pr1 = bikeResistanceToPeloton(i);
if (pr0 <= pelotonResistance && pr1 >= pelotonResistance) {
return i;
}
pr0 = pr1;
}

return minMaxR.max();
}
resistance_t bike::resistanceFromPowerRequest(uint16_t power) {
qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value();

QSettings settings;

double watt_gain = settings.value(QZSettings::watt_gain, QZSettings::default_watt_gain).toDouble();
double watt_offset = settings.value(QZSettings::watt_offset, QZSettings::default_watt_offset).toDouble();

auto minMaxR = this->resistanceLimits();

uint16_t power0 = (wattsFromResistance(minMaxR.min()) * watt_gain) + watt_offset;

// Is the requested power at or below the power of the minimum resistance the device provides?
if (power <= power0)
return minMaxR.min();

// Search from the 1st resistance level above minimum to the maximum
for (resistance_t i = 1 + minMaxR.min(); i < minMaxR.max(); i++) {
uint16_t power1 = wattsFromResistance(i)*watt_gain + watt_offset;

if(power0 <= power && power1>=power) {
qDebug() << QStringLiteral("resistanceFromPowerRequest") << power0 << power1 << power;
return i;
}

power0 = power1;
}

// requested power requires resistance beyond the maximum
return minMaxR.max();
}
void bike::cadenceSensor(uint8_t cadence) { Cadence.setValue(cadence); }
void bike::powerSensor(uint16_t power) { m_watt.setValue(power, false); }

Expand Down
8 changes: 7 additions & 1 deletion src/devices/bike.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ class bike : public bluetoothdevice {
bool connected() override;
virtual uint16_t watts();
virtual resistance_t pelotonToBikeResistance(int pelotonResistance);
virtual double bikeResistanceToPeloton(double resistance) { return resistance; }
virtual resistance_t resistanceFromPowerRequest(uint16_t power);
virtual uint16_t powerFromResistanceRequest(resistance_t requestResistance);
virtual uint16_t wattsFromResistance(resistance_t resistance);

virtual bool ergManagedBySS2K() { return false; }
bluetoothdevice::BLUETOOTH_TYPE deviceType() override;
metric pelotonResistance();
Expand All @@ -48,6 +50,10 @@ class bike : public bluetoothdevice {
virtual bool inclinationAvailableByHardware();
bool ergModeSupportedAvailableByHardware() { return ergModeSupported; }

/**
* @brief The inclusive minimum and maximum cadence values that power can be calculated for.
*/
virtual minmax<int16_t> cadenceLimits() { return minmax<int16_t>(0, 250); }
public Q_SLOTS:
void changeResistance(resistance_t res) override;
virtual void changeCadence(int16_t cad);
Expand Down
11 changes: 0 additions & 11 deletions src/devices/bkoolbike/bkoolbike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,17 +732,6 @@ void bkoolbike::controllerStateChanged(QLowEnergyController::ControllerState sta
}
}

resistance_t bkoolbike::pelotonToBikeResistance(int pelotonResistance) {
for (resistance_t i = 0; i < max_resistance; i++) {
if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) {
return i;
}
}
if (pelotonResistance < bikeResistanceToPeloton(1))
return 0;
else
return max_resistance;
}

double bkoolbike::bikeResistanceToPeloton(double resistance) {
QSettings settings;
Expand Down
6 changes: 2 additions & 4 deletions src/devices/bkoolbike/bkoolbike.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,18 @@ class bkoolbike : public bike {
bkoolbike(bool noWriteResistance, bool noHeartService);
void changePower(int32_t power) override;
bool connected() override;
resistance_t pelotonToBikeResistance(int pelotonResistance);

minmax<resistance_t> resistanceLimits() override {return minmax<resistance_t>(1,100);}
private:
void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false,
bool wait_for_response = false);
void startDiscover();
void forceInclination(double inclination);
uint16_t watts() override;
double bikeResistanceToPeloton(double resistance);
double bikeResistanceToPeloton(double resistance) override;

QTimer *refresh;

const int max_resistance = 100;

QList<QLowEnergyService *> gattCommunicationChannelService;
QLowEnergyCharacteristic gattWriteCharControlPointId;
QLowEnergyCharacteristic gattWriteCharCustomId;
Expand Down
2 changes: 1 addition & 1 deletion src/devices/bluetooth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2293,7 +2293,7 @@ void bluetooth::connectedAndDiscovered() {
#else
settings.setValue(QZSettings::ftms_accessory_address, b.deviceUuid().toString());
#endif
ftmsAccessory = new smartspin2k(false, false, this->device()->maxResistance(), (bike *)this->device());
ftmsAccessory = new smartspin2k(false, false, this->device()->resistanceLimits().max(), (bike *)this->device());
// connect(heartRateBelt, SIGNAL(disconnected()), this, SLOT(restart()));

connect(ftmsAccessory, &smartspin2k::debug, this, &bluetooth::debug);
Expand Down
1 change: 0 additions & 1 deletion src/devices/bluetoothdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ QStringList bluetoothdevice::metrics() {
return r;
}

resistance_t bluetoothdevice::maxResistance() { return 100; }

uint8_t bluetoothdevice::metrics_override_heartrate() {

Expand Down
13 changes: 12 additions & 1 deletion src/devices/bluetoothdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define BLUETOOTHDEVICE_H

#include "definitions.h"
#include "minmax.h"
#include "metric.h"
#include "qzsettings.h"

Expand Down Expand Up @@ -420,10 +421,20 @@ class bluetoothdevice : public QObject {
*/
virtual uint8_t metrics_override_heartrate();

/**
* @brief Overridden in subclasses to specify the range of resistance levels supported by the device.
*/
virtual minmax<resistance_t> resistanceLimits() { return minmax<resistance_t>(0,100); }

/**
* @brief Overridden in subclasses to specify the maximum resistance level supported by the device.
*/
virtual resistance_t maxResistance();
// virtual resistance_t maxResistance() { return 100; }

/**
* @brief Overridden in subclasses to specify the minimum resistance level supported by the device.
*/
// virtual resistance_t minResistance() { return 0; }

public Q_SLOTS:
virtual void start();
Expand Down
6 changes: 1 addition & 5 deletions src/devices/chronobike/chronobike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,7 @@ void chronobike::update() {
}

if (requestResistance != -1) {
if (requestResistance > 15) {
requestResistance = 15;
} else if (requestResistance == 0) {
requestResistance = 1;
}
requestResistance = this->resistanceLimits().clip(requestResistance);

if (requestResistance != currentResistance().value()) {
emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance));
Expand Down
2 changes: 2 additions & 0 deletions src/devices/chronobike/chronobike.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class chronobike : public bike {
chronobike(bool noWriteResistance, bool noHeartService);
bool connected() override;

minmax<resistance_t> resistanceLimits() override {return minmax<resistance_t>(1,15);}

private:
// void writeCharacteristic(uint8_t *data, uint8_t data_len, QString info, bool disable_log = false, // Unused
// bool wait_for_response = false);
Expand Down
94 changes: 17 additions & 77 deletions src/devices/computrainerbike/computrainerbike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,28 +74,6 @@ computrainerbike::computrainerbike(bool noWriteResistance, bool noHeartService,
// ********************************************************************************************************
}

resistance_t computrainerbike::resistanceFromPowerRequest(uint16_t power) {
qDebug() << QStringLiteral("resistanceFromPowerRequest") << Cadence.value();

QSettings settings;

double watt_gain = settings.value(QZSettings::watt_gain, QZSettings::default_watt_gain).toDouble();
double watt_offset = settings.value(QZSettings::watt_offset, QZSettings::default_watt_offset).toDouble();

for (resistance_t i = 1; i < max_resistance; i++) {
if (((wattsFromResistance(i) * watt_gain) + watt_offset) <= power &&
((wattsFromResistance(i + 1) * watt_gain) + watt_offset) >= power) {
qDebug() << QStringLiteral("resistanceFromPowerRequest")
<< ((wattsFromResistance(i) * watt_gain) + watt_offset)
<< ((wattsFromResistance(i + 1) * watt_gain) + watt_offset) << power;
return i;
}
}
if (power < ((wattsFromResistance(1) * watt_gain) + watt_offset))
return 1;
else
return max_resistance;
}

uint16_t computrainerbike::wattsFromResistance(resistance_t resistance) {

Expand Down Expand Up @@ -183,13 +161,9 @@ void computrainerbike::innerWriteResistance() {
bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool();

if (requestResistance != -1) {
if (requestResistance > max_resistance) {
requestResistance = max_resistance;
} else if (requestResistance < min_resistance) {
requestResistance = min_resistance;
} else if (requestResistance == 0) {
requestResistance = 1;
}

requestResistance = resistanceLimits().clip(requestResistance);


if (requestResistance != currentResistance().value()) {
emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance));
Expand Down Expand Up @@ -342,55 +316,21 @@ bool computrainerbike::inclinationAvailableByHardware() {
return false;
}

std::vector<int> computrainerbike::bikeToPeloton({ 10,20,25,30,35,40,45,50,55,60,65,70,75,80,85,100 });

double computrainerbike::bikeResistanceToPeloton(double resistance) {

auto r = this->resistanceLimits().clip(resistance);

return bikeToPeloton[r-1];
}

resistance_t computrainerbike::pelotonToBikeResistance(int pelotonResistance) {
if (pelotonResistance <= 10) {
return 1;
}
if (pelotonResistance <= 20) {
return 2;
}
if (pelotonResistance <= 25) {
return 3;
}
if (pelotonResistance <= 30) {
return 4;
}
if (pelotonResistance <= 35) {
return 5;
}
if (pelotonResistance <= 40) {
return 6;
}
if (pelotonResistance <= 45) {
return 7;
}
if (pelotonResistance <= 50) {
return 8;
}
if (pelotonResistance <= 55) {
return 9;
}
if (pelotonResistance <= 60) {
return 10;
}
if (pelotonResistance <= 65) {
return 11;
}
if (pelotonResistance <= 70) {
return 12;
}
if (pelotonResistance <= 75) {
return 13;
}
if (pelotonResistance <= 80) {
return 14;
}
if (pelotonResistance <= 85) {
return 15;
}
if (pelotonResistance <= 100) {
return 16;
}

for(int i=0; i<bikeToPeloton.size(); i++)
if(pelotonResistance <= bikeToPeloton[i])
return (resistance_t)(i+1);

return Resistance.value();
}

Expand Down
14 changes: 9 additions & 5 deletions src/devices/computrainerbike/computrainerbike.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,19 @@ class computrainerbike : public bike {
computrainerbike(bool noWriteResistance, bool noHeartService, uint8_t bikeResistanceOffset,
double bikeResistanceGain);
resistance_t pelotonToBikeResistance(int pelotonResistance) override;
resistance_t resistanceFromPowerRequest(uint16_t power) override;
resistance_t maxResistance() override { return max_resistance; }
virtual double bikeResistanceToPeloton(double resistance) override;

minmax<resistance_t> resistanceLimits() override {return minmax<resistance_t>(1,16);} // limits inferred from Peloton conversion
bool inclinationAvailableByHardware() override;
bool connected() override;

uint16_t wattsFromResistance(resistance_t resistance) override;
private:
resistance_t max_resistance = 100;
resistance_t min_resistance = -20;
uint16_t wattsFromResistance(resistance_t resistance);
/**
* @brief A mapping of peloton->(resistance-1)
*/
static std::vector<int> bikeToPeloton;

double GetDistanceFromPacket(QByteArray packet);
QTime GetElapsedFromPacket(QByteArray packet);
void btinit();
Expand Down
6 changes: 1 addition & 5 deletions src/devices/cscbike/cscbike.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,7 @@ void cscbike::update() {
}

if (requestResistance != -1) {
if (requestResistance > 15) {
requestResistance = 15;
} else if (requestResistance == 0) {
requestResistance = 1;
}
requestResistance = this->resistanceLimits().clip(requestResistance);

if (requestResistance != currentResistance().value()) {
emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance));
Expand Down
Loading
Loading