Calibration calculations – part 2

Apologies for the delay in posting this update, was away for a few days in Norway. An awesome place to visit – but pricey (not helped by the grim GBP exchange rate).

Calibration from PowerTap data

f(x) = a*x*x + b*x + c

Multiple Data Fitting Results
level_1     48.37   a:0.031647 b:3.0117 c:-6.2383
level_12    51.19   a:0.032029 b:3.3858 c:-5.8462
level_23    42.64   a:0.042916 b:4.0801 c:-14.053
level_34    44.03   a:0.052877 b:5.368  c:-19.749
level_45    34.98   a:0.08673  b:6.3456 c:-14.823
level_56    30.46   a:0.0332   b:11.926 c:-53.106
level_67    33.22   a:0.17617  b:9.3606 c:-30.054
level_78    37.14   a:0.18789  b:11.523 c:-36.988
level_89    22.27   a:0.24039  b:13.578 c:-42.477
level_100    21.4   a:0.1618   b:16.801 c:-59.99

To get more accurate power data, I collected a couple of hours of data, riding at 10 different resistance levels to match the 1-10 standard resistance lever positions. This data was then fed into the xcrvfit curve fitting software to produce the above quadratic equations for power against speed at each resistance level. (These seem to be a better fit than the linear equations derived from the tacx graphs).

curve_fitting

To populate the lookup table, I also wanted to plot power against resistance at steady speeds. In order to get this, I filtered the original data by speed in a spreadsheet, and performed another curve fitting against these new data series. I’m not entirely happy with the outcome from this 2nd curve fitting (more details below), so I may perform this step again with some additional ride data.

curve_fitting2

Lookup table

Using the data collected above, I was able to calculate the resistance levels required to populate a 12×12 lookup table of speed vs power points.

The actual values in the lookup table have been trivially encoded (by adding 50 to the original 1-100 values). This allows the use of estimated values outside of this range to maintain the slope at the limits of the resistance adjustment, while remaining within a uint8_t datatype.

uint8_t lookup_table_1d[POWER_ROWS * SPEED_COLS] = {
/*   0,     5,  10,  15,  20,  25,  30,  35,  40,  45,  50,  55,  60,*/
/*  25,*/  51,  45,  40,  20,  25,  20,  20,  35,  40,  40,  49,  51,
/*  50,*/ 130,  91,  65,  20,  25,  20,  20,  35,  40,  40,  49,  51,
/*  75,*/ 170, 111,  83,  65,  25,  20,  20,  35,  40,  40,  49,  51,
/* 100,*/ 170, 130,  95,  78,  63,  20,  20,  35,  40,  40,  49,  51,
/* 150,*/ 170, 180, 114,  94,  83,  75,  54,  35,  40,  40,  49,  51,
/* 200,*/ 170, 180, 135, 107,  95,  85,  76,  70,  61,  40,  49,  51,
/* 250,*/ 170, 180, 165, 120, 105,  94,  86,  80,  74,  65,  49,  51,
/* 300,*/ 170, 180, 165, 133, 114, 101,  93,  87,  81,  73,  64,  57,
/* 350,*/ 170, 180, 165, 152, 123, 108,  99,  93,  87,  80,  76,  64,
/* 400,*/ 170, 180, 165, 152, 132, 115, 104,  98,  91,  85,  80,  76,
/* 450,*/ 170, 180, 165, 152, 142, 123, 108, 103,  95,  89,  85,  80,
/* 500,*/ 170, 180, 165, 152, 155, 131, 112, 108,  99,  93,  89,  85
};

Knowing the current speed and power, we can then index into this table to find the closest resistance value.

Interpolation

However using just the values at the 12×12 speed/power intersections would be very coarse, so we’ll interpolate between the surrounding four table points to get a more accurate value.

There will doubtless be much better explanations of bilinear interpolation out there on the internet, so I won’t try here, but basically it’s interpolating twice along one axis, and then once along the other axis using the intermediate values from the first step.

//      x1     x     x2
//       |     |      |
// y1---z11----------z21---
//       |     |      |
// y  ---|-----z------|----
//       |     |      |
// y2---z12----------z22---
//       |     |      |

Test ride

Here’s a screenshot from a new ergo session using the lookup table. It’s doing a reasonable job of tracking the target load, but still not as close as I’d like it to be.

ergo3

As mentioned above, I’m not very confident in the output from the 2nd curve fitting, so repeating this step with additional data may help. Alternatively, I suspect it may be just as quick to set a target power using the manual ergo mode of GC, and then tweak the resistance levels as necessary for each speed point in the table. That said, it’s still a lot of faffing around trying to get it spot on, so may be worth trying to trim the resistance based on real-time power data first.

Next post

I’ve had my fill of calibration for a while, so next I’ll be porting the microcontroller code to a USB part.

Advertisements