Thursday, October 31, 2013

comparing some statistics riders vs. testers @ Low-Key Portola Valley

This is yet another in a series of the Low-Key Hillclimbs Portola Valley Hills multi-climb day. We used GPS to time riders based on when they were interpolated to have crossed a series of "lines" (essentially passing through virtual pylons) in the correct direction. Between certain lines there was a time budget which was designed to be easy to meet, as long as you didn't dally. The lines were designed to be wide enough so all riders who rode the course would be credited with crossing all of the lines, even in the presence of GPS errors.

It all worked so well in testing. But in practice, on "game day", the conclusions from testing proved optimistic.

First I'll look at time budgets. I had provided a lot of slack in these, and I needed it. There's two major reasons for this. One is that the test riders were mostly solo. On the other hand the "event" riders tended to ride in groups. With group rides the faster riders would wait at the top of climbs for slower riders. This added time to all but the slowest climbers in the group.

Another reason is the riders knew what their time budget was. Since they wanted to recover to produce a good result on the following climb, they likely rode at a slow enough pace to use a reasonably large fraction of the time budget.

Here's a plot shoing that: I plot the fraction of the time budgets taken by the testers for each checkpoint superposed on the fraction of time taken by the event-day riders. You can see the testers tend to fall at the lower range of the distributions. Indeed, at checkpoint 10 I had to increase the time limit from 10 minutes to 15 minutes.

time budgets

Checkpoint 4 is Joaquin, which I neutralized by assigning a large time budget. Curiously the time budget I was initially most worried about, the long grind to checkpoint 3, was the least issue. The long spin to Summit Spring was an issue for one rider who stopped for around 16 minutes in addition to taking a longer than recommended path. I hadn't thought that transfer was going to be an issue.

Then I looked at the line crossings. I earlier showed that with my initial line definitions the test riders used only 1/3 of the total line width. Well, that turned out to be optimistic. In the actual event I had to considerably widen several lines, in particular on Golden Oak and on Summit Spring, but also at the top of Golden Oak East for one outlier activity. Here's a histogram of the line crossing parameters for the test riders (using the new lines) plotted along with the same statistics for the riders on Saturday.

line crossings

The statistics are shown in the legend. The standard deviation for ride-day was substantially larger than the standard deviation for the test riders. Standard deviation represents the spread in points under the assumption points are normally distributed (characterized by a Gaussian probability function). However, the "ride day" curve deviates from a Gaussian shape. There are a significant number of non-normal outliers, with errors which extend considerably beyond the Gaussian core. The Gaussian portion itself is similar between the testers and the Saturday riders. The outliers are what are responsible for the increased standard deviation int he statistics.

The test should be whether a certain bike computer is responsible for a disproportionate fraction of the outliers. I wanted to test this but my first attempt at HTML scraping failed because of Strava's restriction of that information to clients who have logged in, and my Perl script did not log in. And it's not provided to via their API.

In any case, the message is clear: it's important to test with a broad range of testers. My testing, which led to the conclusion the course was robust, was optimistic.

Wednesday, October 30, 2013

A look at GPS data from Low-Key Hillclimbs Week 4: Portola Valley Hills

This is another in a series of the Low-Key Hillclimbs Portola Valley Hills meta-climb. It was the second climb where Low-Key used custom timing code to extract rider times from GPS data. But it was by far the most complex, since instead of one climb where time was the difference between the time at the top and bottom, it was a series of 5 climbs where the times from each were added.

I did preliminary testing of the Portola Valley Hills course with 6 data sets of riders who had attempted to pre-ride the course. One did the climbs in the incorrect sequence, leaving 5 riders which the scoring code processed. I had no problem with these riders.

But it's a big difference between processing 5 data sets and processing 70.

Here I'll look at the GPS tracks I recorded for each of the climbs in the Portola Valley Hills. First, the good. Here's plots for the three climbs ending at appropriately named Peak. The plots are x versus y, where x and y are the distance eastward and northward in meters or kilometers from the first checkpoint of the course. It's obvious which axes are in km and which are in meters.

Golden Oaks + Cervantes

Cervantes is blue, Golden Oak West is green, and Golden Oak East is red. These data look very good. There's one or two wayward data sets on each climb. The one deviant track on Cervantes appears to recover right at the finish line, which is to the right. Golden Oak West contains one slightly deviant trace, but it deviates only for one turn in the middle of the route, which is irrelevant for total timing. Golden Oak East has only one trace where there appears to be a chance for an error of any significance.

Now the bad. Summit Spring is next.

Summit Spring

The start is to the right, the finish to the left. There's at least 5 tracks which deviate substantially from the main "cloud" of 65. In several cases I applied manual finish line shifts to accomodate these deviant trajectories. The rest look fairly good. Note even small distance shifts on Summit Spring can yield time shifts of several seconds. But that's part of the deal with this week's climb. In the name of diversity we decided to live with a bit less precision.

Finally, the ugly. Joaquin.


Joaquin was a mess. Several riders were diverted substantially to the WNW. One rider's GPS launched a start-line-piercing spike to the SSW. Then there's that strange trace shooting out to the SE. The finish area is arguably manageable, but the start area is a total wreck. I saw this plot and I threw in the towel. It would be too much contamination of the final results. I neutralized Joaquin.

Before you say "what was he thinking??"", here's the data from the test riders, shown in green, plotted versus the event data, shown in red. The plot is zoomed in relative to the previous one, so the extreme outliers on the red data are truncated. Sure, the green data aren't great. There's some lateral spread. But it's all quite consistent with the spirit of the event: accuracy to within 5 seconds or so on each climb.

Joaquin test

I may look more closely at these data in the future. In particular I am interested in whether the outliers in this plot are associated with a particular GPS unit. To do that I need to scrape the HTML from Strava, using the URLs for the rider activities, to get the computer type. It's not provided in the V3 API. It's slightly complicated by authentication, but that's another matter.

In any case, the moral of the story is processing GPS data from a diverse group of hillclimb enthusiasts is a nontrivial task. It's critical to identify problem cases like Joaquin before starting a competition. An alternative is to use altitude data in conjunction with position to do timing. I didn't investigate that option, and indeed I didn't even record altitude numbers when I had then upload their rides to But the deal with altitude is it may be recorded directly, like with the Garmin Edge 500-800, or may be determined from map data using the recorded position, as it is typically with phones and with the Garmin Edge 200. So using altitude only provides independent information if it is derived from a unit which measures altitude directly.

