Saturday, January 23, 2010

simulating Metrigear Vector cadence extraction (pt 1)

I've done a lot of discussion about the MetriGear Vector. A brief summary of some conclusions.

Metrigear Vector

The Vector measures force components on the pedal. These force components can be derived from bending moments measured at at least two positions in the spindle. Power equals force in the direction of pedal motion multiplied by pedal speed. Pedal speed is rotation rate multiplied by crank length. Crank length can be derived from data, or instead as Metrigear has indicated, can be provided by the user. Providing it simplifies calculations.

With a spindle firmly screwed into a crank, the propulsive direction is always the same, perpendicular to the direction of orbital (centripetal) acceleration. Acceleration in the tangential (propulsive) direction averages to zero, while the centripetal acceleration averages to a positive value. Determining which direction of acceleration averages to zero allows the system to orient itself, to determine which is the propulsive direction, without requiring careful orientation of the hardware (as Metrigear describes doing with FrankenRider for test purposes).

Once the system has a good idea how it is oriented, it can determine the radial acceleration. However, there are many acceleration components. For example, when the bike speeds up or slows down, there is a forward or reverse acceleration component aligned with the direction of bike motion. When the bike bottoms out at the end of a descent there's a vertical acceleration component. And when the bike hits one of the many bumps on our fine San Francisco Bay Area roads, there's a corresponding response in vertical acceleration. Additionally, road bumps will introduce longitudinal (in the direction of bike motion) accelerations.

In addition to the direct affect of road bumps, there are internal modes of the bike-rider system. Hitting a single bump may cause the bike to oscillate. These oscillations are generally at relatively high frequency (30-60 Hz, for example), though, and can be filtered from the data before sampling.

The key is that all of these acceleration components move both pedals together. From the standpoint of the spindles, the accelerations are in opposite directions, since the spindles are rotated 180 degrees relative to each other, once they are "aligned" relative to the direction of pedal rotation. So for example if I hit a bump with the pedals at 12 o'clock and 6 o'clock, one spindle experiences an acceleration towards the center of the crank, the other away from the center of the crank. So if I average the accelerations on the two spindles relative to the direction to the center of the crank, or relative to the direction of propulsive rotation, these other acceleration components cancel. This is an advantage of the Vector versus the Brim Brothers system, which has accelerometers and force sensors in the cleats. The spindles have a nice stable orientation relative to the propulsive direction. The cleats, on the other hand, are constantly shifting relative to the propulsive direction.

So if I average the left and right spindle signals, I should be able to isolate the centripetal acceleration. Then I can derive the rate of pedal rotation (knowing crank length). Then extracting the correct component of force, I know power.

The key question, though, is how well does this all actually work? Metrigear set for itself an accuracy target of 1.5%: ouch! Assuming some error in force extraction, it had better be well under this threshold in rotation rate extraction, at least for the time scale for which this accuracy target applies (it doesn't necessarily, for example, get 1.5% for each millisecond).

So to see if this 1.5% target was reasonable, I decided to write a little simulator in Perl. This also gave me a chance to see if my proposed method of pedal rotation rate extraction actually worked.
....
my $a = $ride_data[$ndata]->[2];
my $v = $ride_data[$ndata]->[1] +
$a * ($t - $ride_data[$ndata]->[0]);
my $phase = $phase0 + $s * $dphaseds;
my $omega = $v * $dphaseds;
my $rpm = $omega * 60 / $twopi;
my $domegadt = $a * $dphaseds;
my $cos = cos($phase);
my $sin = sin($phase);
$s += ($v + $vlast) / 2 * ($t - $tlast)
if ($ndata > 0);

# calculate acceleration components
# assume left and right crank are 180 deg out of phase
# phase is defined as zero when cranks are horizontal
my (%ax, %ay);
my $sign = 1;
for my $lr ( "L", "R" ) {
my $g_noisy = $gfactor * $g + $a_noise_v;
my $a_noisy = $a + $a_noise_h;
my $at = $sign *
($sin * $a_noisy -
$cos * $g_noisy) +
$domegadt * $L;
my $ar = $sign *
($cos * $a_noisy +
$sin * $g_noisy) +
$omega ** 2 * $L;
$ax{$lr} = $calign{$lr} * $ar +
$salign{$lr} * $at +
$a_noise{$lr}->{x};
$ay{$lr} = -$salign{$lr} * $ar +
$calign{$lr} * $at +
$a_noise{$lr}->{y};
$sign = -$sign;
}

Etc....

Now, before everyone immediately runs for the exits, I'm not going to describe the nitty-gritty details of these simulations, such as detailed signals the accelerometers would see, or the details of how I do the orientation determination. Frankly, these details would just bore even those of you I haven't already bored, anyway. So I'll just focus on the results. Can it hit the rotation rate target? Given a simplistic assumption of "noise" based on the work of Champoux and Hastings I've already described, does can it see the "signal"? These questions could actually be answered fairly simply analytically. But it's more fun to do so numerically.

More next time.

No comments: