File Coverage

blib/lib/BikePower.pm
Criterion Covered Total %
statement 175 345 50.7
branch 55 144 38.1
condition 15 35 42.8
subroutine 39 68 57.3
pod 24 58 41.3
total 308 650 47.3


line stmt bran cond sub pod time code
1             #!/usr/local/bin/perl
2             # -*- perl -*-
3              
4             #
5             # $Id: BikePower.pm,v 2.5.1.13 1999/04/07 19:43:47 eserte Exp $
6             # Author: Slaven Rezic
7             #
8             # Copyright: see at bottom of file
9             #
10             # Mail: eserte@cs.tu-berlin.de
11             # WWW: http://user.cs.tu-berlin.de/~eserte/
12             #
13              
14 1     1   809 use strict;
  1         2  
  1         112  
15              
16             package BikePower;
17              
18 1         4468 use vars qw($m_s__per__mi_h $m_s__per__km_h $Nt__per__lb $kg__per__Nt
19             $Watts__per__Cal_hr $Watts__per__horsepower
20             $NOSAVE
21             @out %fmt @air_density %members
22             %air_resistance @air_resistance_order
23             @rolling_friction
24             @ISA $VERSION $has_xs
25 1     1   5 );
  1         1  
26              
27             require DynaLoader;
28             @ISA = qw(DynaLoader);
29             $VERSION = '0.33';
30              
31             eval {
32             bootstrap BikePower $VERSION;
33             $has_xs = 1 unless $@;
34             };
35              
36             if ($has_xs) {
37             *calc = \&calcXS;
38             } else {
39             *calc = \&calc_slow;
40             }
41              
42             # Conversion factors
43             $m_s__per__mi_h = 0.44704; # meters/second per miles/hour
44             $m_s__per__km_h = (1000.0 / 3600.0); # m/s per km/h
45             $Nt__per__lb = 4.4482;
46             $kg__per__Nt = 0.102;
47             $Watts__per__Cal_hr = 1.163; # Watts per dietary Calories/hour
48             # 1 dietary Calorie == 1000 calories
49             $Watts__per__horsepower = 745.700;
50              
51             $NOSAVE = 1 << 0;
52              
53             # Air Density table for dry air between -30 to +44 degrees C
54             #
55             # Taken from the Handbook of Chemistry and Physics, Thirtieth
56             # Edition
57             #
58             # This table does not include the changes for air pressure or
59             # humity.
60             @air_density =
61             (1.5147, 1.5083, 1.5019, 1.4955, 1.4892, # -30°C 3.6°F
62             1.4829, 1.4767, 1.4706, 1.4645, 1.4584, # -25
63             1.3951, 1.3896, 1.3841, 1.3787, 1.3734, # -20
64             1.3680, 1.3628, 1.3575, 1.3523, 1.3472, # -15
65             1.3420, 1.3370, 1.3319, 1.3269, 1.3219, # -10
66             1.3170, 1.3121, 1.3072, 1.3024, 1.2977, # - 5
67             1.2929, 1.2882, 1.2835, 1.2789, 1.2742, # 0
68             1.2697, 1.2651, 1.2606, 1.2561, 1.2517, # 5
69             1.2472, 1.2428, 1.2385, 1.2342, 1.2299, # 10
70             1.2256, 1.2214, 1.2171, 1.2130, 1.2088, # 15
71             1.2047, 1.2006, 1.1965, 1.1925, 1.1885, # 20
72             1.1845, 1.1805, 1.1766, 1.1727, 1.1688, # 25
73             1.1649, 1.1611, 1.1573, 1.1535, 1.1498, # 30
74             1.1460, 1.1423, 1.1387, 1.1350, 1.1314, # 35
75             1.1277, 1.1242, 1.1206, 1.1170, 1.1135 # 40°C 138.6°F
76             );
77              
78             # members
79             # maybe accessed by hash or by method
80             %members =
81             ('imperial' => [[], 0, 'metric/imperial flag', undef],
82             'T_a' => [['temperature'], 20, 'temperature [°C]', undef],
83             'given' => [[], 'v', 'resolve for v/P/C', undef],
84             'first_C' => [[], 500, 'consumption [cal/h]', undef],
85             'first_V' => [[], 30, 'velocity [km/h]', undef],
86             'first_P' => [[], 200, 'power output [Watts]', undef],
87             'V_incr' => [[], 2, 'velocity increment in table', undef],
88             'P_incr' => [[], 25, 'power increment in table', undef],
89             'C_incr' => [[], 100.0,
90             'consumed_power increment in table', undef],
91             'N_entry' => [[], 10, 'number of entries in table', undef],
92             'C_a' => [[], 0.90, 'air resistance coefficient', undef],
93             'A1' => [[], 0, 'linear coefficient of air resistance', undef],
94             'A2' => [[], undef,
95             'quadratic coefficient of air resistance', $NOSAVE],
96             'A_c' => [[], 0.3080527, 'frontal area of the cyclist in meters^2',
97             undef],
98             'T' => [['transmission_efficiency'], 0.95,
99             'transmission efficiency of bicycle drivetrain', undef],
100             'E' => [['human_efficiency'], 0.249,
101             'efficiency of human in cycling', undef],
102             'H' => [['headwind'], 0.0,
103             'velocity of headwind [meters/second]', undef],
104             'R' => [['rolling_friction'], 0.0047,
105             'coefficient of rolling friction', undef],
106             'G' => [['grade'], 0, 'grade of hill', undef],
107             'Wc' => [['weight_cyclist'], 77, 'weight of cyclist [kg]', undef],
108             'Wm' => [['weight_machine'], 10,
109             'weight of machine and clothing [kg]', undef],
110             'BM_rate' => [[], 1.4,
111             'basal metabolism rate [Watts/kg of body weight]', undef],
112             'cross_wind' => [[], 0, 'the wind given is a cross wind', undef],
113              
114             'P' => [['power'], undef, 'power in Watts', $NOSAVE],
115             'V' => [['velocity'], undef, 'velocity in m/s', $NOSAVE],
116             'C' => [['consumption'], undef, 'consumption in Cal/hr', $NOSAVE],
117             );
118              
119             %air_resistance =
120             (
121             'standing', => {'A_c' => 0.6566873,
122             'text_en' => 'standing',
123             'text_de' => 'stehend',
124             },
125             'upright' => {'A_c' => 0.4925155,
126             'text_en' => 'upright',
127             'text_de' => 'aufrecht',
128             },
129             'crouch' => {'A_c' => 0.4297982,
130             'text_en' => 'crouch',
131             'text_de' => 'geduckt',
132             },
133             'racing' => {'A_c' => 0.3080527,
134             'text_en' => 'racing crouch',
135             'text_de' => 'geduckt in Rennhaltung',
136             },
137             'tuck' => {'A_c' => 0.2674709,
138             'text_en' => 'full downhill tuck',
139             'text_de' => 'Abfahrtshaltung',
140             },
141             'pack_end' => {'A_c' => 0.2213353,
142             'text_en' => 'end of pack of 1 or more riders',
143             'text_de' => 'am Ende eines Verbandes',
144             },
145             'pack_middle' => {'A_c' => 0.1844627,
146             'text_en' => 'in the middle of a pack',
147             'text_de' => 'in der Mitte eines Verbandes',
148             },
149             );
150             @air_resistance_order = sort { $air_resistance{$b}->{A_c} <=>
151             $air_resistance{$a}->{A_c}
152             } keys %air_resistance;
153              
154             @rolling_friction =
155             ({'R' => 0.004,
156             'text_en' => 'narrow tubular tires, lowest',
157             'text_de' => 'schmale röhrenförmige Reifen, niedrigster Wert',
158             },
159             {'R' => 0.0047,
160             'text_en' => '26 x 1.125 inch tires',
161             'text_de' => '26 x 1.125"-Reifen',
162             },
163             {'R' => 0.0051,
164             'text_en' => '27 x 1.25 inch tires',
165             'text_de' => '27 x 1.25"-Reifen',
166             },
167             {'R' => 0.0055,
168             'text_en' => 'narrow tubular tires, highest',
169             'text_de' => 'schmale röhrenförmige Reifen, höchster Wert',
170             },
171             {'R' => 0.0066,
172             'text_en' => '26 x 1.375 inch tires',
173             'text_de' => '26 x 1.375"-Reifen',
174             },
175             {'R' => 0.0120,
176             'text_en' => 'mountain bike tires',
177             'text_de' => 'Mountainbike-Reifen',
178             },
179             );
180              
181             my $member;
182             my $i=0;
183             foreach $member (keys %members) {
184             foreach ($member, @{$members{$member}->[0]}) {
185             my $sub = q#sub # . $_ . q# {
186             my($self, $val) = @_;
187             if (defined $val) {
188             $self->{'# . $member . q#'} = $val;
189             } else {
190             $self->{'# . $member . q#'};
191             }
192             }#;
193 22 50   22 1 35 eval $sub;
  22 50   6 1 201  
  0 100   13 1 0  
  22 50   10 1 116  
  6 0   0 0 10  
  6 50   6 1 10  
  0 0   0 1 0  
  6 0   0 1 18  
  13 0   0 1 18  
  13 0   0 1 22  
  1 0   0 1 6  
  12 0   0 0 139  
  10 0   0 1 15  
  10 50   4 1 17  
  0 50   1 1 0  
  10 0   0 1 216  
  0 0   0 0 0  
  0 0   0 1 0  
  0 0   0 1 0  
  0 0   0 1 0  
  6 100   12 0 8  
  6 50   6 1 9  
  0 0   0 1 0  
  6 0   0 1 22  
  0 0   0 1 0  
  0 100   17 1 0  
  0 50   22 0 0  
  0 50   6 0 0  
  0 50   6 0 0  
  0 50   6 1 0  
  0 100   43 0 0  
  0 100   3 0 0  
  0 50   6 0 0  
  0 100   25 0 0  
  0 100   33 0 0  
  0 100   35 0 0  
  0 100   30 0 0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  4         6  
  4         8  
  0         0  
  4         23  
  1         62  
  1         7  
  0         0  
  1         14  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  12         21  
  12         21  
  6         108  
  6         20  
  6         10  
  6         11  
  0         0  
  6         92  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  17         237  
  17         26  
  6         12  
  11         136  
  22         32  
  22         36  
  0         0  
  22         150  
  6         94  
  6         11  
  0         0  
  6         130  
  6         10  
  6         13  
  0         0  
  6         104  
  6         8  
  6         11  
  0         0  
  6         28  
  43         170  
  43         90  
  10         39  
  33         388  
  3         8  
  3         5  
  1         9  
  2         7  
  6         9  
  6         12  
  0         0  
  6         140  
  25         38  
  25         226  
  1         7  
  24         548  
  33         256  
  33         54  
  7         78  
  26         209  
  35         50  
  35         56  
  1         8  
  34         301  
  30         182  
  30         50  
  1         7  
  29         358  
194             }
195             }
196              
197             # output variables
198             @out = qw(V F Pa Pr Pg Pt P hp heat B C kJh);
199             # format for printf
200             %fmt = qw(V %5.1f
201             F %4.1f
202             Pa %4.0f
203             Pr %4.0f
204             Pg %5.0f
205             Pt %4.0f
206             P %5.0f
207             hp %5.2f
208             heat %5.0f
209             B %3.0f
210             C %5.0f
211             kJh %5.0f);
212              
213             ## XXX vielleicht sollten die Werte im Hash die echten SI-Werte
214             ## sein. FETCH und STORE machen dann anhand von metric die
215             ## Umwandlung. Funktioniert es mit -variable und Tk?
216             sub TIEHASH {
217 4     4   30 my($class, %a) = @_;
218 4 50       13 $class = (ref $class ? ref $class : $class);
219              
220 4         9 my $s = {};
221 4         8 bless $s, $class;
222              
223 4 50 33     17 if ($a{'-no-ini'} || !$s->load_defaults) {
224 4 100       12 if (!$a{'-no-default'}) {
225 1         5 $s->default;
226             }
227             }
228 4         16 $s->set_values(%a);
229 4 50 66     87 if (!$s->given && !$a{'-no-default'}) { $s->given('v') }
  0         0  
230              
231 4         13 $s;
232             }
233              
234 4     4 0 67 sub new { shift->TIEHASH(@_) }
235              
236             sub _nosave {
237 78     78   73 my($k) = @_;
238 78 50       118 return 1 if !exists $members{$k};
239 78         79 my $v = $members{$k};
240 78 100       448 return 0 if !defined $v->[3];
241 12         48 return $v->[3] & $NOSAVE;
242             }
243              
244             sub clone {
245 2     2 0 53 my($class, $old);
246 2 100 66     14 if (ref $_[0] and $_[0]->isa('BikePower')) {
247             # Syntax: $clone = $object->clone(%args);
248 1         3 $old = shift;
249 1         3 $class = ref $old;
250             } else {
251             # Syntax: $clone = clone BikePower $object, %args;
252 1         2 $class = shift;
253 1         1 $old = shift;
254             }
255 2         3 my(%args) = @_;
256 2         6 $args{'-no-ini'} = $args{'-no-default'} = 1;
257 2         6 my $new = $class->new(%args);
258 2         3 my($k, $v);
259 2         6 while(($k, $v) = each %members) {
260 52 50 66     79 next if _nosave($k) || !defined $old->{$k} || $old->{$k} eq '';
      66        
261 44         145 $new->{$k} = $old->{$k};
262             }
263 2         6 $new;
264             }
265              
266             sub default {
267 1     1 0 2 my($self) = @_;
268 1         2 my($k, $v);
269 1         6 while(($k, $v) = each %members) {
270 26 100       35 next if _nosave($k);
271 22         62 $self->{$k} = $v->[1];
272             }
273 1         3 $self;
274             }
275              
276             sub set_values {
277 4     4 0 15 my($self, %a) = @_;
278 4         23 my($k, $v);
279 4         13 while(($k, $v) = each %a) {
280 28 50 66     196 if ($k !~ /^[_\-]/ && defined $v && $v ne '') {
      66        
281 21         70 $self->{$k} = $v;
282             }
283             }
284             }
285              
286             sub _default_filename {
287 0     0   0 my $home;
288 0 0       0 if ($^O eq 'MSWin32') {
289 0         0 eval {
290 0         0 require Win32Util; # XXX private module
291 0         0 $home = Win32Util::get_user_folder();
292 0 0       0 if (defined $home) {
293 0         0 $home .= "/bikepwr.rc";
294             }
295             };
296             }
297 0 0       0 if (!defined $home) {
298 0   0     0 $home = eval { local $SIG{__DIE__};
299             (getpwuid($<))[7];
300             } || $ENV{'HOME'} || '';
301 0 0       0 $home .= ($^O eq 'MSWin32' ? "/bikepwr.rc" : "/.bikepowerrc");
302             }
303 0         0 $home;
304             }
305              
306             sub load_defaults {
307 0     0 0 0 my($self, $file) = @_;
308 0 0       0 $file = _default_filename unless $file;
309 0         0 my $x;
310 0 0       0 if (! -r $file) {
311 0         0 return undef;
312             }
313 0         0 eval 'do "$file"';
314 0 0       0 if ($@) {
315 0         0 warn $@;
316 0         0 return undef;
317             }
318 0         0 my($k, $v);
319 0         0 while(($k, $v) = each %$x) {
320 0         0 $self->{$k} = $v;
321             }
322 0         0 1;
323             }
324              
325             sub save_defaults {
326 0     0 0 0 my($self, $file) = @_;
327 0 0       0 $file = _default_filename unless $file;
328 0         0 my $x;
329 0         0 my($k, $v);
330 0         0 while(($k, $v) = each %$self) {
331 0 0 0     0 if ($k !~ /^[_\-]/ && !_nosave($k) && $v ne '' ) {
      0        
332 0         0 $x->{$k} = $v;
333             }
334             }
335 0 0       0 if (!open(FILE, ">$file")) {
336 0         0 warn "Can't open file: $!";
337 0         0 return undef;
338             }
339 0         0 eval { require Data::Dumper };
  0         0  
340 0 0       0 if (!$@) {
341 0         0 print FILE Data::Dumper->Dump([$x], ['x']), "\n";
342             } else {
343 0         0 print FILE "\$x = {\n";
344 0         0 while(($k, $v) = each %$x) {
345 0         0 print FILE $k, "=> '", $v, "',\n";
346             }
347 0         0 print FILE "}\n";
348             }
349 0         0 close FILE;
350 0         0 1;
351             }
352              
353             sub FETCH {
354 0     0   0 my($self, $key) = @_;
355 0         0 $self->{$key};
356             }
357              
358             sub STORE {
359 0     0   0 my($self, $key, $value) = @_;
360 0         0 $self->{$key} = $value;
361             }
362              
363             sub _numify {
364 10     10   12 my($s) = @_;
365 10 50       28 if ($s =~ /^\s*(\S+)/) {
366 10         113 $1;
367             } else {
368 0         0 $s;
369             }
370             }
371              
372 24     24 0 2508 sub weight_cyclist_N { $_[0]->weight_cyclist / $kg__per__Nt }
373 24     24 0 1039 sub weight_machine_N { $_[0]->weight_machine / $kg__per__Nt }
374 0     0 0 0 sub total_weight { $_[0]->weight_cyclist + $_[0]->weight_machine }
375 24     24 0 53 sub total_weight_N { $_[0]->weight_cyclist_N + $_[0]->weight_machine_N }
376 6     6 0 154 sub velocity_kmh { $_[0]->velocity / $m_s__per__km_h }
377 0     0 0 0 sub V_incr_ms { $_[0]->V_incr * $m_s__per__km_h }
378 6     6 0 107 sub air_density { $air_density[int($_[0]->temperature + 30)] }
379             sub calc_A2 {
380 6     6 0 7 my $self = shift;
381 6 50       117 if (defined $self->A2) {
382 0         0 $self->A2;
383             } else {
384 6         113 ($self->C_a * $self->air_density / 2) * _numify($self->A_c);
385             }
386             }
387 10     10 0 216 sub BM { $_[0]->BM_rate * $_[0]->weight_cyclist }
388 0     0 0 0 sub C_incr_W_cal_hr { $_[0]->C_incr * $Watts__per__Cal_hr }
389              
390 18     18 0 1468 sub sqr { $_[0] * $_[0] }
391              
392             sub calc_slow {
393 2     2 0 10 my $self = shift;
394             # effective Headwind
395 2 50       34 my $eff_H = $self->headwind * ($self->cross_wind ? .7 : 1);
396 2         36 my $A_c = _numify($self->A_c);
397 2         38 my $R = _numify($self->rolling_friction);
398 2         5 my $A2 = $self->calc_A2;
399 2         5 my($F_a);
400              
401 2 100 66     49 if ($self->given eq 'P' || $self->given eq 'C') {
402             # Given P, solve for V by bisection search
403             # True Velocity lies in the interval [V_lo, V_hi].
404 1         2 my $P_try;
405 1         1 my $V_lo = 0;
406 1         1 my $V = 64;
407 1         2 my $V_hi = 128;
408 1         3 while ($V - $V_lo > 0.001) {
409 16         33 $F_a = $A2 * sqr($V + $eff_H) + $self->A1 * ($V + $eff_H);
410 16 50       40 if ($V + $eff_H < 0) {
411 0         0 $F_a *= -1;
412             }
413 16         1279 $P_try = ($V / $self->transmission_efficiency)
414             * ($F_a + ($R + $self->grade) * $self->total_weight_N);
415 16 100       753 if ($P_try < $self->power) {
416 4         8 $V_lo = $V;
417             } else {
418 12         17 $V_hi = $V;
419             }
420 16         206 $V = 0.5 * ($V_lo + $V_hi);
421             }
422 1         23 $self->velocity($V);
423             }
424            
425             # Calculate the force (+/-) of the air
426 2         42 $F_a = $A2 * sqr($self->velocity + $eff_H)
427             + $self->A1 * ($self->velocity + $eff_H);
428 2 50       41 if ($self->velocity + $eff_H < 0) {
429 0         0 $F_a *= -1;
430             }
431              
432             # Calculate the force or rolling restance
433 2         5 my $F_r = $R * $self->total_weight_N;
434              
435             # Calculate the force (+/-) of the grade
436 2         42 my $F_g = $self->grade * $self->total_weight_N;
437              
438             # Calculate the total force
439 2         6 my $F = $F_a + $F_r + $F_g;
440              
441             # Calculate Power in Watts
442 2         45 $self->power($self->velocity * $F / $self->transmission_efficiency);
443              
444 2         3 my $P_t;
445             # Calculate Calories and drivetrain loss
446 2 50       39 if ($self->power > 0) {
447 2         42 $self->consumption($self->power / $self->human_efficiency + $self->BM);
448 2         47 $P_t = (1.0 - $self->transmission_efficiency) * $self->power;
449             } else {
450 0         0 $self->consumption($self->BM);
451 0         0 $P_t = 0.0;
452             }
453              
454 2         45 $self->{_out}{'Pa'} = $self->velocity * $F_a;
455 2         53 $self->{_out}{'Pr'} = $self->velocity * $F_r;
456 2         40 $self->{_out}{'Pg'} = $self->velocity * $F_g;
457 2         4 $self->{_out}{'Pt'} = $P_t;
458 2         42 $self->{_out}{'P'} = $self->power;
459 2         41 $self->{_out}{'hp'} = $self->power / $Watts__per__horsepower;
460 2         40 $self->{_out}{'heat'} = $self->consumption - ($self->BM + $self->power);
461 2         41 $self->{_out}{'C'} = $self->consumption;
462 2         5 $self->{_out}{'B'} = $self->BM;
463 2 50       42 if (!$self->imperial) {
464 2         5 $self->{_out}{'V'} = $self->velocity_kmh;
465 2         5 $self->{_out}{'F'} = $kg__per__Nt * $F;
466             # $self->{_out}{'kJh'} = (3600.0 / 1000.0) * $self->consumption;
467 2         40 $self->{_out}{'kJh'} = $self->consumption / $Watts__per__Cal_hr; # really Cal/hr
468             } else {
469 0           $self->{_out}{'V'} = $self->velocity / $m_s__per__mi_h;
470 0           $self->{_out}{'F'} = $F / $Nt__per__lb;
471 0           $self->{_out}{'kJh'} = $self->consumption / $Watts__per__Cal_hr; # really Cal/hr
472             }
473             }
474              
475             sub display_parameters {
476 0     0 0   my($self) = @_;
477 0 0         if (!$self->imperial) {
478 0           printf
479             "grade of hill = %5.1f%% headwind = %4.1f km/h\n",
480             100.0 * $self->grade, $self->headwind / $m_s__per__km_h;
481 0           printf
482             "weight: cyclist %5.1f + machine %4.1f = total %5.1f kg\n",
483             $self->weight_cyclist, $self->weight_machine, $self->total_weight;
484             } else {
485 0           printf
486             "grade of hill = %5.1f%% headwind = %4.1f mi/h\n",
487             100.0 * $self->grade, $self->headwind / $m_s__per__mi_h;
488 0           printf
489             "weight: cyclist %5.1f + machine %4.1f = total %5.1f lb\n"; # XXX
490             }
491 0           printf
492             "rolling friction coeff = %6.4f BM rate = %5.2f W/kg\n",
493             _numify($self->rolling_friction), $self->BM_rate;
494 0           printf
495             "air resistance coeff = (%6.4f, %g)\n",
496             $self->calc_A2, $self->A1;
497 0           printf
498             "efficiency: transmission = %5.1f%% human = %4.1f%%\n",
499             100.0 * $self->transmission_efficiency,
500             100.0 * $self->human_efficiency;
501 0           print "\n";
502             }
503              
504             sub _init_output {
505 0     0     my($self) = @_;
506 0 0         if ($self->given eq 'C') {
    0          
507 0           $self->power($self->human_efficiency *
508             ($self->first_C * $Watts__per__Cal_hr - $self->BM));
509 0           $self->P_incr($self->human_efficiency * $self->C_incr_W_cal_hr);
510             } elsif ($self->given eq 'P') {
511 0           $self->power($self->first_P);
512             } else {
513 0           $self->velocity($self->first_V * $m_s__per__km_h); # m/s
514             }
515             }
516              
517             sub _incr_output {
518 0     0     my($self) = @_;
519 0 0 0       if ($self->given eq 'P' || $self->given eq 'C') {
520 0           $self->power($self->power + $self->P_incr);
521             } else {
522 0           $self->velocity($self->velocity + $self->V_incr_ms);
523             }
524             }
525              
526             sub output {
527 0     0 1   my($self) = @_;
528              
529 0 0         if (!$self->imperial) {
530 0           print
531             " kph F_kg P_a P_r P_g P_t P hp heat " .
532             # "BM C kJ/hr \n";
533             "BM C Cal/hr\n";
534             } else {
535 0           print
536             " mph F_lb P_a P_r P_g P_t P hp heat " .
537             "BM C Cal/hr\n";
538             }
539 0           $self->_init_output;
540 0           my $entry;
541 0           for ($entry = 0; $entry < $self->N_entry; $entry++) {
542 0           $self->calc();
543 0           printf
544             "$fmt{'V'} $fmt{'F'} $fmt{'Pa'} $fmt{'Pr'} $fmt{'Pg'} $fmt{'Pt'} ".
545             "$fmt{'P'} $fmt{'hp'} $fmt{'heat'} $fmt{'B'} $fmt{'C'} ".
546             "$fmt{'kJh'}\n",
547 0           map { $self->{'_out'}{$_} } @out;
548 0           $self->_incr_output;
549             }
550             }
551              
552             sub tk_interface {
553 0     0 0   require BikePower::Tk;
554 0           BikePower::Tk::tk_interface(@_);
555             }
556              
557             1;
558              
559             __END__