So next time, we pick hills where the start and finish have nice clear views of the sky.

But I received one suggestion which was very promising. Instead of a total time based on a sum of indidivual times for each of every climb on a course, give riders one or more "throw-aways". Then if they have GPS issues on one climb and fail to match the course, that becomes a throw-away. If a rider matches all climbs on the course, throw-aways are those climbs contributing least well to his total score. Riders would then be given a time for throw-away climbs relative to the average and standard deviation rider time for that climbs and how they compared to the average and standard deviation of times on their counting climbs. This would work, but would require more coding. Maybe I'll try something like that on the Portola Valley data set, as a trial for something next year.

Tuesday, October 29, 2013

recursive course timing for Low-Key Hillclimbs week 4: Portola Valley Road

There were a number of challenges with organizing the Portola Valley Hills Low-Key Hillclimbs. For example, the Edge 500 GPS quality on Joaquin Road. But one of the more interesting was the scoring conundrum represented by a rider who repeated one of the climbs.

The scoring code I used here was originally developed for Kennedy Fire Road last year. There we had a long climb with a number of intermediate check-points. To get an overall time I assigned a time to each checkpoint, but overall time was essentially the time crossing the finish minus the time crossing the start. If the rider completed the course multiple times I'd keep track of times between the start and finish and take the shortest one. If a rider recrossed the start line I'd start over. If he crossed the finish line I'd ignore everything until he recrossed the start line. It was easy.

For Portola Valley Hills I added in the cocnept of time budgets for time segments between checkpoints. If a rider took less than the time budget between checkpoints then no time was assessed for that segment. The idea was to keep riders moving on the course but not put any time pressure on riders to rush from one climb to the base of the next. This worked fairly well, except a regoup at the top of Cerventes resulted in the first riders there exceeding the 10 minutes I had allocated for the transfer to Golden Oak West. No problem: I increased the time to 15 minutes, since I wanted to encourage groups to stick together to help with navigation. And navigation went very well. Nobody missed any checkpoints, which is remarkable.

With a climb like Kennedy Fire Trail, suppose a rider recrossed an earlier checkpoint due to backtracking. That wouldn't matter: the time was ticking. If I was ranking riders on splits between checkpoints I'd just take the shortest time between checkpoints. But for total time, how I allocated total time between checkpoints was irrelevent. Total time was just the finish time minus the start time.

With Portola Valley Hills, however, it did matter. For example, suppose I have the following checkpoints:


where A-B has a time budget of 10 minutes, C-D has a time budget of 10 minutes, but B-C has no time budget and therefore contributes directly to total time. If the rider passes right through, crossing A-B-C-D, there's no question about how to score this. Suppose A-B takes 5 minutes, B-C takes 2 minutes, and C-D takes 7 minutes. 5 minutes and 7 minutes are each less than the 10 minute budget, so they contribute zero. That leaves the 2 minutes from B-C, which is thus the overall time for this portion of the route.

Now consider a rider who repeats the climb of B-C. That rider then crosses the checkpoints in order A-B-C-B-C-D. I had anticipated this, considering riders might want to redo segments if they had difficulty such as a dropped chain. If they repeated a climb they would likely go faster the second time, because if they'd been fast the first time, they wouldn't have repeated it. So I took for each checkpoint the last time the rider crossed that checkpoint, unless the checkpoint was the beginning of a segment with a time budget, then I took the first time the rider crossed it. The reason for this special treatment is it assigned more total time to segments with time budgets. But for repeats of timed segments the last time would count.

But what happend at Portola Valley is one rider repeated a climb but was slower the second time. He expected his first try should have counted, and with good reason. But the code essentially ignored his first crossings of checkpoints B and C. Thus his checkpoint crossing pattern of A-B-C-B-C-D became simplified by ignoreing the crossings in (): A-(B-C-)B-C-D. The first climb and return to the start of that climb was considered part of the transition from A to B. Using the numbers before, with A-B taking 5 minutes, and B-C taking 2 minutes, the code would assume A-B was 7 minutes. The time for the second climb of B-C, for example 3 minutes, was then taken as the time for that. The time from C to D was thus 7 minutes and under the 10 minute budget.

The rider would have preferred eliminating the checkpoint crossing in () as follows: A-B-C(-B-C)D. Then the return to start and second climb of B-C would be considered part of the budgeted C-D transition. The second climb B-C was 3 minutes and the subsequent ride to D was 7 minutes so this is exactly the 10 minute budget so A-B and C-D would each be counted as zero, with B-C counted as 2 minutes, for a total time of 2 minutes.

I could have tried to kludge some ad hoc rule of thumb into my scoring to deal with this. But it would have also been flawed. Consider a similar situation: A-B-C-B-C-D. Again, A-B takes 5 minutes, B-C takes 2 then 3 minutes, but this time C-D takes 9 minutes. The rider could choose the first, faster B-C at 2 minutes, but then the second B-C would get lumped in with the C-D and total 12 minutes, exceeding the 10 minute budget. So the rider would receive a total time of 4 minutes. On the other hand, taking the second, slower of the B-C climbs would result in 7 total for A-B (under budget), 3 for B-C, and 9 for C-D (under budget). The total would be 3 minutes, less time despite using the slower climb of B-C.

So I had to come up with a new look at the problem. Kludged fixes wouldn't do. It gets worse when you add in accidental line crossing, a too-common occurance with so many of the climbs ending at Peak Road, and with some riders taking an alternate route to Summit Spring which crossed the Hillbrook pre-start.

I realized I needed the computer to consider all possible interpretations of a rider's data. A completion of a course involves passing all checkpoints in order. There may be other checkpoint passings, for example repeating climbs, or perhaps accidentlly triggering checkpoints from earlier climbs when moving from one checkpoint to the next. Checkpoint recrossings were another issue with which I'd had to deal, and I'd added more complexity to ignore checkpoint crossings which were inconsistent with repeating climbs. It was turning into a mess.

But by considering all possible interpretations of the data, without trying to be intelligent about it, I could calculate all possible times for the rider, and simply take the fastest. It was just a matter of how to figure out all possible interpretations of the data. After I'd thought about it a bit, I realized recursion was the simplest and most reliable approach.

But first consider the example:


I can number these crossings 1=>A, 2=>B, 3=>C, 4=>B, 5=>C, and 6=>D. From this, I need a sequence A-B-C-D. I have several options for this:


Note each of these maps to A-B-C-D. For each of these I can then calculate a total time. I then simply take the one with the best time.

With recursion, the problem is simplified. I need to consider only three cases: how to know when I've got a solution, how to know when there is no solution, and taking the next step towards constructing a legal sequence of checkpoint crossings. To do this I divide the list into two portions: those checkpoints which I've decided to use so far, and those checkpoints crossed after the last checkpoint on that first list for which I have not yet decided. I then need to keep track of which checkpoint needs to be crossed next.

I start with no checkpoints in the first list, all in the second list. So I have 1=>A, 2=>B, 3=>C, 4=>B, 5=>C, and 6=>D in the second list. The next checkpoint to be crossed is A. I'm not done, because D isn't at the end of the first list (there is no first list). I'm not out of solutions, since there's an A in the list of unprocessed checkpoints. So I pick an A. There's only one, so this is easy. That goes into the first list. The others remain in the second list.

Now the lists are 1=>A for the first list, and 2=>B, 3=>C, 4=>B, 5=>C, and 6=>D for the second list. The next checkpoint is B. I'm not done (the first list doesn't end in D) and I'm not stuck without a solution (there's at least one B in the second list). Indeed, there's two B's in the second list. So I need to try both cases. This is where recursion is so useful. The computer can keep track of each separate case using the language's (in this case Perl) recursion support.

So I first consider the case where I put 2=>B on the first list, and solve the problem for the next checkpoint is C. I then get 1=>A, 2=>B for the first list, and 3=>C, 4=>B, 5=>C, and 6=>D for the second list. I then need to solve the second list for the next node being C. There's two possibilities, so I need to try both.

Eventually I'll finish solving these problems and then I return to solve the case for the second choice of B. In this case the first list would be 1=>A, 4=>B, while the second list would be 5=>C, and 6=>D.

Eventually in each case where I don't walk down a dead-end (this is a lot like my favorite maze-solving algorithm). Then the first list contains a sequence A-B-C-D and I know I'm done. The second list may or may not be empty. The rider may have crossed checkpoints after the finish line. But as soon as D is crossed having crossed A-B-C, the rider obviously doesn't want to continue.

Once I came up with this algorithm, laying in bed at 3 am, things became so much simpler. The rider could ride multiple laps, cross random checkpoints accidentally, etc, and while these may add to the work the computer needs to do, it will always find the interpretation most favorable to a rider. My growing list of ad-hoc rules I'd used before could be discarded. No rider can ever get himself into trouble by crossing a checkpoint versus not crossing it.

Unfortunately, when I thought of this at 3 am on Monday morning, I had to code it immediately. A 1:27 Caltrain delay on my morning commute allowed me to finish the job. But then later that day I got a recommendation for another, unrelated enhancement which would require me to rip open the code again. No doubt I'll get sucked back in and get to work again.

Friday, October 25, 2013

Tour de France 2014: total km versus historical trend

Back in 2010 I did a regression of the Tour de France total length since WWII. There was a clear overall trend of course length reduction. In the 1920's, a typical route was 5500 km. By the 2000's that had decreased by 2000 km. The effect of this was profound: the Tour went from an ultra-endurance event with stages starting hours before dawn, unable to sustain body mass, to one where riders are able to devote considerably more time to recovery each day.

Since then I like keeping tabs on the distance to see how it's doing relative to that trend. After all, while most of the public focuses on the final 20 km of each stage, it's the up to 200 km preceding that which provide the real character of the event, wearing down riders and teams and tapping into the human body's endurance limits. Without those preceding kilometers, the Tour loses some of its character. Even with the pack still together, it's what I call the "unseen attrition" of the effort. It wears riders down. Only those able to survive it are in a position to sprint for the win. The Tour is a self-selecting group. If the stages were half the distance, the final 20 km might seem much the same, but it would be a different group, or at least the riders in that group would have a different physiological optimization. It would lose a good part of it's epic nature which makes it so attractive.

When CyclingNews published data for the 2014 route, I had another datum. Here's the plot:


2014's tour distance of 3656 is a strong showing by recent standards: the longest since 2000. But every year 1996-2000 was longer, as was every year 1991-1994. There was a palpable reduction in distance around 2000. But since that drop there has been a plateau. After a relatively short 2013 course, the shortest since 2002, 2014 supports that the present plateau is being upheld. The new distance standard established around 2000-2001 shows no signs of being further diminished. The following highlights the present millenium and the last year of the prior:


Every year since 2006 has been above the trend line, although last year came close.

