---------- bike_power.c ----- CUT HERE ----------
/*
bike_power.c April 13, 1993
by Ken Roberts (roberts@cs.columbia.edu)
Dept of Computer Science, Columbia University, New York
updated by Mark Grennan (markg@okcforum.oknorm.edu)
(mgrennan@outelecom.telecom.uoknorm.edu)
(CIS 76545,2506)
Oklahoma Office of State Finance, Oklahoma City, Oklahoma
This program is written in ANSI C. It has been successfully
compiled by the GNU gcc compiler and run under Unix. I
compiled it with the command:
# cc bike_power.c -o bike_power
If that produces error messages, then you have a non-ANSI
compiler. Either find an ANSI compiler (e.g. try "gcc"
instead of "cc") or edit the program to make it compatible
with your compiler (should be pretty straightforward).
Other compilers that are known to work are...
Turbo C
Turbo C++
Microsoft C 6.0
The initilaztion file (bike_pwr.ini) is processed first. command-line
flags are then processed. Therefore command-line options override
init file options.
The meanings of the command-line flags are given by
# bike_power +H
It does not matter if whitespace is put between the flag and
its following argument:
# bike_power -v25 -i.5 -n11 -g-.12
is exactly equivalent to
# bike_power -v 25.0 -i 0.5 -n 11 -g -0.12
Command-line arguments are applied in the order given. A
wild example is:
# bike_power +M -v10 -n13 -M -f5 -h 5 +M
which is processed as follows: Set the units to Metric, then
set the velocity V = 10 kph, and the number of table entries
N_entry = 13. Then set units to English, and set up the
English version of table format 5, which resets the value of
N_entry to 6. Then the headwind is 5 mph. Finally the table
is printed out in Metric units.
Usually it's better to first give any flags from the set {+M
+P +C -s -f} since they can affect the interpretation or
override the values of other flags. Also +P +C -v are all
mutually contradictory, since the program always takes one
and calculates the other two from it. (the default is -v).
The meanings of the columns in the output table are given by
# bike_power +O
All program internal values are in standard scientific
meter-kilogram-second (MKS) units. Conversions to other
units are made only at the point of input or output. See
below under "Conversion factors".
Accurate values for the various parameters: These are
difficult to come by. Good luck. Fortunately the lack of
accurate parameters does not prevent the investigation of
many interesting questions.
The comments contain derivations and discussions of the
various parameter values, and relate them to some published
sources. I got a lot of help from the book Frank R. Whitt
and David G. Wilson, Bicycling Science, (Second Edition),
MIT Press, 1982 hereafter referred to as "W&W".
You will surely want to customize this program, now that you
have the source. (Don't be deterred by lack of knowledge of
the details of the C programming language. It's really
pretty straightforward, once you find the variable you want
to change.) The most obvious change is to the default values
for the weights of the cyclist (Wc) and the machine (Wm).
You'll probably also want your own -s sets and -f formats.
Just go down to the appropriate sections under "Process
command line flags" and start editing.
*/
#include
/* Conversion factors */
#define mOs_per_miOhr 0.44704 /* meters/second per kilometers/hour */
#define mOs_per_kmOhr (1000.0 / 3600.0) /* meters/second per miles/hour */
#define Nt_per_lb 4.4482
#define kg_per_Nt 0.102
#define Watts_per_CalOhr 1.163 /* Watts per dietary Calories/hour */
/* 1 dietary Calorie == 1000 calories */
#define Watts_per_horsepower 745.700
double read_double_arg (int i);
int read_int_arg (int i);
void read_string_arg (int i, char* s);
void print_help();
void explain_table();
static char** argp;
char *skip_blanks ();
struct parse_list {
int p_length;
char *p_string;
};
struct parse_list config_lines[] = {
{5, "Power" }, /* 1 */
{8, "Calories" }, /* 2 */
{6, "Metric" }, /* 3 */
{7, "English" }, /* 4 */
{8, "No_Parms" }, /* 5 */
{2, "A1" }, /* 6 */
{2, "A2" }, /* 7 */
{10, "Metabolism" }, /* 8 */
{10, "Efficiency" }, /* 9 */
{5, "Grade" }, /* 10 */
{8, "Headwind" }, /* 11 */
{9, "Increment" }, /* 12 */
{7, "Entries" }, /* 13 */
{8, "Friction" }, /* 14 */
{10, "Drivetrain" }, /* 15 */
{8, "Velocity" }, /* 16 */
{11, "Bike_Weight" }, /* 17 */
{14, "Cyclist_Weight" }, /* 18 */
{10, "Cross_Wind" }, /* 19 */
{8, "Air_Temp" }, /* 20 */
{4, "Area" }, /* 21 */
{0, NULL }
};
/*
Air Density table for dry air between -30 to +44 degrees C
Taken from the Handbook of Chemistry and Physics, Thirtieth
Edition
This table does not include the changes for air pressure or
humity.
*/
double air_density[75] = {
1.5147, 1.5083, 1.5019, 1.4955, 1.4892, /* -30 3.6f */
1.4829, 1.4767, 1.4706, 1.4645, 1.4584, /* -25 */
1.3951, 1.3896, 1.3841, 1.3787, 1.3734, /* -20 */
1.3680, 1.3628, 1.3575, 1.3523, 1.3472, /* -15 */
1.3420, 1.3370, 1.3319, 1.3269, 1.3219, /* -10 */
1.3170, 1.3121, 1.3072, 1.3024, 1.2977, /* - 5 */
1.2929, 1.2882, 1.2835, 1.2789, 1.2742, /* 0 */
1.2697, 1.2651, 1.2606, 1.2561, 1.2517, /* 5 */
1.2472, 1.2428, 1.2385, 1.2342, 1.2299, /* 10 */
1.2256, 1.2214, 1.2171, 1.2130, 1.2088, /* 15 */
1.2047, 1.2006, 1.1965, 1.1925, 1.1885, /* 20 */
1.1845, 1.1805, 1.1766, 1.1727, 1.1688, /* 25 */
1.1649, 1.1611, 1.1573, 1.1535, 1.1498, /* 30 */
1.1460, 1.1423, 1.1387, 1.1350, 1.1314, /* 35 */
1.1277, 1.1242, 1.1206, 1.1170, 1.1135 /* 40c 138.6f */
};
void main(int argc, char* argv[])
{
int metric_flag = 0;
int display_parameters_flag = 1;
int v_given = 1;
int p_given = 0;
int at_given = 0;
int calOhr_given = 0;
int cross_wind = 0;
char arg_string[32];
int entry;
FILE *stream;
char temp[256];
char *c;
int i;
double D_a = 1.2047; /* Density of air at 20c */
double T_a = 20.0; /* Temp of the Air in C */
double A_c = 0.3080527; /* Area (frontal) of the cyclist in meters^2*/
double C_a = 0.90; /* Air resistance coefficient */
double A2 = 0.167; /* racing crouch (hands on crops, elbows bent) */
double A1 = 0.0;
/*
Force of air resistance
F_a = A2 * (V + H)^2 + A1 * (V + H)
From W&W p85ff, air resistance coefficient C_a
C_a = F_a / (dynamic_pressure_of_air * frontal_area)
Where F_a is force of air resistance. At bicycling speeds:
dynamic_pressure_of_air = air_density * (V + H)^2 / 2
where V + H is the relative air velocity.
So...
F_a = C_a * air_density * frontal_area * (V + H)^2 / 2
p90 suggests that the Reynolds number is in the ballpark of
200000, so there may be some advantage to wearing rough,
rather than smooth clothing.
air_density is 1.2047 kg/m^3 at 20^C = 68^F.
p91 suggests that roughly, C_a = 0.9 for a bicycle and rider.
F_a = (0.9 * 1.2047 / 2) * frontal_area * (V + H)^2
= 0.54 * frontal_area * (V + H)^2
p93 says that frontal_area = 0.33 m^2 (racing crouch)
frontal_area = 0.5 m^2 (erect tourist).
F_a = 0.17889795 * (V + H)^2 ==> A2 = 0.18 [racing crouch]
F_a = 0.2710575 * (V + H)^2 ==> A2 = 0.27 [upright sitting]
Derived from Bicycling magazine, August 1990, p98,
Typical values for A2: lb*hr^2/mi^2 Nt*s^2/m^2
standing 0.016 0.356
upright (hands on bar tops) 0.012 0.267
crouch (hands on drops, elbows locked) 0.0105 0.233
racing crouch (hands on crops, elbows bent) 0.0075 0.167
full downhill tuck 0.0065 0.145
Effect of drafting:
Bicycling magazine, around July 1990 says that the reduction
in total power requirements due to drafting a paceline of:
1 or more riders 20 mph 18%
(longer paceline provides 23 mph 27%
no additional reduction) 25 mph 27%
in the middle of a pack 25 mph 39%
Since those are reductions in total power output, A2 must be
reduced by a larger percentage than that. I get values like
following a paceline of
1 or more riders 25 mph A2 = 0.12
in the middle of a pack 25 mph A2 = 0.10
*/
double Wc = Nt_per_lb * 175.0; /* weight of cyclist [Newtons] */
/* current value is 150 pounds */
double Wm = Nt_per_lb * 23.0; /* weight of machine and clothing [Newtons] */
/* current value is 25 pounds */
double W; /* weight = weight_cyclist + weight_machine [Newtons] */
double R = 0.0047; /* coefficient of rolling friction */
/*
Force of rolling friction
F_r = R * W
Bicycling magazine, August 1990 has F_r = 0.4 lb = 1.78 Nt,
which gives
R = 1.78 Nt / (80 kg * 9.8 Nt/kg) = 0.0022
From W&W p109:
R = k / wheel_diameter
and suggested value of k is 0.0012.
(k values for steel-on-steel range 0.0002--0.0060)
R = 0.0012 / (27 * 0.0254) = 0.00175 [27 inch wheel]
R = 0.0012 / (26 * 0.0254) = 0.00182 [26 inch wheel]
But W&W go on to discuss R values for various tires,
pressures, etc. On very smooth surfaces:
For narrow tubular tires, values are around 0.004 to 0.0055
For 1.125 inch tires, the value is R = 0.0047
For 26 x 1.375, value is R = 0.0066
Other results for 27 x 1.25 inch tires are 0.0051,
with the lowest experimental value R = 0.004
W&W says there is little dependence of R on increasing
velocity (although there was one experiment that reported
something like R = 0.003 + 0.00017 * V for narrow tubulars on
very smooth surface.) Bicycling magazine August 1990 showed
no velocity dependence for R. I have chosen the default R for
what I guess to be realistic road and tire conditions for my
usual riding.
*/
double G = 0.00; /* grade of the hill */
/*
Force of gravity
F_g = G * W
Grade is here measured as the sine of the hill angle:
grade G = vertical_rise / odometer_distance
Actually the convention I prefer for grade uses the tangent of
the angle: vertical_rise / horizontal_distance But for most
hills of interest to bicyclists, the difference between sine
and tangent is less than 1%. In case it matters:
G = tangent/sqrt(1+tangent^2)
*/
double E = 0.249; /* efficiency of human in cycling */
double T = 0.95; /* transmission efficiency of bicycle drivetrain */
/*
From W&W, p29:
"The peak efficiencies of the two systems [bicyclist and
automobile] (the energy in the power going to the
crankshaft divided by the energy in the food or fuel) are
remarkably close to one another, in the region of 20--30
percent."
From W&W p 37:
Racer Tourist
mph V mph V P C ~Cal/hr
27 12.1 22.5 10.1 373 1680 1440
25 11.2 21 9.4 298 1365 1170
22 9.8 18.5 8.3 224 1050 900
19 8.5 16 7.2 149 735 630
14.5 6.5 12 5.4 82 420 360
10.5 4.7 8.3 3.7 37 263 225
7.2 3.2 6 2.7 19 186 159
3.2 1.4 1.8 0.8 6 133 114
0 0 0 0 0 105 90
mph = velocity [miles/hour], V = velocity [m/s], r = total
mass 77kg, frontal area 0.34m^2, tire pressure 689 kPa
(100psi), Tourist = total mass 85kg, frontal area 0.511m^2,
tire pressure 345 kPa (50psi) This gives a fairly consistent
measure of efficiency = P / (C - BM) where BM = C[V=0], as
efficiency = 0.2365. Interpolating to standard 5 mph
increments gives for the Racer:
mph P C Cal/hr
5 12 157 135
10 34 251 216
15 89 455 391
20 174 840 722
25 298 1365 1174
30 486 2153 1851
These values correspond fairly closely with my program using
these inputs:
bike_power -v5 -n6 -i5 -a 0.172 -wc 175 -wm 25 -t1 -e.2365
Mostly because it seems like an easy thing to do, I've decided
to pretend that this 0.2365 efficiency represents the product
of both human and transmission inefficiency: 0.249 * 0.95.
Transmission efficiency value of 0.95 is suggested by W&W p
157.
These values of efficiency also yield rough equivalence with
an informally given table of calorie consumption vs velocity,
which I found in Bicycling magazine around January 1990:
mph Cal/mi C Cal/hr
10 26 302 260
15 31 541 465
20 38 884 760
25 47 1367 1175
30 59 2059 1770
Unfortunately, this table doesn't make a reasonable fit with a
V^3 power law. One simple way to account for this departure
from V^3 is that people tend to sit up more at low speeds and
crouch down at high speeds, so the higher speeds actually had
lower A2 values.
*/
double H = 0.0; /* velocity of headwind [meters/second] */
double BM_rate = 1.4; /* Basal Metabolism rate [Watts/kg of body weight] */
double F_a; /* force of air resistance [Newtons] */
double F_r; /* force of rolling friction */
double F_g; /* force to overcome gravity on hill */
double F; /* total force resisting forward motion [Newtons] */
double P = 200.0; /* power output [Watts] */
double P_t; /* power loss due to drivetrain inefficiency [Watts] */
/*
From W&W p51:
For elite bicyclists, P > 1200W is sustainable for very
very short periods, drops to about 570W for duration of 60
sec, then curves to about 430W for 300s, on down to 390W
for 3000s, finally dropping off to 240W for 100000s. Eddy
Merckx could sustain about 440W for about 3000s on an
ergometer. (So it seems unlikely that LeMond was actually
putting out 3/4 hp in the 1989 TdF final time trial, as
Frank Berto claims in Bicycling Magazine, June 1990.
Remember, LeMond had aero bars and a tailwind.)
*/
double C; /* power consumption [Watts] */
double B; /* basal metabolism [Watts] */
double V = mOs_per_miOhr * 25.0; /* velocity [meters/second] */
double V_incr = mOs_per_miOhr * 1.0; /* velocity increment in table */
double P_incr = 10.0; /* power increment in table */
double C_incr = Watts_per_CalOhr * 100.0;
/* consumed_power increment in table */
int N_entry = 1;
/*
Process the BIKE_PWR.INI default file
*/
if ((stream=fopen("bike_pwr.ini", "r"))==NULL) /* OK, let's open the file */
return; /* no file, no work to do */
while ((fgets (temp, 255, stream)) != NULL) /* Now we parse the file ... */
{
c = temp; /* Check out the first char */
if ((*c == '%') || (*c == ';')) /* See if it's a comment
* line */
continue;
i = strlen (temp); /* how long this line is */
if (i < 3)
continue; /* If too short, ignore it */
c = &temp[--i]; /* point at last character */
if (*c == '\n') /* if it's a newline, */
*c = '\0'; /* strip it off */
switch (parse( temp, config_lines))
{
case 1: /* Power */
c = skip_blanks (&temp[5]);
sscanf(c, "%lf", &P);
p_given = 1;
calOhr_given = 0;
v_given = 0;
break;
case 2: /* Calories */
c = skip_blanks (&temp[8]);
sscanf(c, "%lf", &C);
calOhr_given = 1;
p_given = 1;
v_given = 0;
C *= Watts_per_CalOhr;
break;
case 3: /* Metric */
metric_flag = 1;
break;
case 4: /* English */
metric_flag = 0;
break;
case 5: /* No_Parms */
display_parameters_flag = 0;
break;
case 6: /* A1 */
c = skip_blanks (&temp[2]);
sscanf(c, "%lf", &A1);
break;
case 7: /* A2 */
c = skip_blanks (&temp[2]);
sscanf(c, "%lf", &A2);
break;
case 8: /* Metabolism */
c = skip_blanks (&temp[10]);
sscanf(c, "%lf", &BM_rate);
break;
case 9: /* Efficiency */
c = skip_blanks (&temp[10]);
sscanf(c, "%lf", &E);
break;
case 10: /* Grade */
c = skip_blanks (&temp[5]);
sscanf(c, "%lf", &G);
break;
case 11: /* Headwind */
c = skip_blanks (&temp[8]);
sscanf(c, "%lf", &H);
if (metric_flag){
H *= mOs_per_kmOhr;
}
else{
H *= mOs_per_miOhr;
}
break;
case 12: /* Increment */
c = skip_blanks (&temp[9]);
sscanf(c, "%lf", &C_incr);
if (p_given)
if (calOhr_given)
C_incr *= Watts_per_CalOhr;
else
P_incr = C_incr;
else
if (metric_flag)
V_incr = mOs_per_kmOhr * C_incr;
else
V_incr = mOs_per_miOhr * C_incr;
break;
case 13: /* Entries */
c = skip_blanks (&temp[7]);
sscanf(c, "%d", &N_entry);
break;
case 14: /* Friction */
c = skip_blanks (&temp[8]);
sscanf(c, "%lf", &R);
break;
case 15: /* Drivetrain */
c = skip_blanks (&temp[10]);
sscanf(c, "%lf", &T);
break;
case 16: /* Velocity */
c = skip_blanks (&temp[8]);
sscanf (c, "%lf", &V);
if (metric_flag){
V = mOs_per_kmOhr * V;
}
else{
V = mOs_per_miOhr * V;
}
break;
case 17: /* Bike_Weight */
c = skip_blanks (&temp[11]);
sscanf (c, "%lf", &Wm);
if (!metric_flag)
Wm *= Nt_per_lb;
break;
case 18: /* Cyclist_Weight */
c = skip_blanks (&temp[14]);
sscanf (c, "%lf", &Wc);
if (!metric_flag)
Wc *= Nt_per_lb;
break;
case 19: /* Cross_Wind */
cross_wind = 1;
break;
case 20: /* Air_Temp */
c = skip_blanks (&temp[8]);
sscanf (c, "%lf", &T_a);
if (!metric_flag)
T_a = (5/9)*(T_a-32);
at_given = 1;
break;
case 21: /* Area */
c = skip_blanks (&temp[4]);
sscanf(c, "%lf", &A_c);
break;
}
}
fclose(stream);
/*
Process command line flags
*/
argp = argv + 1;
while (*argp){
register char c;
c = (*argp)[0];
if (c == '+'){
c = (*argp)[1];
if (c == 'H'){
print_help();
return;
}
else if (c == 'M'){
/* metric = velocity in kph, weight in kg */
metric_flag = 1;
}
else if (c == 'P'){
p_given = 1;
calOhr_given = 0;
v_given = 0;
P = read_double_arg (2);
}
else if (c == 'C'){
calOhr_given = 1;
p_given = 1;
v_given = 0;
C = Watts_per_CalOhr * read_double_arg (2);
}
else if (c == 'D'){
display_parameters_flag = 1;
}
else if (c == 'O'){
explain_table();
return;
}
else{
printf("Unknown flag \"%s\"\n", *argp);
print_help();
return;
}
}
else if (c == '-'){
c = (*argp)[1];
if (c == 'A'){ /* linear coefficient of air resistance */
A1 = read_double_arg (2);
}
else if (c == 'M'){
metric_flag = 0;
}
else if (c == 'D'){
display_parameters_flag = 0;
}
else if (c == 'a'){ /* quadratic coefficient of air resistance */
A2 = read_double_arg (2);
}
else if (c == 'b'){ /* basal metabolism [Watts per kg] */
BM_rate = read_double_arg (2);
}
else if (c == 'e'){
c = (*argp[2]);
if (c == 'c')
E = read_double_arg (2);
if (c == 'd') /* transmission efficiency of drivetrain */
T = read_double_arg (2);
}
else if (c == 'f'){
read_string_arg (2, arg_string);
if (strcmp (arg_string, "1") == 0){
N_entry = 1;
}
else if (strcmp (arg_string, "5") == 0){
if (metric_flag){
V = mOs_per_kmOhr * 5.0;
V_incr = mOs_per_kmOhr * 5.0;
N_entry = 10;
}
else{
V = mOs_per_miOhr * 5.0;
V_incr = mOs_per_miOhr * 5.0;
N_entry = 6;
}
}
else if (strcmp (arg_string, "10") == 0){
if (metric_flag){
V = mOs_per_kmOhr * 10.0;
V_incr = mOs_per_kmOhr * 10.0;
N_entry = 5;
}
else{
V = mOs_per_miOhr * 10.0;
V_incr = mOs_per_miOhr * 0.5;
N_entry = 21;
}
}
else if (strcmp (arg_string, "20") == 0){
if (metric_flag){
V = mOs_per_kmOhr * 20.0;
V_incr = mOs_per_kmOhr * 0.5;
}
else{
V = mOs_per_miOhr * 20.0;
V_incr = mOs_per_miOhr * 0.5;
}
N_entry = 21;
}
else if (strcmp (arg_string, "33") == 0){
if (metric_flag){
V = mOs_per_kmOhr * 33.0;
V_incr = mOs_per_kmOhr * 0.5;
N_entry = 27;
}
else{
V = mOs_per_miOhr * 33.0;
V_incr = mOs_per_miOhr * 1.0;
N_entry = 28;
}
}
else{
printf("Unknown -f table format \"%s\"\n", arg_string);
printf("Valid formats are: 1 5 10 20 33\n");
return;
}
}
else if (c == 'g'){ /* grade of hill */
G = read_double_arg (2);
}
else if (c == 'i'){ /* increment of velocities */
if (p_given){
if (calOhr_given)
C_incr = Watts_per_CalOhr * read_double_arg (2);
else
P_incr = read_double_arg (2);
}
else{
if (metric_flag){
V_incr = mOs_per_kmOhr * read_double_arg (2);
}
else{
V_incr = mOs_per_miOhr * read_double_arg (2);
}
}
}
else if (c == 'n'){ /* number of entries in the table */
N_entry = read_int_arg (2);
}
else if (c == 'r'){ /* coefficient of rolling friction */
R = read_double_arg (2);
}
else if (c == 's'){
read_string_arg (2, arg_string);
if (strcmp (arg_string, "uphill") == 0){
/* uphill seated climbing */
G = 0.06;
A2 = 0.27;
}
else if (strcmp (arg_string, "stand") == 0){
/* standing out of the saddle */
A2 = 0.36;
}
else if (strcmp (arg_string, "downhill") == 0){
/* 150 lb cyclist, 25 lb machine, full downhill tuck */
P = 0;
A2 = 0.145;
}
else if (strcmp (arg_string, "atb") == 0){
/*
mountain bike: high rolling friction,
position sitting with hands up on straight bar
*/
Wm = Nt_per_lb * 28.0;
R = 0.012;
A2 = 0.27;
}
else{
printf("Unknown -s table format \"%s\"\n", arg_string);
printf("Valid formats are: \n");
printf(" uphill = uphill seated, 6\% Grade\n");
printf(" stand = standing\n");
printf(" downhill = downhill, full tuck, P=0\n");
printf(" atb = Mountain bike\n");
return;
}
}
else if (c == 't'){
T_a = read_double_arg (2);
if (!metric_flag)
T_a = (5.0/9.0)*(T_a-32);
at_given = 1;
}
else if (c == 'v'){ /* lowest velocity */
c = (*argp)[2];
if (c == 'm'){ /* volocity of the machain */
v_given = 1;
p_given = 0;
calOhr_given = 0;
if (metric_flag){
V = mOs_per_kmOhr * read_double_arg (3);
}
else{
V = mOs_per_miOhr * read_double_arg (3);
}
}
else if (c == 'w'){ /* volocity of the wind */
c = (*argp) [3];
if (c == 'c') {
cross_wind = 1;
}
else {
if (metric_flag){
H = mOs_per_kmOhr * read_double_arg (3);
}
else{
H = mOs_per_miOhr * read_double_arg (3);
}
}
}
}
else if (c == 'w'){ /* weight */
c = (*argp)[2];
if (c == 'c'){ /* weight of cyclist */
if (metric_flag){
/* input is in kilograms, so convert to Newtons */
Wc = read_double_arg (3) / kg_per_Nt;
}
else{
Wc = Nt_per_lb * read_double_arg (3);
}
}
else if (c == 'm'){ /* weight of machine */
if (metric_flag){
/* kilograms */
/* input is in kilograms, so convert to Newtons */
Wm = read_double_arg (3) / kg_per_Nt;
}
else{
Wm = Nt_per_lb * read_double_arg (3);
}
}
else{
printf("Unknown flag \"%s\"\n", *argp);
print_help();
return;
}
}
else{
printf("Unknown flag \"%s\"\n", *argp);
print_help();
return;
}
}
else {
printf("Unknown argument \"%s\"\n", *argp);
print_help();
return;
}
argp++;
}
/*
Create total Weight
*/
W = Wc + Wm;
/*
Create total coloric rate
*/
B = BM_rate * kg_per_Nt * Wc;
if (calOhr_given){
P = E * (C - B);
P_incr = E * C_incr;
}
/*
Crosswinds are about 70% that of Headwinds
This realy should take into account a true angelular speed.
*/
if (cross_wind)
H *= .7;
/*
Calculate the quadratic coefficient of air resistance (A2)
*/
if(T_a < -30) /* set the limits of the table */
T_a = -30;
if(T_a > 44)
T_a = 44;
if (at_given){
D_a = air_density[(int)T_a+30]; /* calculations for humity and */
/* presure should be made */
A2 = (C_a * D_a / 2) * A_c;
}
/*
Display parameters
*/
if (display_parameters_flag){
if (metric_flag){
printf(
"grade of hill = %5.1f%% headwind = %4.1f kph\n",
100.0 * G, H / mOs_per_kmOhr);
printf("weight: cyclist %5.1f + machine %4.1f = total %5.1f kg\n",
kg_per_Nt * Wc, kg_per_Nt * Wm, kg_per_Nt * W);
}
else{
printf(
"grade of hill = %5.1f%% headwind = %4.1f mph\n",
100.0 * G, H / mOs_per_miOhr);
printf("weight: cyclist %5.1f + machine %4.1f = total %5.1f lb\n",
Wc / Nt_per_lb, Wm / Nt_per_lb, W / Nt_per_lb);
}
printf("rolling friction coeff = %6.4f BM rate = %5.2f W/kg\n",
R, BM_rate);
printf("air resistance coeff = (%6.4f, %g)\n",
A2, A1);
printf("efficiency: transmission = %5.1f%% human = %4.1f%%\n",
100.0 * T, 100.0 * E);
printf("\n");
}
if (metric_flag)
printf(" kph F_kg P_a P_r P_g P_t P hp heat BM C kJ/hr \n");
else
printf(" mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr\n");
/*
Calculate values for output table
*/
for (entry = 0; entry < N_entry; entry++){
if (p_given){
/*
Given P, solve for V by bisection search
True Velocity lies in the interval [V_lo, V_hi].
*/
double P_try;
double V_lo = 0.0;
double V_hi = 128.0;
V = 64.0;
while (V - V_lo > 0.001){
F_a = A2 * (V + H) * (V + H) + A1 * (V + H);
if((V+H) < 0)
F_a *= -1;
P_try = (V / T) * (F_a + (R + G) * W);
if (P_try < P)
V_lo = V;
else
V_hi = V;
V = 0.5 * (V_lo + V_hi);
}
}
/*
Calculate the force (+/-) of the air
*/
F_a = A2 * (V + H) * (V + H) + A1 * (V + H);
if((V+H) < 0)
F_a *= -1;
/*
Calculate the force or rolling restance
*/
F_r = R * W;
/*
Calculate the force (+/-) of the grade
*/
F_g = G * W;
/*
Calculate the total force
*/
F = F_a + F_r + F_g;
/*
Calculate Power in Watts
*/
P = V * F / T;
/*
Calculate Calories and drivetrain loss
*/
if (P > 0){
C = P / E + B;
P_t = (1.0 - T) * P;
}
else{
C = B;
P_t = 0.0;
}
if (metric_flag){
printf("%5.1f %4.1f %4.0f %4.0f %5.0f %4.0f %5.0f %5.2f %5.0f %3.0f %5.0f %5.0f\n",
V / mOs_per_kmOhr,
kg_per_Nt * F,
V * F_a,
V * F_r,
V * F_g,
P_t,
P,
P / Watts_per_horsepower,
C - (B + P),
B,
C,
(3600.0 / 1000.0) * C);
}
else{
printf("%5.1f %4.1f %4.0f %4.0f %5.0f %4.0f %5.0f %5.2f %5.0f %3.0f %5.0f %5.0f\n",
V / mOs_per_miOhr,
F / Nt_per_lb,
V * F_a,
V * F_r,
V * F_g,
P_t,
P,
P / Watts_per_horsepower,
C - (B + P),
B,
C,
C / Watts_per_CalOhr);
}
if (p_given)
P += P_incr;
else
V += V_incr;
}
}
/*
Each of these three functions reads the value of a command line argument.
First it tries reading at character i in the current argument,
which is presumable the first character after the flag itself.
If that is null, it then tries to read the entire next argument.
*/
double read_double_arg(int i)
{
double B;
if (*(*argp + i)) {
if (sscanf (*argp + i, "%lf", &B) != 1){
printf("Argument for \"%s\" must be a number\n", *argp);
print_help();
exit(-1);
}
}
else{
argp++;
if (sscanf (*argp, "%lf", &B) != 1){
printf("Argument for \"%s\" must be a number\n", *(argp - 1));
print_help();
exit(-1);
}
}
return B;
}
int read_int_arg(int i)
{
int J;
if (*(*argp + i)) {
if (sscanf (*argp + i, "%d", &J) != 1){
printf("Argument for \"%s\" must be an integer\n", *argp);
print_help();
exit(-1);
}
}
else{
argp++;
if (sscanf (*argp, "%d", &J) != 1){
printf("Argument for \"%s\" must be an integer\n", *(argp - 1));
print_help();
exit(-1);
}
}
return J;
}
void read_string_arg(int i, char* S)
{
if (*(*argp + i)) {
if (sscanf (*argp + i, "%s", S) != 1){
printf("Argument for \"%s\" must be a string\n", *argp);
print_help();
exit(-1);
}
}
else{
argp++;
if (sscanf (*argp, "%s", S) != 1){
printf("Argument for \"%s\" must be a string\n", *(argp - 1));
print_help();
exit(-1);
}
}
}
void print_help()
{
printf("bike_power [flag]*\n");
printf(" flags:\n");
printf(" +H = display this message\n");
printf(" +O = explanation of output table headings\n");
printf(" +P = power in Watts (program solves for velocity)\n");
printf(" +C = consumption in Calories/hour (program solves for velocity)\n");
printf(" +D = prints display of the parameters.\n");
printf(" +M = metric units (velocity in kph, weight and force in kg)\n");
printf(" -M = English units (velocity in mph, weight and force in lb)\n");
printf(" -D = suppresses display of the parameters.\n");
printf(" -A = linear coefficient of air resistance (A1).\n");
printf(" -a = quadratic coefficient of air resistance (A2).\n");
printf(" -b = basal metabolism rate [Watts per kg]\n");
printf(" -ec = efficieny of the human cycling\n");
printf(" -ed = efficency of the bicycle drivetrain\n");
printf(" -f = table format: 1 5 10 20 33\n");
printf(" -g = grade of hill = vertical_rise / odometer_distance\n");
printf(" -i = increment in output table\n");
printf(" -n = number of entries in output table\n");
printf(" -r = coefficient of rolling friction\n");
printf(" -s = set of pre-specified parameters: u s d atb\n");
printf(" -t = Temp of the air\n");
printf(" -vm = first velocity in output table\n");
printf(" -vw = velocity of the wind (+ for headwind, - for tail).\n");
printf(" -vwc = the wind given is a cross wind.\n");
printf(" -wc = weight of cyclist\n");
printf(" -wm = weight of machine and clothing\n");
}
void explain_table()
{
printf("kph = velocity [kilometers per hour].\n");
printf("mph = velocity [miles per hour].\n");
printf("F_kg = total force resisting forward motion [kilograms].\n");
printf("F_lb = total force resisting forward motion [lb = pounds].\n");
printf("P_a = power output to overcome air resistance [Watts].\n");
printf("P_r = power output to overcome rolling friction [Watts].\n");
printf("P_g = power output to climb grade [Watts].\n");
printf("P_t = power loss due to drivetrain inefficiency [Watts].\n");
printf("P = P_a + P_r + P_g = total power output [Watts].\n");
printf("hp = total power output [horsepower].\n");
printf("heat = C - (P + BM) = power wasted due to human inefficiency [Watts].\n");
printf("BM = basal metabolism [Watts].\n");
printf("C = total power consumption [Watts].\n");
printf("kJ/hr = total power consumption [kilo-Joules per hour].\n");
printf("Cal/hr = total power consumption [dietary Calories per hour].\n");
}
int parse (input, list)
char *input;
struct parse_list list[];
{
int i;
for (i = 0; list[i].p_length; i++)
{
if (strnicmp (input, list[i].p_string, list[i].p_length) == 0)
return (++i);
}
return (-1);
}
char *skip_blanks (string)
char *string;
{
while (*string && isspace (*string))
++string;
return (string);
}
---------- bike_power.c ----- END CUT HERE ----------
---------- bike_power.doc ----- CUT HERE ----------
Subject: bicycle power-output calculator: the program
Here is the description of the "bike_power" program written by
Ken Roberts of the dept of computer science, Columbia University,
New York.
(revised since it was posted on July 18 1990)
================================================================
Description:
This is a computer program called "bike_power", which calculates power
output and power consumption for bicycling. You give it things like riding
speed, body weight, hill grade, and wind speed. The program prints out a
table with power output and power consumption, broken out in various ways.
The program can be used to answer questions like:
How many horsepower was LeMond putting out in the final 1989 TdF time
trial? If he were turning a generator, could he produce enough
electricity to read rec.bicycles on his home computer?
After climbing a 6% hill at 12 mph for half an hour in a 6.5 mph headwind,
how many chocolate ice cream cones am I entitled to eat? [Answer: As
many as you want. Or ... something like 1400 Cal/hr * 0.5 hr = 700
Calories worth.]
If I can go 22 mph on the flat, can I buy a bike with a low gear of 42 x 21
and be able to pedal up a 10% hill? [Answer: No -- unless you think a
cadence of 40 rpm is acceptable.] [Related answer 1: Pros don't need
triple chainrings.] [Related answer 2: 15% hills require an awesome
power output.]
If I can ride at 19 mph, how fast could I go if I were drafting somebody?
with a headwind? or a tailwind?
How fast would I descend a 12% hill? How much faster could I go if I used
an enormous chainring so I wouldn't "spin out"? What if I attached a 50
lb weight to my bike?
Here are some examples of the program in use:
========
Example 1: How much power was LeMond putting out in the final 1989 TdF
time trial, riding at 34 mph with say a 5 mph tailwind:
C> bike_pwr -D -vm34 -wc174 -wm21 -a0.17 -r0.004 -vw-5
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
34.0 7.2 434 53 0 26 513 0.69 1546 111 2169 1865
Answer: 513 Watts, which is over 2/3 horsepower. He was burning about 1865
calories per hour to produce that power. Frank Berto in Bicycling
magazine says it was 3/4 horsepower, but perhaps he understates the
significance of aero bars and tailwind.
What do all the columns in the output table mean?
c> bike_pwr +O
kph = velocity [kilometers per hour].
mph = velocity [miles per hour].
F_kg = total force resisting forward motion [kilograms].
F_lb = total force resisting forward motion [lb = pounds].
P_a = power output to overcome air resistance [Watts].
P_r = power output to overcome rolling friction [Watts].
P_g = power output to climb grade [Watts].
P = P_a + P_r + P_g = total power output [Watts].
hp = total power output [horsepower].
heat = C - (P + BM) = power wasted due to human inefficiency [Watts].
BM = basal metabolism [Watts].
C = total power consumption [Watts].
kJ/hr = total power consumption [kilo-Joules per hour].
Cal/hr = total power consumption [dietary Calories per hour].
========
What do all those command line flags mean?
C> bike_pwr +H
bike_power [flag]*
flags:
+H = display this message
+O = explanation of output table headings
+P = power in Watts (program solves for velocity)
+C = consumption in Calories/hour (program solves for velocity)
+D = prints display of the parameters.
+M = metric units (velocity in kph, weight and force in kg)
-M = English units (velocity in mph, weight and force in lb)
-D = suppresses display of the parameters.
-A = linear coefficient of air resistance (A1).
-a = quadratic coefficient of air resistance (A2).
-b = basal metabolism rate [Watts per kg]
-e = human cycling efficiency
-f = table format: 1 5 10 20 33
-g = grade of hill = vertical_rise / odometer_distance
-i = increment in output table
-n = number of entries in output table
-r = coefficient of rolling friction
-s = set of pre-specified parameters: u s d atb
-t = transmission efficiency of bicycle drivetrain
-vm = first velocity in output table
-vw = velocity of the wind (+ for headwind, - for tail)
-vwc = the wind given is a cross wind.
-wc = weight of cyclist
-wm = weight of and clothing
========
Example 2: Suppose I'm going to climb a 6% hill into a 10 mph headwind. How
fast do I have to go to burn Calories at a rate of 700, 800, or 900
per hour?
C> bike_pwr -D +C700 -i100 -n3 -g.06 -vw10 -a.27
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
5.9 14.6 36 12 122 9 179 0.24 540 95 814 700
6.7 14.9 45 14 139 10 208 0.28 627 95 931 800
7.4 15.2 54 16 155 12 237 0.32 715 95 1047 900
========
Example 3: I'm going 22.3 mph on a flat smooth road, about as fast as I
can sustain:
C> bike_pwr -vm22.3 -r.004 -a.172
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
22.3 4.5 170 31 0 11 212 0.28 640 95 947 814
In my mirror I see a paceline coming up at 25 mph, so I drop in behind and
find that with the same 212 Watts power output, I can keep up with the
paceline, because of the draft (A2 = 0.12 at 25 mph):
C> bike_pwr +P212 -r.004 -a.12
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
25.0 4.1 167 35 0 11 212 0.28 639 95 947 814
But then we hit this 10% hill, and I have to stand out of the saddle, and
my speed quickly drops, and the paceline leaves me behind.
C> bike_pwr +P212 -r.004 -a.36 -g.10
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
5.4 18.7 5 8 189 11 212 0.28 640 95 947 814
With the 53-42T x 12-21T drivetrain on my bike, my lowest gear is
(42/21)*27 = 54 inch. So my cadence is now 5.4/(0.003*54) = 33 rpm. And at
the top of the hill I notice this pain in my left knee.
Exercise 3a: If Pedro Delgado can produce a steady output of 375 Watts on
a TdF road stage, and a can deliver 450 Watts for short very steep
sections, what gear-inch will he need to maintain a cadence of 50
rpm on the steepest hill in the 1990 TdF? (The climb to Alpe d'Huez
has an average grade of 8.1%, maximum grade of 14%. Assume that he
climbs seated with air resistance coefficient A2 = 0.27).
Exercise 3b: On the 8.1% grade, suppose he gets help by drafting a
teammate, which reduces his air resistance coefficient by 7% down
to A2 = 0.25. How much faster can he then go with his 375 Watts?
========
Example 4: My usual time trial circuit has a 2% uphill grade on the 20 km
going out, and then I turn around and enjoy the 2% downhill all the
way back. I put out a constant 300 Watts and get a time of
1:01:43. (This is not the best way to ride this course.) What would
be the slope of a constant-grade pure uphill course that would
"equivalent" to my circuit? (i.e. require the same average power
output to achieve the same time)
40 km / (1 + (1 + 43/60)/60) = 38.9 kph
A little trial-and-error with the -g flag gives:
C> bike_pwr +P300 -r.004 -g.004 +M
kph F_kg P_a P_r P_g P_t P hp heat BM C kJ/hr
38.9 2.7 218 34 34 15 300 0.40 905 95 1300 4680
So 2% up and 2% down is "equivalent" to at most 0.4% pure uphill grade.
("at most", because better strategy would have given a better time for the
up-and-down circuit).
Exercise 4a (not easy): What are the speeds going out and coming back on
the up-and-down circuit that give the best time for an overall
average output of 300 Watts? What is the equivalent pure uphill
grade?
Exercise 4b (significantly harder): What are the three speeds for a
circuit that is 10 km uphill 2%, 20 km flat, 10 km downhill 2% that
give the best time for an overall average output of 300 Watts?
========
Example 5: How fast can a 150 lb rider on a 25 lb bicycle coast down a 12%
hill?
Here the grade is -0.12. We will assume that the rider goes into a tuck
which reduces the air resistance coefficient to 0.145.
C> bike_pwr +P0 -wc 150 -wm 25 -a 0.145 -g -0.12
grade of hill = -12.0% weight = 175.0 lb
air resistance coeff = (0.1450, 0)
mph F_lb P_a P_r P_g P hp heat BM C Cal/hr
55.3 0.0 2195 116 -2311 0 0.00 0 95 96 82
Answer: Just over 55 mph. That's where the air resistance P_a and rolling
friction P_r finally overcome gravity P_g.
What if this rider had an enormous gear, and could apply additional power
at those speeds?
C> bike_pwr +P0 -n7 -i100 -wc 150 -wm 25 -a 0.145 -g -0.12
grade of hill = -12.0% weight = 175.0 lb
air resistance coeff = (0.1450, 0)
mph F_lb P_a P_r P_g P hp heat BM C Cal/hr
55.3 0.0 2195 116 -2311 0 0.00 0 95 96 82
56.6 0.9 2344 118 -2362 100 0.13 323 95 518 446
57.7 1.7 2490 120 -2410 200 0.27 646 95 942 810
58.8 2.6 2632 123 -2455 300 0.40 969 95 1364 1173
59.8 3.4 2773 125 -2498 400 0.54 1292 95 1787 1537
60.8 4.1 2912 127 -2539 500 0.67 1615 95 2210 1900
61.7 4.9 3049 129 -2578 600 0.80 1937 95 2632 2263
So even applying 400 Watts, the speed is only increased by 4.5 mph. Adding
a 50 lb weight, with no pedaling, raises the speed to 62.7 mph.
================================
The program implements a simple model of human bicycling performance:
Force F = A2 * (v + h)^2 + A1 * (v + h) + (r + g) * (wc + wm)
Power_output P = (v * F) / t
Consumed_power C = (P / e) + (b * wc)
where the symbols are described by the command line flags listed above.
Comments in the source program include extended discussion of the
derivation of parameter values from published sources. Suggestions for
modifications of the model or its parameters are most welcome.
================================================================
Revisions as of July 20, 1990: by
Ken Roberts roberts@cs.columbia.edu
Columbia U. 212-854-8123, -8699 Home 201-862-0995
Since the posted description of July 18, three features have been
added:
-t lets you specify the transmission efficiency of the bicycle
drivetrain. The power loss due to drivetrain inefficiency is shown
in the output table column labelled P_t.
+P lets you give the power output in Watts, and have the program solve
for velocity, instead of the other way around.
+C lets you specify the power consumption on Calories/hour, and let
the program find the appropriate velocity. The -n and -i flags can
be used in the obvious way to create tables with multiple power
output or calorie consumption values (see revised examples below).
-s lets you select a set of pre-specified parameter values. For
example,
-ss gives values for a 175 lb rider with a 23 lb machine, position
standing out of the saddle.
-sd gives values for a 150 lb rider with a 25 lb machine, position full
downhill tuck.
By modifying the source code, you can make up your own sets.
There are also some new and modified examples in the description.
Also, the processing of +P and +C has been modified to handle speeds up to
286 mph (460 kph).
================================================================
Revisions as of April 14, 1993: by
Mark Grennan markg@okcforum.uoknorm.edu
Okla. State Finance 405-521-2780 Home 405-728-9836
CIS 76545,2506
This revision adds the "bike_pwr.ini" file to set defaults for the program.
I also have change a couple of command line options to make room for more
inprovements.
The -v options is now -vm, and the -h options is not -vw. This groups the
major volicty controls together.
-vm = first velocity in output table of the machine
-vw = velocity of the wind (+ for headwind, - for tail)
I also included a new -vwc command line option to cacluate wind drag for
cross wind problems.
I also found one bug. If you produce a table where a tail wind (-vw -20)
is grater then the cyclist's speed (-vm 10), the graph show a positive
P_a and calculated it as forware restance, not force.
Acording to Power bike it takes about 1.1 lbs of force to over come the
basic internal friction of a bicycle. (your number may very)
C> bike_pwr +P0
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
0.0 1.1 0 0 0 0 0 0.00 0 111 111 96
So, how much of a tail wind does it take to over come this resitance?
Answer: about 10mph.
C> bike_pwr +P0 -vw-10
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
0.0 0.0 -0 0 0 0 0 0.00 0 111 111 96
And with a 20mph tail wind we sould role how fast?
Answer: about 9.8?
C> bike_pwr +P0 -vw-20
mph F_lb P_a P_r P_g P_t P hp heat BM C Cal/hr
9.8 0.0 -21 21 0 0 0 0.00 0 111 111 96
I'm not sure this number is right? so more calculations sould be made.
However Power Bike does indecate it is is taking 21 Watts to overcome
rolling restience and we are receiving 21 Watts from the wind.
================================================================
---------- bike_power.doc ----- END CUT HERE ----------
---------- bike_power.ini ----- CUT HERE ----------
;
; Bike Power Defaults
;
;
; metric units (velocity in kph, weight and force in kg, temp in c)
;
; Metric
;
; English units (velocity in mph, weight and force in lb, temp in f)
;
English
;
; weight of cyclist
;
Cyclist_Weight 175
;
; weight of machine and clothing
;
Bike_Weight 23
;
; grade of hill = vertical_rise / odometer_distance
;
; use negitive numbers for downhill grades
;
;Grade 0
;
; headwind velocity
;
;Headwind 0
;
; Headwind volocity to be calculated as a cross wind
;
;Cross_Wind
;
; Air Tempture
;
; If this value is given the A2 entry in this file
; is ignored.
;
;Air_temp 68
;
; Frountal area of the cyclist in meters^2
;
; These figures where calculated by dividing the .542115 by
; the figures for A2 below. .542115 is (.9 * 1.2047 / 2) or
; C_a * air_density * frontal_area as described in the
; source.
;
; standing 0.6566873
; upright (hands on bar tops) 0.4925155
; crouch (hands on drops, elbows locked) 0.4297982
; racing crouch (hands on crops, elbows bent) 0.3080527
; full downhill tuck 0.2674709
; end of pack of 1 or more riders 0.2213353
; in the middle of a pack 0.1844627
;
;Area 0.3080527
;
; coefficient of rolling friction
;
; narrow tubular tires range from 0.004 to 0.0055
;
; 26 x 1.125 inch tires 0.0047
; 27 x 1.25 inch tires 0.0051
; 26 x 1.375 0.0066
; for mountain bike tires 0.0120
;
; for more exacting figures see page 109 of Bicycle Science
;
Friction 0.0047
;***************************************************************
;
; Fixed data
;
; All other part of the table will be solved for
;
;***************************************************************
;
; first velocity in output table
;
Velocity 17
;
; power in Watts (program solves for velocity)
; If this input is set Bike Power will solve for speed
;
; Power .45
;
; consumption in Calories/hour (program solves for velocity)
;
; Calories 700
;***************************************************************
;
; Output Tabel parameters
;
;***************************************************************
;
; suppresses display of the parameters.
;
No_Parms
;
; number of Entries in output table
;
Entries 1
;
; Increment the Fixed data by this amount
;
Increment 1.0
;***************************************************************
;
; Standards for calculations
;
;***************************************************************
; linear coefficient of air resistance.
; A1 0.0
;
; quadratic coefficient of air resistance.
;
; Figures from Cycling Mag.
;
; standing 0.356
; upright (hands on bar tops) 0.267
; crouch (hands on drops, elbows locked) 0.233
; racing crouch (hands on crops, elbows bent) 0.167
; full downhill tuck 0.145
; end of pack of 1 or more riders 0.12
; in the middle of a pack 0.10
;
A2 0.167
;
; basal metabolism rate [Watts per kg of body weight]
;
; This shouldn't change much from person to person
; I'm not sure how this is measured. This number is
; quoted right out of the source code.
;
Metabolism 1.4
;
; human cycling efficiency
;
; Figure quoted from page 29 of Bicycling Science
;
Efficiency 0.249
;
; transmission efficiency of bicycle drivetrain
;
; Figure quoted from page 29 of Bicycling Science
;
Drivetrain 0.95
---------- bike_power.ini ----- END CUT HERE ----------