But before the traditionalists get excited that we've seen a boost in stage length, the reason for the change is more the type of stages than their length. First, there's no prologue, and prologues are traditionally extremely short, for example 10 km. Second, there's only a single individual time trial, and it's relatively (by today's standard) long at 54 km (a throwback to a time trial in the 1994 Tour, which is coincidently the one and only year I attended). And third, there's no team time trial, and while there have been some epic-distance team time trials in Tour history, in the last decades the rare team time trial has been short so as to minimize the impact on general classification. The road stages themselves are still short by traditional standards. The average of the first 19 stages is 182 km, with a standard deviation of 30 km. Stage 19 is only 125 km, which 20 years ago was a virtually unthinkable sum, except for a split stage. The day after is another mini-stage at 145 km.

Still, the traditionalist in me is happy to see this sort of total km number. I should seriously think about heading over. Carcassonne, perhaps? I was there in 1994.

Thursday, October 24, 2013

response to Bicycling article on Kim Flint and Strava

I couldn't believe what I was seeing when I got an email from Bicycling magazine promoting an article which discusses Strava's responsibility in Kim Flint's death in June 2010. The article is here. It spawned an even more remarkable set of comments arguing Strava had responsibility in Flint's fatal crash, which resulted when he went after a downhill KOM in the Berkeley Hills. There was a law suit resulting from the crash, pressed by Flint's family, and Strava won. The result of the crash was Strava's segment flagging policy, as well as a beefed-up user agreement bludgeoning the potential user even stronger with the idea of personal responsibility and the inherent danger of the roads. It additionally resulted in Strava's Stand With Us policy, calling on users to support it's vision of friendly competition with personal responsibility.

Here was my response to that Bicycling article:

Any argument that Strava should take responsibility for removing downhill segments is poorly thought out. Once Strava gets into the game of personally deciding what is safe and what is not, numerically or humanly, it's a dangerous precedent. Sure, this segment on which Flint died may well be viewed as dangerous, but what of a predominantly climbing segment with a short descent along the way, as many extended climbs contain? What of an ultra-endurance segment, crossing a state, which invariably crosses intersections, perhaps with stop signs or traffic lights? For every "dangerous" segment I can show you another which would generally appear reasonable, yet which contains similar dangerous aspects.

So instead Strava has put the burden on users: users to exercise judgement for their own behavior, users to flag segments for which no reasonable attempt at speed can be considered safe. Indeed, it's often argued this flagging goes too far by allowing a single user to permanently flag a segment.

So the answer: Kim Flint is responsibly for Kim Flint's death, and perhaps the driver if the driver was also speeding for the conditions of that road. Nobody else. Not Strava. Not the creator of the segment. Not you or me. The roads are a dangerous place, we know that, and we must act with appropriate caution. Being employed by NVidia is not a guarantee against stupidity in all aspects of life.

Tuesday, October 22, 2013

testing Portola Valley Low-Key Hillclimb: segment distance consistency

To further test the Low-Key timing on the Portola Valley route, continuing the work of the previous two blog posts, I decided to check the distance covered by 4 riders who completed the course on trial runs. The following is a summary of these results:

avg dd
sigma dd
Golden Oak E beginning
Golden Oak E midway
Golden Oak W finish @ Peak
Joaquin start
Joaquin finish
Hillbrook pre-start
Hillbrook start
Hillbrook finish
Cerventes start @ Kiowa
Cervents finish @ Peak
Golden Oak W pre-start
Golden Oak W start
Golden Oak W @ Toro
GOlden Oak W Peak
Summit Spring start @ Tripp
Summit Spring @ Patrol Road
Summit Spring finish

The distances shown in the plot are to the checkpoint in question. So for example for checkpoint 2, that's the distance covered from checkpoint 1 to that point. The distance is determined by interpolating ride crossings.

Two numbers are shown: the average distance covered and the standard deviation. The standard deviation represents the spread in the data. Two measurements selected at random are expected to differ by approximately one standard deviation.

There's several sources which could contribute to differences in ride distance for one rider to the next. One is obviously differences in ride distance. Riders didn't always take the optimal route, especially on transfer segments which were nominally untimed, intentionally (for example to stop for water) or unintentionally. Additionally sometimes riders took the inside line versus outside line on steep corners. Additionally it may be a different distance to different points along the start and finish "lines".

But another source is error. For example, GPS glitches may result in the recorded trajectory deviating from the actual trajectory. Then there's the finite sampling rate. A rider riding through a corner follows a curved path, while GPS samples taken at intervals, for example every 3 seconds for a phone but maybe every 8 seconds for Garmin's "smart sampling", will approximate that curved path by a shorter straight-line path.

On some cases, the standard deviation is very small. For example, the sections on Golden Oak are amazingly tight, with standard deviation of less than 3 meters. The other checkpoints tend to have more variation. For example, the first half of Summit Spring has 21 meters of variation. Part of this is riders choosing different lines, but the difference is too large for just that to be the case. The GPS signal likely isn't as good on Summit Spring, and the road there has a more convoluted path, which makes it more prone to position errors becoming distance errors.

Here's a comparison between two segments. The first is the upper portion of Golden Oak E, where there is a very tight spread on distance. The second is the upper portion of Summit Spring, where there is a much larger spread in distance. Golden Oak on the top is 20 meters per line on the y-axis, 50 meters on the x-axis. The bottom plot, Summit Spring, is also 50 meters per line on the x-axis, but 10 meters per line on the y-axis.

Note these plots have somewhat compressed x-axes due to an earlier error in my script.

Golden Oak top

Summit Spring top

What's the signifance of this? The distance differences don't directly translate into timing errors. However, they are suggestive of larger position errors, and position errors will yield timing errors. For example, on a steep finish of Summit Spring the average speed among these strong riders was 1.8 meters per second. So a 10 meter GPS position error could yield a 6 second difference in time out of an average on that segment of 218 seconds.

That's just how it goes with GPS timing... sometimes you need to get lucky.

San Francisco Transit First policy

I tried to find the San Francisco Transit-First policy and indeed some old links were stale. I dug it up again at this link. But it's sort of flaky, so to give myself a chance of finding it again, I figured I'd just copy it here.

The transit-first policy of San Francisco is brilliant for its time, as it was passed in the dark ages of the 1970's. But unfortunately even though we consider ourselves now far more enlightened, the policy is typically ignored. Compliance is by convenience, not by intent. In any case, that it persists in the city charter gives continued hope for the future. We now realize the focus on the car in the mid-20th century nearly killed our cities as virtually all new infrastructure investment was in suburbia, a failed, unsustainable, unscalable model. Today demand for cities is higher than ever, and with a half-century of neglect, supply is inadequate. As a result the most expensive housing in the nation is in urban cores. Cities are cooking from the economic pressure of soaring housing costs. It's not wide expressways and highway interchanges which attract people: it's being part of a vibrant community, and cities provide that.

Here's the section of the charter:

   (a)   The following principles shall constitute the City and County's transit-first policy and shall be incorporated into the General Plan of the City and County. All officers, boards, commissions, and departments shall implement these principles in conducting the City and County's affairs:
      1.   To ensure quality of life and economic health in San Francisco, the primary objective of the transportation system must be the safe and efficient movement of people and goods.
      2.   Public transit, including taxis and vanpools, is an economically and environmentally sound alternative to transportation by individual automobiles. Within San Francisco, travel by public transit, by bicycle and on foot must be an attractive alternative to travel by private automobile.
      3.   Decisions regarding the use of limited public street and sidewalk space shall encourage the use of public rights of way by pedestrians, bicyclists, and public transit, and shall strive to reduce traffic and improve public health and safety.
      4.   Transit priority improvements, such as designated transit lanes and streets and improved signalization, shall be made to expedite the movement of public transit vehicles (including taxis and vanpools) and to improve pedestrian safety.
      5.   Pedestrian areas shall be enhanced wherever possible to improve the safety and comfort of pedestrians and to encourage travel by foot.
      6.   Bicycling shall be promoted by encouraging safe streets for riding, convenient access to transit, bicycle lanes, and secure bicycle parking.
      7.   Parking policies for areas well served by public transit shall be designed to encourage travel by public transit and alternative transportation.
      8.   New transportation investment should be allocated to meet the demand for public transit generated by new public and private commercial and residential developments.
      9.   The ability of the City and County to reduce traffic congestion depends on the adequacy of regional public transportation. The City and County shall promote the use of regional mass transit and the continued development of an integrated, reliable, regional public transportation system.
      10.   The City and County shall encourage innovative solutions to meet public transportation needs wherever possible and where the provision of such service will not adversely affect the service provided by the Municipal Railway.
   (b)   The City may not require or permit off-street parking spaces for any privately-owned structure or use in excess of the number that City law would have allowed for the structure or use on July 1, 2007 unless the additional spaces are approved by a four-fifths vote of the Board of Supervisors. The Board of Supervisors may reduce the maximum parking required or permitted by this section.
(Amended by Proposition A, Approved 11/6/2007)
Editor's Note:
   Formerly Sec. 16.102.

testing time budgets: 2013 Low-Key Hillclimbs week 4, Portola Valley Hills

For Low-Key Hillclimbs week 4 riders must ride a series of short hills, and we add up their times on those hills. The intent is that riding between the hills not be included, but we don't want the riders to head out for lunch between climbs, the intent is that the ride be continuous, providing some test of endurance over short hills as well as peak power. So to allow for that there is a time budget to get from one hill to the next.

But if a rider needs to wait for a friend to finish the preceding climb, takes a wrong turn, or even has a puncture and does a fairly quick tube swap, we want the rider to have time to complete the transition. So the times to get between the climbs have been generously allocated. Additionally, Low-Key gets a broad range of riders, including unicyclists in the past, and so it would be a mistake to set these time limits for the fastest riders and compel the more endurance-oriented riders to take stupid risks to avoid additional time being added to their total.

Several riders have pre-ridden the course and posted their data on Strava. I have tested these riders with the PHP and HTML code I will use for rider data entry after the climb. Either the rider or I was able to transfer the data from Strava to the Low-Key Hillclimbs server in every case except one where the rider was using Internet Explorer. I don't consider Internet Explorer's woes to be my problem: it's essentially a broken browser. Fortunately these days almost everyone has access to an alternate.

My code generates a status report of how long it took riders to complete these "transfer" segments relative to the time budget. All of the riders who completed the course are relatively fast, all have ranked highly on Strava segments. So the test is optimistic: I need to make sure the time budget leaves plenty of buffer for the endurance crowd.

Here's the result:


Note there's no data for segments where there is no time budget, segments which are part of the climbs which are intended to fully contribute to the end result.

For the other segments, all points fall well below the 100% limit at which time starts to count. This includes a transition where one of the riders expressed considerable concern over having gone too long due to detouring and stopping for water. That was the point to checkpoint 10 where 71% of the time budget was used. The same rider earlier took a wrong turn (he did the ride before I'd prepared a cue sheet for navigation). This added around 100 meters of extra riding, but more importantly led to a delay while he figured out his error. Here he used 63% of his time budget. So in both cases, despite not taking the most direct route between the points, he finished the sections with plenty of time to spare. All other riders completed all segments with at least 40% of the time remaining (no more than 60% used).

So it seems as if we're ready to go. Riders are crossing the lines reliably and have plenty of time to get between hills. My fingers are crossed things go well. Low-Key is, after all, a perpetual experiment.

Monday, October 21, 2013

testing line-crossings for Low-Key Hillclimbs Portola Valley Hills course timing

For Low-Key Hillclimbs week 4 this year, we're doing a GPS-timed route which I have been told is similar to something which has been used in rally car races: the riders must follow a somewhat challenging route, doing a series of short climbs in a given order, where the net time is calculated as the sum of the times taken to get up the hills with any time taken to get between the hills if those are over the allowed budget. So if there's two hills, and there's a budget of 10 minutes to get from the top of the first to the bottom of the second, then if the rider takes 8 minutes to cover the gap, there is no time assessed for that, but if it takes 12 minutes, that would add 2 minutes to the rider's total time. The ideas is that the time be based only on the climbs, but that the rider make a reasonable effort to get from one climb to the next in a timely fashion.

Key to all of this is to time the rider between checkpoints. I define checkpoints as one would in most races: with a line, conceptually between pylons, where the rider must have a GPS track which passes between the pylons. Since GPS is prone to position errors, and for that matter the maps on which the "pylon" placement is based also have error, it's important the lines be made ride enough that a rider riding on the actual road be registered as crossing the line legally. Too narrow a line and a rider might complete the full course but not be given credit. Too wide a line and you may pick up riders from nearby roads, or perhaps base timing on data which is of such poor quality that the resulting time has little validity.

So in placing my "pylons" I extended them a healthy distance past the edge of the roads as viewed in satellite view. I then took Strava tracks from people who pre-rode the route and ran them through my scoring code. I wanted to see if there were any close calls where the track barely squeezed into the defined line. In one case there was, and in that case I moved the line (which had been in a tight switchback) to a more robust location. There are 17 checkpoints in all, so it's important they be robust.

Of the rides I tested, the first was manually generated from exporting a GPX file from Garmin Connect. I added times to that using my simple bike speed model. The others were from four separate riders, three navigating the course correctly, the other doing the hills in incorrect order and therefore not getting credit for the full route. In each case I took the line crossings reported by my scoring code and assigned a number -100% to +100% based on how far to the left or right of center the rider was. A score of -99% or +99% would therefore represent barely crossing the line, while 0% would represent crossing the line dead-center between the "pylons".

I plot here the normalized line crossing position for these activities versus the checkpoint number (from 0 to 16):


The target was for points to fit within the middle half of the range, from -50% to +50%. All the points fit well within this range, with the extremes being -24% and +36%. The +36% point came from the "Golden Oak (W) pre-start", where the line length is restricted to avoid getting triggered by the road on the climb itself, which passes relatively closely. But even 35% is close to a factor of 3 safety margin. It thus seems if these data are representative, there should be no problem with riders registering their line crossings legally if they did indeed ride the course legally.

Saturday, October 12, 2013

working Low-Key Hillclimbs week 2: climbing Montevina

After coordinating week 1 of the Low-Key Hillclimbs last week, I was a volunteer for week 2, with the role of taking split times where the course transitioned from paved to dirt. It was a fun climb, mostly on paved Montevina Road, but then the riders traversed a barrier and continued the last half-mile on fire road.

To get there, I of course rode. So with a small backpack and on my trusty steel Ritchey Breakaway, I set off ahead of the riders to be in position before the leaders arrived.

Stephen Fong photo

This was to be my longest hard climb effort by a factor of two since I injured myself, and came after riding to work on back-to-back-days, that coming after a hard workout in the gym and physical therapy. Hardly what would be classified as a "pre-competitive taper". But despite this, I went out at a power pace (around 280 W avg) which would have been solid for me up Old La Honda, a substantially shorter climb than Montevina, at my peak fitness. Not surprisingly, this didn't last, and I faded. I managed to catch the fade and settle into something around 240 watts, which I sort of held, with one serious hiccup where I almost took a wrong turn and needed to loop around, until the steep stuff approaching the gate. For the finish, it was a simple exercise in survival, trying to keep my 36/26 turning.


Of course, despite all sorts of reasons this shouldn't be considered my best possible effort on this climb, my immediate response is "I'm too old to climb well anymore." But the rational self says, even if that's true, this doesn't show it. Training really works, and as I've noted here, my volume has been way lower than it was before the crash. And you're not going to whip out an amazing climb your first time trying anything close to Montevina's 500 paved vertical meters.

I'd like to be decent in three weeks, which should be the first one I ride for real.

Cara Coburn photo

The actual work of recording split times went well. I used the Android Ultrachron app. It's principal weakness is it's too easy to hit the "stop" button on the touch screen. I did this twice. The first time was when holding the phone before the first rider arrived. The second time was after the second rider arrived when I accidentally hit "stop" instead of "lap". As a result of the first, I had to restart the timer with the first rider, then sync with the finish line stopwatches after all riders had passed. In the second instance, I estimated it was 1.0 seconds between when I hit "stop" and then "start" again, so I adjusted times on this assumption. A good event-based timing app would just have a "lap" button, with "stop" a menu option. But overall it went well, except I missed one number, which I later got from the video camera we had set up there.

Sometimes taking split times means doing a bit extra for the riders. Here's a shot of Marco and Ruth on their most excellent Calfee custom tandem:

Cara Coburn photo

Friday, October 11, 2013

Yaw angle measured by Trek engineers on Ironman courses

I came across the following interesting tidbit on the CyclingNews review of the Trek Speed Concept 9:

To tweak the original Speed Concept, Trek engineers studied real-world wind conditions on Ironman courses, and settled on optimizing the bike for yaw angles between zero and 12.5 degrees. (They found 3-5 degree average yaw in Arizona, up to a 13 degree average yaw in the notoriously windy Kona worlds course.)

I came up with my own ad hoc calculation, including the Hellman model for ground shear, back in 2011. I published that here:

So the end result of all of this is that, given the assumption of an average 10 mph wind at 10 meter elevation (a stiff wind), a Maxwellan distribution of the ratio of wind speed to rider speed, an average rider speed of 11 m/sec (40 kph), and a Hellman coefficient of 0.34 (associated with urbanized areas), I get the average yaw angle magnitude is 6.8 degrees, with yaw probabilities extending from -20 degrees to +20 degrees. The yaw of greatest probability is, surprisingly, 0 degrees.

I've not seen any experimental data which contradicts this conclusion. But I look forward to seeing what comes across the forums, as this subject has gotten plenty of attention as wind tunnel testing becomes more popular.

This calculation, which drew some criticism, is standing up fairly well. The key here is "urbanized areas". The Kona course is rather extreme. Still, the point remains that those who argue rather extreme yaws on the order of 20 degrees are most important don't have much factual support.

Wednesday, October 9, 2013

Strava flagging proposal: a titration experiment

In my previous post, I noted that Strava segments can be flagged by a single, perhaps overopinionated, observer. Convinced a flag is unjust, other users redefine segments for essentially the same path. These new segments are typically flagged as well. This process may be further repeated, leading to a littered mess of redundent, flagged segments.

The obvious response is for Strava to allow segments to be unflagged. However, they need to be careful here, since it may well be the case if anyone can unflag a segment which had been flagged, enough users exist that persistent segment flagging could become essentially impossible. This would nullify the role of crowd-sanctioning that flagging is designed to play. There are segments which are intriniscally dangerous to contest, and Strava doesn't want to be found responsible for promoting dangerous competition.

So a balance is needed. But it doesn't take much imagination to derive a way to reach it.

It's a matter of titration. In chemistry, a titration experiment is one in which a basic solution is combined with an acidic solution in the proper ratio to yield a neutral solution. If the acid is more acidic than the base is basic, you need more base than acid to achieve a neutral balance.

The same can be applied here. There is some ratio of opinions that a segment is safe which balance a single opinion that it is not. Majority rule would imply that ratio is one. But perhaps one is not enough. Perhaps if the same number of people feel that something is safe as the number of people that feel it is dangerous, there is considerable doubt about the safety, enough to justify excluding that segment from competition. But at some point, the balance tips to concluding it is safe. For example, if 100 times as many people think a segment is safe as think it is dangerous, I think there is reasonable grounds to conclude it is safe. If the ratio is 10 times as many, I think most people would further conclude it is safe. Less than a ratio of 10, and reasonable people might disagree on the conclusion. But a 10:1 vote is fairly conclusive.

Don't like the ratio of ten? Fine, make it 20. Make it 17. Make it 42. Whatever. There exists a reasonable number. Presently there is no number.

So how do you conduct such a vote? I think the best way is to allow premium Strava users (this filters out marginal free accounts, perhaps multiple with the same person) to vote either up or down on a segment, one vote per account. Then Strava retains a list of who voted safe, who voted unsafe, and if the number of the latter is more than 10% of the former then the segment is flagged.

west side of Conzelman, Tim & Madie Photography

An alternate approach would be to wait for a segment to get flagged. Then you could introduce two widgets for that flagged segment: 1. support this flag, or 2. oppose this flag. If the number of opposers reaches at least ten times the number of supporters (including the original flag), the flag is removed, and those who flagged or voted can't do so again for that particular segment (the one vote per person policy).

The general idea here is that segments for which riders attempting speed records are a clear and obvious danger to other road users should be flagged. But sometimes the overzealous nullify segments which are perfectly qualified to be ridden safely under appropriate conditions. This approach would provide for a reasonable mechanism for these flags to be vetoed.

I think the real reason Strava doesn't do this sort of thing is a fear of lawsuit. It doesn't matter if a vote is 10 thousand to 1: it could be claimed they willfully ignored a warning that a segment was dangerous, exposing themselves. But I hope I'm wrong.

Monday, October 7, 2013

flagging segments: the case of the Hawk Hill backside

Yesterday I took advantage of an oh-so-precious closure of Conzelman Road in the Marin Headlands to ride the backside of Hawk Hill. While the road was "closed" in the sense of auto access, it was open as never before to hikers, walkers, and cyclists. The "closure" really revealed the potential for Conzelman Road, normally a congested, traffic-clogged tourist trap where drivers work their way through the numerous parking hotspots until they reach the top, get out of their cars, snap a few photos, get back in their cars, and battle the crawling traffic back down. This is all because the National Park Service, which oversees the Headlands as part of the Golden Gate National Park, operates under the policy that human legs are vestigial atavisms, and the only sort of meaningful human access is car access. Fortunately the people, young and old, enjoying the wonderful and rare serenity of the hill yesterday didn't buy into this 20th-century myth.

I, as did several others, took advantage of the wonderful lack of Federal presence by climbing the backside of Hawk Hill, the impressively steep east side of Conzelman Road, which due to the constraints of motor vehicles is one-way down-only. The road is plenty wide for bidirectional cycling traffic, and with the sharp and steep corners, descending riders need to be going slowly anyway. So I stuck to the extreme right, and rang my shiny brass bell when I approached blind corners. When I saw descending cyclists, I waved at them, just in case they failed appreciate my liberal interpretation of traffic law.

It was a worthy effort: initially, as I've been doing lately in efforts of this duration (around 6 minutes) tried to keep my power over 300 watts. But towards the top the road steepened, holding the increased grade longer than I'd remembered from descending. After what I thought was the top, more came into view. I came close to cracking, my power dropping as my legs became torque-limited rather than power-limited. Turning the pedals was an exercise in survival. My spirits were raised by two women, also climbing the hill, who cheered me as they chose the saner option of walking this section. I finally made it, wasted.

But the pain would be worth it, right? I'd at least get a solid time on Strava.

But it was not to be. Here's a segment of the climb: Kitty Hawk Climb Backside. And with it are listed those painful words: "This segment is ineligible for a segment goal because it has been marked as hazardous by another user." As I write this it's been "Ridden 113 Times By 106 People". Apparently they all survived.

What often happens in this instance is someone defines an equivalent segment, hoping the flagger's vigilance had waned. And so it wasn't surprising I observed a virtual copy: Hawk Hill Backside Climb. But it, too, has been flagged.

Flagging Strava segments is a controversial topic. The main issue is it's not a democratic process: all it takes is one user, of typically thousands examining a segment, to unilaterally decide the segment is unsafe, and he can flag it into oblivion. No amount of opinion to the contrary matters. And since there is a broad spectrum of what is construed to be safe, all it takes is one local extremist to render what the vast majority might consider a perfectly reasonable segment void.

My view: if going for speed presents a clear danger to other people, in particular pedestrians and/or juvenile cyclists, it should be flagged. On the other hand, if a segment presents a danger to the rider, that's his problem. We all sign a user agreement with Strava that we recognize cycling is intrinsically dangerous, and we are to use our own judgement about where to go fast and where to not do so. So a downhill segment such as the one on which Kim Flint died I would not flag. Kim was well into adulthood and should have realized that descending that road was dangerous. On the other hand, I would flag a segment on a popularly used pedestrian-only path. A mixed pedestrian-cyclist path is another matter, however. There I'm not sure.

The controversial issue is whether a segment needs to be safe always, or whether it needs to be safe at any time. For example, imagine a road which is heavily trafficked during weekdays at commute time, but which at 5:30 am on a weekend might have extremely small traffic. Of course it is dangerous to go plowing at top speed during the period of peak congestion, but should those with the motivation to ride it at the crack of dawn be denied the chance to see how their effort compared? We don't set speed limits for cars on highways based on what is safe during peak congestion: it is explicitly stated in the vehicle code that present conditions must be considered. The same principle applies to Strava segments.

Another example is a segment which goes through a traffic signal. Sure, you'd never hold a formal race on such a road without intersection control. But random users might get lucky and get the green light. In circumstances it may be perfectly safe to ride the segment quickly, assuming cyclists can't exceed the prevailing speed of motor traffic.

Stop signs are another matter. In the case of a long segment, for example an SF2G commute segment which will exceed 50 km, it is impractical to expect that there will be no stop signs along the way. But for a short segment, for example two blocks where between the blocks is a stop sign, running the stop sign at full speed would be critical to getting a high ranking. There I can understand why the segment might get flagged (although I have never done so).

So going back to the Hawk backside: riding this road, under rare circumstances, can be safe. It was far safer riding it yesterday, without any auto traffic, the "wrong" way then it is the "right" way with gaping tourists driving their oversized vehicles, admiring the views instead of the road ahead. So I definitely would not have flagged the backside of Hawk. Filbert Road in San Francisco also comes to mind: it's a one-way down street which is commonly climbed by cyclists in the opposite direction. There's plenty of room there for both bike and car and the principal risk is drivers pulling out of a parking spot, not anticipating uphill traffic. But the risk is almost completely to the cyclist, who on the 31.5% grade has virtually no momentum to present a risk to pedestrians.

Nothing in life is completely safe. Riding faster is arguably often riskier than riding slower. But driving faster is clearly riskier than driving slower, and we're a culture where driving quickly is not only accepted, but if one fails to do it, one is ridiculed and hated for getting in the way. So I think considerable thought should be given before flagging Strava segments. Perhaps, just perhaps, there is a valid alternate perspective to your initial reaction that the segment is a safety hazard.

Sunday, October 6, 2013

Car-Free Headlands, thanks to the Republican Party

I rode Hawk Hill in the Headlands today, and what an eye-opening experience. Rather than a traffic-clogged photo-op, it was a peaceful vista to be savored and enjoyed. Walkers, hikers, cyclists were going up and down the hill, all smiling at the rare opportunity presented by the Federal shutdown... the shut-down of a national park service that is so car-centric it views "access" synonymous with "car access". I went to the summit then started descending the backside of Conzelman. As I turned a corner I saw two women slowly climbing the other way. My first reaction was "they're crazy", until a few seconds later it occurred to me... why not? The "narrow" road is plenty wide enough for bidirectional bike traffic. So when I reached the bottom I turned around and climbed it myself: ouch, that is steep. It's an opportunity I'm not likely to get again.

I strongly recommend checking it out. It's a chance to envision the potential of Hawk Hill -- something more than a traffic-clogged parking lot where people step out of their oversized vehicles, snap a few photos, then drive back down. I really wish the park service would realize that their version of "access" destroys the beauty of what they have the duty to protect.

One downer: I suffered dearly on that oh-so-steep climb of the Conzelman backside only to later upload my data and find the segment was flagged. The pain, the pain...

Thursday, October 3, 2013

Low-Key Hillclimbs Montebello route image

Thanks to Will Van Kaenel for this great image, from Google Earth. Low-Key Hillclimbs begin Saturday!!!

Wednesday, October 2, 2013

post-injury progress

It's been three and a half months since my crash in June, and while I continue to progress, it's been a lot slower than I originally expected. Strength is improving thanks to Physical Therapy (@ Potrero Physical Therapy, supplemented by plenty of work in the gym), and my cycling is getting stronger after a break for some travel and watching America's Cup. My Strava plot tells the story (distance in km):

Note the short distances from late 2012 were from a focus on running versus cycling.

I can run short distances (very short) but even a half mile running to the gym last week left me slightly hobbled for a few days. I'm definitely looking forward to getting my running legs back, as I very much miss trail running.

Cycling is going better. While my right side is uncomfortable pedaling, it's not painful, and I'm more limited by lack of aerobic fitness and endurance than the injury. I've not yet done any extended climbs (more than 1100 vertical feet), and my longest ride was commuting to work this morning, 53 miles.

It's been frustrating, for sure. But the high degree of fatigue I suffered earlier is almost completely gone now. I continue to be mostly off caffeine for the first time since college, which is nice (I had some white tea when traveling to the East Coast due to jetlag). But for timeline I'm definitely thinking early next year before I'm going to set any meaningful fitness goals. For now the focus is on the physical therapy and on getting a minimal level of aerobic work in.

Tuesday, October 1, 2013

2013 World Championship Men's Road Race

The finish of the 2013 World Road championships was remarkable. There's something special about Road World Championships, with riders representing nations rather than trade teams, in a winner-takes-all scenario in which the winner always worthy, but where circumstances and luck play a substantial role.

In this case, after the crashes had filtered down the field, it came down to four riders: Nibali from host Italy, Costa from Portugal, and Rodriguez and Valverde from Spain. Obviously Spain had a big advantage with two riders who could win.

Rodriguez and Valverde have been like twin brothers the past few years. Despite riding for separate trade teams it seems like they're always together. But the past few years Rodriguez has been the stronger. And world championships was no different.

With two riders in the final four, Rodriguez launched. This put the team in an excellent position, as Valverde could just follow the wheels of the other two. If Rodriguez were to stay away and win, great -- Valverde would be fresh to sprint for second place. But if Rodriguez were caught, Valverde could immediately counter. Nibali and Costa, tired from chasing Rodriguez, would have been unable to stay with Valverde. But even if they were, even if they managed to pull out the effort it took to catch him, then Rodriguez would have had time to recover and been in prime position to take the win.

But when Rodriguez was caught by Nibali alone, without help from Costa, the inevitable counter from Valverde didn't happen. It was clear, Valverde, like the vast majority of riders in the brutally long and difficult race, was tired. So it was four again.

Because Costa was clearly tired, barely hanging on to the chase set by Nibali, this move, despite the fact Rodriguez was surely fatigued by this point, had a chance. Valverde would again sit on wheels, while Nibali was spent from having chased down Rodriguez's previous move.

But then it turned out Costa wasn't as tired as he'd appeared. He launched from the group, caught Rodriguez, and after a few seconds of tactical plplay, Rodriguez led out the sprint only to have Costa come around to take the championship.

Valverde was criticized by his coach for having not followed Costa. But it was clear: Valverde was cooked. There's simply nothing you can do if someone accelerates and you're not fast enough to follow.

Then Costa was criticized for not having contributed to Nibali's first chase of Rodriguez. This is a trickier issue, but Costa played the hand he had, and was able to just barely win as a result. It would have been no victory for Costa to have chased with Nibali only to have Nibali win the race. Nibali had to be frustrated, though. Had he not chased, Rodriguez would have won. Better to chase and then take chances with Valverde and Costa than to not chase and have no chance at all (barring Rodriguez crashing, suffering a mechanical problem, or physically self-destructing). But Costa took advantage of Nibali's willingness to take responsibility for the win.

But from Costa's perspective, he rode for Portugal, a minor team in the race, while Nibali represented Italy, the host team and a cycling power. Had Italy wanted to win the race, they should have had more than just Nibali in that front group. Costa had no responsibility to aid Italy. Italy wasn't some underdog with which Portugal was going to ally itself.

So Costa played a game and won. I'm not going to criticize anyone for how they acted in that race. That said, while the race was epic, I don't think anyone is saying the "strongest rider won". But Costa is only 26, still improving as a rider, so perhaps he will do the champion's rainbow jersey honor in the next year.