Add files via upload

This commit is contained in:
Peter Norvig authored and GitHub committed 2019-06-04 22:00:43 -07:00
1 parent 9b4bf15bfc
commit 76cd9dda04
3 files changed
+355 -152

No files matched your search

+287 -149
View File
@@ -4,12 +4,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"<div align=\"right\"><i>Peter Norvig, 23 Oct, 2017</i></div>\n",
"<div align=\"right\"><i>Peter Norvig, 23 Oct 2017<br>Revised 2 June 2019</i></div>\n",
"\n",
"# Bicycling: Speed versus Grade, Eddington Number, and H-index\n",
"\n",
"Like most people, I bike slower when I'm going up a steep hill than on a flat road. But how much slower?\n",
"To answer that, I downloaded all my recorded [Strava](https://www.strava.com/athletes/575579) rides longer than 25 miles as [`bikerides25.tsv`](bikerides25.tsv). Here I parse the file into a set of `Ride` structures:"
"To answer that, I downloaded all my recorded [Strava](https://www.strava.com/athletes/575579) rides longer than 25 miles as [`bikerides25.tsv`](bikerides25.tsv). I parse the file into `rides`, a list of `Ride` structures. I filter out all the rides that have exactly 0 ft climbing (i.e. stationary bike rides) and that have `'MTB'` in the title (i.e. mountain bike rides that are not relevant to road bike riding)."
]
},
{
@@ -27,52 +27,34 @@
"Ride = namedtuple('Ride', 'miles, feet, hours, date, title')\n",
"\n",
"def parse_ride(line: str) -> Ride:\n",
" \"\"\"Parse a line from a Strava log file into a `Ride`. Line format is:\n",
" \"\"\"Parse a line from a Strava log file into a `Ride`. Line format is tab separated:\n",
" Ride\tThu, 8/9/2018\tBRNW\t4:58:07\t68.41 mi\t3,862 ft\"\"\"\n",
" _, date, title, time, mi, ft = line.strip().split('\\t')\n",
" return Ride(number(mi), number(ft), hours(time), date, title)\n",
" return Ride(number(mi), number(ft), hours(*time.split(':')[::-1]), date, title)\n",
"\n",
"def number(string) -> float: return float(re.sub(r'[^0-9.]','', string))\n",
"def number(string) -> float: return float(re.sub(r'[^0-9. ]', '', string))\n",
"\n",
"def hours(time: str) -> float: \n",
" \"\"\"Convert '1:30:00' to 1.5\"\"\"\n",
" hour, min, sec = map(int, time.split(':'))\n",
" return hour + min / 60 + sec / 3600\n",
"def hours(sec, min, hour=0) -> float: return int(sec)/3600 + int(min)/60 + int(hour)\n",
"\n",
"rides = map(parse_ride, open('bikerides25.tsv'))"
"rides = [parse_ride(line) for line in open('bikerides25.tsv') \n",
" if 'MTB' not in line and '\t0 ft' not in line]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A few of the rides were on stationary bikes and thus have 0 feet climbed; let's filter them out. A few others were mountain bike rides where I spent a lot of time off the bike pushing it uphill; I'll filter out rides < 8 mph:"
"I'll want to plot the data to visualize it, so I'll collect four interesting vectors of numbers: length of ride in miles, speed in miles per hour, grade in feet climbed per mile, and grade in percent:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"rides = [r for r in rides if r.feet > 0 and r.miles / r.hours > 8]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Collect three vectors of numbers: miles per hour, feet climbed per mile, and miles per ride. Plot feet per mile versis miles per hour:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAD8CAYAAABn919SAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJztnX+QFOeZ37/PDiM0K6e06LTnEiNxEMUHZYTFmi1Ld5tzBOcI2bKkPTgbU0rFjl1FLpUfJ0pZZxWpDmT7is1hn5TUJU7wSZEdqbi1fniNTBLkGKVURRnZi3cx4gwn6yQBI9vgE4NjdiSG3Sd/zPRuT0+/3W/3vP1znk8VxW5P7/TbvbPffvp5v+/zEDNDEARByD49SQ9AEARBMIMIuiAIQk4QQRcEQcgJIuiCIAg5QQRdEAQhJ4igC4Ig5ARfQSeix4noLBG9Yts2TkTTzX9vENF0tMMUBEEQ/CA/HzoRfRjArwF8g5lvcnn9KwAuMPMXohmiIAiCoMMivx2Y+SUiWu72GhERgE8C2GB2WIIgCEJQfAXdh98D8AtmflVn52uvvZaXL1/e4SEFQRC6iyNHjvySmfv99utU0LcC2Ou1AxFtA7ANAJYtW4bJyckODykIgtBdENGbOvuFdrkQ0SIAmwCMe+3HzHuYeZCZB/v7fW8wgiAIQkg6sS1+BMAJZj5jajCCIAhCeHRsi3sBfB/ASiI6Q0Sfa770KfikWwRBEIT40HG5bFVs/4zx0QiCIAihkZWigiAIOUEEXRAEISd0alsUUszEVAW7D5zEW9UalvaVMLJxJYYHykkPSxCEiBBBzykTUxU88Nwx1OqzAIBKtYYHnjsGACLqgpBTJOWSU3YfODkv5ha1+ix2HziZ0IgEQYgaEfSc8la1Fmi7IAjZRwQ9pyztKwXaLghC9hFBzykjG1eiVCy0bCsVCxjZuDKhEQmCEDUyKZpTrIlPcbkIQvcggp5jhgfKIuCC0EVIykUQBCEniKALgiDkBBF0QRCEnCCCLgiCkBNE0AVBEHKCuFwSRgpoCYJgChH0BJECWoIgmEQEPUG8CmhlXdDlyUMQ4kcEPUHyWkBLnjwEIRl0mkQ/TkRniegVx/Z/TUQniOg4Ef1ZdEPML3ktoCWlewUhGXRcLk8AuMO+gYjWA7gHwM3MvBrAl80PLf/ktYBWXp88BCHt+Ao6M78E4G3H5n8BYIyZ323uczaCseWe4YEydm1ag3JfCQSg3FfCrk1rMp+WyOuThyCknbA59N8G8HtE9KcA3gHwb5n5h247EtE2ANsAYNmyZSEPl1/yVEDLmgitVGsgAGx7LQ9PHoKQdsIuLFoE4BoAtwIYAfBNIiK3HZl5DzMPMvNgf39/yMMJaceaCK000yoMwPpA5OXJQxDSTtgI/QyA55iZAfyAiOYAXAvgnLGRCZnCbSKU0RDzQ6MbkhmUIHQZYQV9AsB6AC8S0W8DuALAL42NKsdk0Z+tM2aZCBWE5PEVdCLaC+A2ANcS0RkAOwA8DuDxppXxEoBPN6N1wYMs+rN1x7y0rzSfbrEjE6GCEB86LpetzHwdMxeZ+XpmfoyZLzHzP2Hmm5j5g8x8MI7BZp0s+rN1x5xXC6YgZAlZKRojWUxL6I5ZepgKQvKIoMdIGtISQXP4QcacJwumIGQREfQYGdm4siUfDQRPS9i93j0EzDVnLvpKRey8e7WnoIbJ4ZsYsyAI8SANLmKk05WhTq/3nG0aulqrY+Tpo5iYqih/PkwOP6+rWQUhj0iEHjOdpCXcBNlOfY49S++GzeFLKkUQsoEIegyY8p7rTJ567RN1Dj+LHntByBOScokYe5qEsZC39kqNqNARXq99VNbC9av6MTR2ECtG92No7GCosZk8T0EQwiGCHjEmvedugmyn2EPzk5UTU5U2kXbLh29eV8azRyodC3EWPfaCkDck5RIxJr3ndq+3l8vFz81iT4MMjR000gYvix57QcgbIugRYzpvrTNBGaRXqSkhToPHXhC6HUm5REyUeWsVQUTaVDMKWfovCMkjgh4xUeatVQQRaVNCLH51QUgeirNI4uDgIE9OTsZ2vLQyNHbQNT1hqna4M4cONERaJbBiNxSEdENER5h50G8/yaEnQJi8dRDRDVooSxYOCUI+EEFPgKATiGFqsNhF2roZ3Dc+jQIRZplR7ith/ap+vHjinETmDuSJRcgqkkNPgJGNK1EstLZgLRZImbfuxOPtrP8y20yxVao1PHn4lCwEciALpIQsI4KeFM6pC4+pjE6shX71X+zU6rO4b3zauOsmS8gCKSHLiKAnwO4DJ1Gfa1Vwq7CWG51YC8Ms7OnmqFQWSAlZxlfQiehxIjrb7B9qbdtJRBUimm7++1i0w8wXKnFwy6sDnVkLwy7s6dao1JQvXxCSQCdCfwLAHS7bH2Hmtc1//9PssPKNShwIcI2KO/F4+9V/8aJSrXVd+kUWSAlZRsuHTkTLAXyHmW9qfr8TwK+Z+ctBDiY+9AYTUxVsH592TZsXiDDHbNRdYe9y5OZyUT0ZWHh52POIuFyEtKHrQ+9E0D8D4FcAJgHcz8znFT+7DcA2AFi2bNm6N998U+sE8s7y0f2++8QlpG4LkZyYWvQkCEJwol5Y9FUAX0TDm/FFAF8B8Fm3HZl5D4A9QCNCD3m8edIUPXUylrLCi27Hnsc2ec5u4961ac18FO+GTAoKQvoJ5XJh5l8w8ywzzwH4GoAPmR2WO2nyCHc6Ft3ctvW+ps5ZNW4AODS6AWWZFBSEzBJK0InoOtu3fwDgFdW+JkmTR7jTsTgnOgtErvsViIyes9+4ZVJQELKLb8qFiPYCuA3AtUR0BsAOALcR0Vo0Ui5vAPjnEY5xnjR5hE2Mxbk8362gliqvHfac/cYdtA6MIAjpwVfQmXmry+bHIhiLL2lqohBF4wqgXUhVee2wx9EZd5hiXWma2xCEbiVTxblGNq50jWKTSAfojCWoyKmE1OQ5j2xciZFnjqI+uzA/7VVHRocwxcMEQTBPpgQ9TekAv7G4idzIM0exc99xXKjVtcceyTkHqCOjc1MK0vJOEITokAYXEaFqYmHH7jOPKmXhfN+L715GtVZv28/NZ67yp9sbUgPAitH9rvcEAvD62J0dn4MgdDvS4CJhdCYtW9wltjSIFc0DnaUsHpo4hqcOn5oXW68bjNt4VZUaq7V6S0olTXMbgtDNSLXFiNAVs7eqNTz8/PGWnDYA1GcZDz9/PPTxJ6YqLWLuh9t4vW5KYnUUhPQhEXpEuE2auqGKbgHg/Ex7akSX3QdOaou5Jb7O9Exfb9FzDGJ1FIR0IYJuGLso9vUWsXhRDy7U6ujrLeLX71xuqYNuCel949Ohj+EmnhNTFd/8vQUB2Lyu8bPOSVw/OrU6CoJglq4T9Cj90s5JxPMzdZSKBTyyZS2GB8p4aOIY9r58GrPMKBBh87qGCO7cd9x1orKvVPQ9htMiaL2uCwN48vCp+XEFYf2qfq39xKMuCPHQVS4XN9dGsUC46opFgayEKrycLUsUEfquTWsAACNPH215rdhD2P2Jm9vGojqG5VLRcdeYwu6MUYm2agVsN5XjFYRO6WqXi0pc3Fwb9Vmej447WRDjl+Zwy0VbE4uWKOpEsX5L970mMvtKRdcngbBYx/J6atDxqEsELwhmyJ2ge4lLECthEEEJmuawY59Y1Dmmn0VQ9Xq5KZQ6E7W6WMf0Em2/G5CsMhUEc+TOtuglLrpWwkq1Fqg8rcqvrUNQr7afRdDrdXuFRxNYLeq8aqj79ehMUwVNQcg6uRN0r4gwSH/NIDXHw1Y+DOPVdusvunldI520YnQ/dh84ic3rysr+o8MDZRwa3YBHt6xFsce9ZG8QKtUaVO9ipU+8bkBpqqApCFkndykXr5SEJWr3f/Oor6MjSOrFy0tux28CVjeX7FV2t1Kt4dkjFd9Jx+GBMh5+/nhHXncLRsP+aL+i9qcCQD0/IKtMBcEcuRN0nSqIuvY83SjRz0tOWIhWgQVxs9IKbm4Q3VyyKmVx/zePYvv4NJbamkE7BbVqQMwtGI2nATfR9pofSFMFTUHIOrkTdK+IMOjkpW6U6BXtOq19nbhB3FDddKybVqVaw5OHT81vtx9T98lCh7BNpGWVqSCYI3eC7pW2CDp5+fbFdzExVfEUF+t452fqyrSDRSduEBVhRNk6pinXS6cRdaerTMX2KAgNciXofmmLoBNttfocRp5eqHroFI71q/rx7JHK/PHsueSyi7B4iXbYXHJYUX6rWpsfm9vTRalYwJXFHt8ce4Eo0UVCYnsUhAV8XS5E9DgRnSWitkbQRHQ/ETERXRvN8IKhioDvG5/G0NhBXO2ylN6P+hxj94GT88JRqdbAWEhlOI9nifmh0Q1tguJl4QtbsVC32bTbMa2f33HXaizpXbg2faUidm1agx13rfb9gMwxJyqcYnsUhAV0IvQnAPwFgG/YNxLRDQBuB3DK5WcSwSsCr1RrKIS06VkTmLpRsOVjd6YBVNF0pVrDfePTuOqKAvpKxcBlCPyaTbth1WGZmKq0taS7eOny/NdzPsdO2o0itkdBWECnSfRLRLTc5aVHAHwewLcNj0mJX67UL588Oxeubs3SpntDF6L2yoUPPHcMuzatwa5Na5SNny9emkWxMDdfzCsMzknGHiJXV8+LJ84BAB781jFlLfbeK7w/Hmlwo4jtURAWCLWwiIjuAVBh5qOGx6PELeXhXPwTZOFQENav6g8kEMzwdKwcGt2gXK1Zn+WO0gXOm57KovlW8yni4iX3SP78TN3zJpZ07txCmmsIwgKBJ0WJqBfAv0cj3aKz/zYA2wBg2bJlQQ83j46tzx6dmqw4+NThU/jdG6/B2xcvdeQIsQukl1iGTRe4TRCqWNpXws593h2RVNEvAfjKJ1srQSblNBHboyAsEMblciOAFQCOUmMC7noAPyKiDzHzz507M/MeAHuARvncsAPLine truncated
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
@@ -84,9 +66,15 @@
}
],
"source": [
"mph = [r.miles / r.hours for r in rides]\n",
"fpm = [r.feet / r.miles for r in rides]\n",
"mls = [r.miles for r in rides]\n",
"def vectors3(rides) -> tuple:\n",
" \"Return vectors of (miles, miles/hour, feet climbed per hour)\"\n",
" return ([r.miles for r in rides],\n",
" [r.miles / r.hours for r in rides],\n",
" [r.feet / r.miles for r in rides])\n",
"\n",
"def percent(r: Ride) -> float: return r.feet / r.miles * (100/5280) \n",
"\n",
"mls, mph, fpm = vectors3(rides)\n",
"\n",
"plt.scatter(fpm, mph);"
]
@@ -95,7 +83,32 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"As expected, there is a lot of variance, but overall speeds get slower as the grade gets steeper. Just eyeballing the scatter plot, it looks like a curve would be a better fit than a straight line, so I'll fit a quadratic (degree two) polynomial to the data, and make the plot prettier:"
"# Making it Prettier\n",
"\n",
"As expected, there is a lot of variance, but overall speeds get slower as the grade gets steeper. Just eyeballing the scatter plot, it looks like a curve would be a better fit than a straight line, so I'll fit a quadratic (degree two) polynomial to the data (for no good theoretical reason; just because that's the simplest nonlinear function I could think of). I'll also make the plot prettier and bigger:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def show(X, Y, xlabel='Grade (feet/mile)', ylabel='Speed (mph)', degree=2): \n",
" \"Plot X versus Y and a best fit curve to it, with some bells and whistles.\"\n",
" plt.rcParams[\"figure.figsize\"] = (12, 10)\n",
" plt.style.use('fivethirtyeight')\n",
" plt.ylabel(ylabel); plt.xlabel(xlabel)\n",
" plt.minorticks_on(); plt.grid(True, which='major'); plt.grid(True, which='minor', alpha=0.4)\n",
" plt.scatter(X, Y) \n",
" X1 = sorted(set(X))\n",
" F = poly_fit(X, Y, degree)\n",
" plt.plot(X1, [F(x) for x in X1], 'k:')\n",
" \n",
"def poly_fit(X, Y, degree) -> callable:\n",
" \"\"\"The polynomial function that best fits the X,Y vectors.\"\"\"\n",
" coeffs = np.polyfit(X, Y, degree)[::-1]\n",
" return lambda x: sum(c * x ** i for i, c in enumerate(coeffs))"
]
},
{
@@ -105,7 +118,7 @@
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAykAAAKACAYAAACYDjf4AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAIABJREFUeJzs3Xt4E/edL/63bMm2bGT5grkaDARzS0yJE0rLLSEXSBrS0GbThpLTpttyTjabh+6ekm3SUHoO64a0P7bbH8k+SQ+9hGzS7iltSggJoc0FEggJBkMhOBATGxkT27ItLMuyZI8lnT+MhGTN6DoajUbv1/PwJMjSfL4z37H4fuZ70/X29vpARERERESkEjnpLgAREREREVEwJilERERERKQqTFKIiIiIiEhVmKQQEREREZGqMEkhIiIiIiJVYZJCRERERESqwiSFiIiIiIhUJa1JyuHDh3H//fdj7ty5KCkpwUsvvRTy85KSEtE/GzduTFOJiYiIiIgo1fTpDO50OjFv3jysXbsWDz30UNjPz507F/L3EydO4P7778eaNWuUKiIRERERESksrUnKypUrsXLlSgDAww8/HPbz8ePHh/z99ddfx8yZM7F06VJFykdERERERMrLmDkp/f39ePnll/Gtb30r3UUhIiIiIqIUSmtPSjz++Mc/YnBwEGvXro363qamJgVKREREREREiaiuro7484xJUnbu3Im77roLY8eOjfreaCcdj6amJlmPJ8Vut8NsNjNOAlhH6o/FOlJ/LK3VkZKxWEfqj6W1OgK0d+1YR4wzWkYM9zp16hROnDjBoV5ERERERFkgI5KUnTt3YurUqbj55pvTXRQiIiIiIkqxtA736u/vR3NzMwDA6/Wira0Np06dQmlpKaZMmQIAGBgYwK5du7BhwwbodLp0FpeIiIiIiBSQ1p6UEydOYPny5Vi+fDlcLhe2bt2K5cuX48knnwy85+WXX4bT6cS6devSWFIiIiIiIlJKWntSli1bht7e3ojveeCBB/DAAw8oVCIiIiIiIkq3jJiTQkRERERE2YNJChERERERqQqTFCIiIiIiUhUmKUREREREpCpMUoiIiIiISFWYpBARERERkaowSSEiIiIiIlVJ6z4pqWK321V9PDEulyvlMbQYx491pP5YrCP1x9JSHSkZi3Wk/lha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 truncated
"image/png": "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 truncated
"text/plain": [
"<Figure size 864x720 with 1 Axes>"
]
@@ -115,33 +128,23 @@
}
],
"source": [
"def show(X, Y, xlabel='Grade (feet/mile)', ylabel='Speed (mph)'): \n",
" plt.rcParams[\"figure.figsize\"] = (12, 10)\n",
" plt.style.use('fivethirtyeight')\n",
" plt.ylabel(ylabel); plt.xlabel(xlabel)\n",
" plt.minorticks_on(); plt.grid(True, which='major'); plt.grid(True, which='minor', alpha=0.4)\n",
" plt.scatter(X, Y) \n",
" X1 = sorted(set(X))\n",
" F = quadratic_fit(X, Y)\n",
" plt.plot(X1, [F(x) for x in X1], 'k-')\n",
" \n",
"def quadratic_fit(X, Y):\n",
" \"\"\"The quadratic function that best fits the X,Y vectors.\"\"\"\n",
" a, b, c = np.polyfit(X, Y, 2)\n",
" return lambda x: a * x ** 2 + b * x + c\n",
"\n",
"show(fpm, mph) "
"show(fpm, mph)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, I average a little under 14 mph when the overall route is fairly flat, with a lot of variability from 12 to 16 mph, depending more on my level of effort than on the grade of the road. But from around 50 ft/mile grade speed falls off quickly: down to 12mph at 80 ft/mile; 11 mph at 100 ft/mile; and under 9 mph at 130 ft/mile. Note that even 130 ft/mile is only 2.5% grade, but if you figure a typical route is 1/3 up, 1/3 down, and 1/3 flat, then that's 7.5% grade on the up part."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So, I average a little under 14 mph when the overall route is fairly flat, with a lot of variability from 12 to 16 mph, depending more on my level of effort than on the grade of the road. But from around 50 ft/mile grade speed falls off quickly: down to 12mph at 80 ft/mile; under 11 mph at 100 ft/mile; and under 9 mph at 130 ft/mile, Note that 130 ft/mile is only 2.5% grade, but if you figure a typical route is 1/3 up, 1/3 down, and 1/3 flatish, then that's 7.5% grade on the up part.\n",
"\n",
"# Estimating Duration\n",
"\n",
"For a route with a given distance and elevation, how long will it take to ride it?"
"This data can help me predict how long will it take to ride a route with a given distance and elevation. For example, to get to Pescadero from La Honda, I could take the flatter [coast route](https://www.google.com/maps/dir/La+Honda,+California/Pescadero,+California/@37.2905834,-122.3896683,12z/data=!4m19!4m18!1m10!1m1!1s0x808faed4dc6265bd:0x51a109d3306a7219!2m2!1d-122.274227!2d37.3190255!3m4!1m2!1d-122.4039496!2d37.3116594!3s0x808f062b7d7585e7:0x942480c22f110b74!1m5!1m1!1s0x808f00b4b613c4c1:0x43c609077878b77!2m2!1d-122.3830152!2d37.2551636!3e1) (15.7 miles, 344 ft climb), or the shorter [creek route](https://www.google.com/maps/dir/La+Honda,+California/Pescadero,+California/@37.2905834,-122.3896683,12z/data=!4m19!4m18!1m10!1m1!1s0x808faed4dc6265bd:0x51a109d3306a7219!2m2!1d-122.274227!2d37.3190255!3m4!1m2!1d-122.3658887!2d37.2538867!3s0x808f00acf265bd43:0xb7e2a0c9ee355c3a!1m5!1m1!1s0x808f00b4b613c4c1:0x43c609077878b77!2m2!1d-122.3830152!2d37.2551636!3e1) (13.5 miles, 735 ft climb); which is faster?"
]
},
{
@@ -150,18 +153,11 @@
"metadata": {},
"outputs": [],
"source": [
"def duration(dist, climb, F=quadratic_fit(fpm, mph)):\n",
" \"Given a distance in miles and total climb in feet, return estimated time in minutes.\"\n",
"def duration(dist, climb, F=poly_fit(fpm, mph, 2)) -> float:\n",
" \"Given a distance in miles and total climb in feet, estimate time in minutes.\"\n",
" return 60 * dist / F(climb / dist)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For example, to get to Pescadero from La Honda, I could take the flatter [coast route](https://www.google.com/maps/dir/La+Honda,+California/Pescadero,+California/@37.2905834,-122.3896683,12z/data=!4m19!4m18!1m10!1m1!1s0x808faed4dc6265bd:0x51a109d3306a7219!2m2!1d-122.274227!2d37.3190255!3m4!1m2!1d-122.4039496!2d37.3116594!3s0x808f062b7d7585e7:0x942480c22f110b74!1m5!1m1!1s0x808f00b4b613c4c1:0x43c609077878b77!2m2!1d-122.3830152!2d37.2551636!3e1) (15.7 miles, 344 ft climb), or the shorter [creek route](https://www.google.com/maps/dir/La+Honda,+California/Pescadero,+California/@37.2905834,-122.3896683,12z/data=!4m19!4m18!1m10!1m1!1s0x808faed4dc6265bd:0x51a109d3306a7219!2m2!1d-122.274227!2d37.3190255!3m4!1m2!1d-122.3658887!2d37.2538867!3s0x808f00acf265bd43:0xb7e2a0c9ee355c3a!1m5!1m1!1s0x808f00b4b613c4c1:0x43c609077878b77!2m2!1d-122.3830152!2d37.2551636!3e1) (13.5 miles, 735 ft climb); which is faster?"
]
},
{
"cell_type": "code",
"execution_count": 6,
@@ -170,7 +166,7 @@
{
"data": {
"text/plain": [
"(69.15756109673171, 62.53280536304684)"
"(69.06954183148981, 62.45380233453541)"
]
},
"execution_count": 6,
@@ -186,66 +182,42 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"This suggests the shorter creek route would be about 7 minutes faster. Good to know, but other factors (like the scenery) are probably more important in making the choice.\n",
"\n",
"# Eddington Number\n",
"\n",
"The physicist Sir Arthur Eddington was a pre-Strava bicyclist who favored this metric:\n",
"\n",
"> *Your [Eddington Number](https://www.triathlete.com/2011/04/training/measuring-bike-miles-eddington-number_301789) is the largest integer**&nbsp;E** for which you have bicycled**&nbsp;E** or more miles on**&nbsp;E** different days.*\n",
"\n",
"Let's calculate mine, and see how many rides I need to take to improve it. For various number of miles, I'll list the number of rides of at least that long that I've taken, and the *gap*&mdash;the number of additional rides I would need to reach that Eddington number."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Mi Rides Gap\n",
"-- ----- ---\n",
"52 53 -1\n",
"53 51 2\n",
"54 48 6\n",
"55 46 9\n",
"56 45 11\n",
"57 42 15\n",
"58 39 19\n",
"59 34 25\n",
"60 33 27\n",
"61 27 34\n",
"62 25 37\n",
"63 23 40\n",
"64 21 43\n",
"65 20 45\n"
]
}
],
"source": [
"def eddington(distances, unit):\n",
" \"\"\"Print information on the number of rides and the Eddington gap.\"\"\"\n",
" print(f'{unit} Rides Gap')\n",
" print(f'-- ----- ---')\n",
" for E in range(1, 1000):\n",
" num_rides = sum(d >= E for d in distances)\n",
" gap = E - num_rides\n",
" if -1 <= gap <= 45:\n",
" print(f'{E:2} {num_rides:2} {gap:2}')\n",
"\n",
"eddington(mls, 'Mi')"
"This suggests the shorter creek route would be about 6 or 7 minutes faster. Good to know, but other factors (like the scenery) are probably more important in making the choice."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So my **Eddington Number is 52**: I've done 53 rides of 52 miles or more, but not 53 rides of 53 miles. \n",
"# Segments\n",
"\n",
"We can also calculate the metric Eddington number:"
"The data I have so far helps me estimate the duration for a long ride over varying up-and-down terrain. But what if I just want to know how long it will take to climb the next hill? To answer that I'll go back to Strava and retrieve data from individual segments, some only a fraction of a mile long, some several miles long, but most with a relatively constant grade. I picked some representative segments, wrote down (in [`bikesegments.csv`](bikesegments.csv)) the segment length in miles and climb in feet, along with several of my times on the segment. (I picked my first, fifth, and tenth fastest times when available, or closest to that if I've done the segment less than 10 times.)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"def parse_segments(lines):\n",
" \"\"\"Parse a string of segments into Rides. Each line contains:\n",
" 'title, miles, feet, time,*'.\"\"\"\n",
" for segment in lines:\n",
" title, mi, ft, *times = segment.split(',')\n",
" for time in times:\n",
" yield Ride(float(mi), int(ft), hours(*time.split(':')[::-1]), '?', title)\n",
" \n",
"segments = list(parse_segments(open('bikesegments.csv')))\n",
"\n",
"mls2, mph2, fpm2 = vectors3(segments) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now I plot this data, this time using a third-degree polynomial, just because it seems to fit better, and listing grade in percent rather than feet per mile:"
]
},
{
@@ -254,55 +226,221 @@
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Km Rides Gap\n",
"-- ----- ---\n",
"75 75 0\n",
"76 74 2\n",
"77 73 4\n",
"78 71 7\n",
"79 70 9\n",
"80 69 11\n",
"81 66 15\n",
"82 58 24\n",
"83 57 26\n",
"84 52 32\n",
"85 51 34\n",
"86 50 36\n",
"87 48 39\n",
"88 47 41\n",
"89 46 43\n",
"90 45 45\n"
]
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 864x720 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"eddington([m * 1.60934 for m in mls], 'Km')"
"pct2 = [f * 100 / 5280 for f in fpm2]\n",
"\n",
"show(pct2, mph2, xlabel='Grade (percent)', degree=3) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"My **metric Eddington Number is 75**, and I only need 11 rides of 80 km (50 miles) to get to 80.\n",
"So I can cruise at 17 mph on flat roads (sometimes only 12.5 mph and occassionally up to 21 mph); I'm down around 6 mph at 6% grade, and down around 5 mph on 8% grades.\n",
"\n",
"# H-Index\n",
"# VAM\n",
"\n",
"Inspired by the [h-index](https://en.wikipedia.org/wiki/H-index) for scientific publications (and indirectly by Eddington's h-index-like metric), I invented a new h-index, or hill-index:\n",
"\n",
"> *Your **h-index** is the largest integer **h** for which you can persistently and repeatedly climb an **h** percent grade at **h** miles per hour.*\n",
"\n",
"My h-index is 6, because I can routinely climb a 6% grade at 6 miles per hour or more, but I only very rarely climb a 7% grade at 7 mph. What's yours?"
" [VAM](https://en.wikipedia.org/wiki/VAM_(bicycling)) stands for *velocità ascensionale media* in Italian, but since I don't have Campagnolo gear, I'll call it \"mean ascent velocity\": the speed in vertical feet climbed per hour (regardless of horizontal distance travelled). Legend has it that at grades between about 6% to 12%, most of your power is going into lifting against gravity, so your VAM should be about constant no matter what the grade in that range. (I guess that below that grade, power is spent on wind and rolling resistance, and above it, power goes largely to cursing *sotto voce*, as they say in Italian.) Here's a plot of my VAM at various grades:"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"data": {
"image/png": "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nFyKJV0DoTBjj44j5UGsuHz/ihvX3vLLQoeIiIjIAcTIPZA+IAhpp1W4VaFFOLuuETWJhQ4RERGRg4iRe2BDr0BbT4PIIbAZAREREREROR0WOkRERERE5HRY6BARERERkdNhoUNERERERE6HhQ4RERERETkdFjpEREREROR0WOgQEREREZHTYaFDREREREROh4UOERERERE5HRY6RERERETkdFjoEBERERGR02GhQ0REREREToeFDhEREREROR13W0/AXimVSruKU59arbZ4TEeMCzC/YsYFmF8x4wLMr5hxAeZXzLjMLd+7jhoXYH7FjAtYP78KhcLkYyx0TGgqaeYqLCy0SBwhjMv8ih2X+RU3LvMrblzmV7y4zK24cZlfceMyv+LGtbf8cukaERERERE5HRY6RERERETkdFjoEBERERGR02GhQ0REREREToeFDhEREREROR0WOkRERERE5HRY6BARERERkdNhoUNERERERE6HhQ4RERERETkdFjpEREREROR0WOgQEREREZHTYaFDREREREROh4UOERERERE5HRY6RERERETkdFjoEBERERGR03G39QTslVKptKs49anVaovHdMS4APMrZlyA+RUzLsD8ihkXYH7FjMvc8r3rqHEB5lfMuID186tQKEw+xkLHhKaSZq7CwkKLxBHCuMyv2HGZX3HjMr/ixmV+xYvL3Iobl/kVNy7zK25ce8svl64REREREZHTYaFDREREREROh4UOERERERE5HRY6RERERETkdFjoEBERERGR02GhQ0REREREToeFDhEREREROR0WOkRERERE5HRY6BARERERkdNhoUNERERERE6HhQ4RERERETkdFjpEREREROR0WOgQEREREZHTYaFDREREREROh4UOERERERE5HXdbT8BeKZVKu4pTn1qttnhMR4wLML9ixgWYXzHjAsyvmHEB5lfMuMwt37uOGhdgfsWMC1g/vwqFwuRjLHRMaCpp5iosLLRIHCGMy/yKHZf5FTcu8ytuXOZXvLjMrbhxm5PfXJUGaadVyK/QIsJHigUpcsTIPUyOd6Q8iBWX719x49pbflnoEBERETmYXJUGwzOLcVWlNZz7oaga6QOCmix2iFwJ9+gQEREROZi00yqjIgcArqq0SDutstGMiOwPCx0iIiIiB5NfoRU8f8vEeSJXxEKHiIiIyMFE+EgFz4ebOE/kirhHh4iIrKr+BuogDx2WdPXhngKiZlqQIscPRdVGy9fi5LUNCYioFgsdIiKyGqEN1GdLi7mBmqiZYuQeSB8QhLTTKtyq0CLcjK5rRK6GhQ4REVlNUxuoN/QKtNGsiBxTjNyDPzdETeAeHSIishpuoCYiImthoUNERFbDDdRERGQtLHSIiMhqFqTIESc3Lmq4gZqIiMTAPTpERGQ1DTdQB3rosKRrIDdQExGRxdnsis6GDRvQrVs3REVFISoqCk888QQyMzMNj+v1erzzzjt44IEHEB4ejkGDBuHChQtGMUpLSzFx4kRER0cjOjoaEydORGlpqdGYc+fOYeDAgQgPD8eDDz6I5cuXQ6/XW+U1EhFRY3UbqPemhmBNZ28WOUREJAqbFTqRkZFYvHgxvvvuOxw5cgSPP/44xowZg59++gkAsHr1aqxduxbLly/H4cOHERISghEjRkClUhlivPjiizh79ix27NiBHTt24OzZs/jzn/9sePzu3bsYMWIEQkNDcfjwYSxbtgx//etf8be//c3qr5eIiIiIiKzHZkvXBg0aZHT85ptvYtOmTTh16hSSkpKwbt06vPLKKxg2bBgAYN26dUhISMCOHTswfvx4XLx4EQcPHsSBAwfQpUsXAMD777+P1NRU5OTkICEhAdu3b4darca6desgk8nQoUMH/PLLL/jggw8wbdo0SCQSq79uIiIiIiISn100I9Bqtdi5cyfKy8vRpUsX5ObmoqCgAH379jWMkclk6NatG7KysgAA2dnZaNWqFbp27WoY8/vf/x6+vr5GYx577DHIZDLDmH79+iE/Px+5ublWenVERERERGRtNm1GcO7cOTz55JOorKyEr68vNm/ejKSkJEOhEhISYjQ+JCQE+fn5AIDCwkIEBQUZXZWRSCQIDg5GYWGhYUxkZGSjGHWPxcbGmpxbTk5Oi1+fJeM0VPcaXT0u8ytuXOZX3LjMr7hxmV/x4jK34sZlfsWNy/yKG9fa+U1ISDD5Z2xa6CQkJODo0aO4e/cu9uzZg8mTJ+PLL7+05ZQMmkqaueqW0FmaUqmEQqFw+bjMr7hxmV9x4zK/4sZlfsWLy9yKG5f5FTcu8ytuXHvLr02Xrnl6eiI+Ph6dOnXCokWLkJycjA8++ABhYWEAgKKiIqPxRUVFCA0NBQCEhoaiuLjYqIOaXq/H7du3jcYIxah7jIiIiIiInJNd7NGpo9PpUF1djZiYGISFheHIkSOGxyorK3HixAnDnpwuXbqgrKwM2dnZhjHZ2dkoLy83GnPixAlUVlYaxhw5cgQRERGIiYmx0qsiIiIiIiJrs1mh89Zbb+H48ePIzc3FuXPnsHjxYhw7dgyjRo2CRCLB5MmTsXrLine truncated
"text/plain": [
"<Figure size 864x720 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"vam2 = [r.feet / r.hours for r in segments]\n",
"\n",
"show(pct2, vam2, xlabel='Grade (percent)', ylabel='VAM (vertical feet per hour)', degree=3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sure enough, the best fit cubic curve looks pretty flat between 6% and 12%, but there is a lot of variance. These numbers confirm that I'm an average club climber; good climbers can do over 5,000 feet per hour.\n",
"\n",
"# Eddington Number\n",
"\n",
"The British physicist Sir Arthur Eddington (1882-1944) was a pre-Strava bicyclist who favored this metric:\n",
"\n",
"> *Your [Eddington Number](https://www.triathlete.com/2011/04/training/measuring-bike-miles-eddington-number_301789) is the maximum number**&nbsp;E** such that you have bicycled**&nbsp;E** or more miles on**&nbsp;E** or more days.*\n",
"\n",
"Let's calculate mine, and see how many rides I need to take to improve it. For various number of miles, I'll list the number of rides of at least that long that I've taken, and the *gap*&mdash;the number of additional rides I would need to reach that Eddington number."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Mi Days Gap\n",
"-- ---- ---\n",
"52 54 -2\n",
"53 52 1\n",
"54 49 5\n",
"55 47 8\n",
"56 46 10\n",
"57 43 14\n",
"58 40 18\n",
"59 35 24\n",
"60 34 26\n",
"61 28 33\n",
"62 26 36\n",
"63 24 39\n",
"64 22 42\n",
"65 21 44\n"
]
}
],
"source": [
"def eddington(distances, unit):\n",
" \"\"\"Print information on the number of rides and the Eddington gap.\"\"\"\n",
" print(f'{unit} Days Gap')\n",
" print(f'-- ---- ---')\n",
" for E in range(1, 999):\n",
" days = sum(d >= E for d in distances)\n",
" gap = E - days\n",
" if -2 <= gap <= 45:\n",
" print(f'{E:2} {days:2} {gap:2}')\n",
"\n",
"eddington(mls, 'Mi')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So my **Eddington Number is 52**: I've done 52 miles or more on more than 52 days, but for 53 miles, only 52 days. This happens to be right around [the mean for Strava users](https://swinny.net/Cycling/-4687-Calculate-your-Eddington-Number). To increase 10% to 57 I would need 14 more 57-mile days. (Eddington's Eddington number was **77**.)\n",
"\n",
"If 52 seems too small a number, we can calculate the metric Eddington number (in kilometers):"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Km Days Gap\n",
"-- ---- ---\n",
"75 76 -1\n",
"76 75 1\n",
"77 74 3\n",
"78 72 6\n",
"79 71 8\n",
"80 70 10\n",
"81 67 14\n",
"82 59 23\n",
"83 58 25\n",
"84 53 31\n",
"85 52 33\n",
"86 51 35\n",
"87 49 38\n",
"88 48 40\n",
"89 47 42\n",
"90 46 44\n"
]
}
],
"source": [
"eddington([m * 1.609344 for m in mls], 'Km')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"My **metric Eddington Number is 75**, and to increase 10% to 82 I would need 23 more 82 km (51 mile) days, but to increase 5 more to 80 I would need just 10 such days.\n",
"\n",
"# H-Index\n",
"\n",
"Inspired by the [h-index](https://en.wikipedia.org/wiki/H-index) for scientific publications (and by Eddington's h-index-like number), I invented a new h-index, or hill-index:\n",
"\n",
"> *Your **h-index** is the maximum number**&nbsp;H** for which you can regularly climb an**&nbsp;H** percent grade at **&nbsp;H** miles per hour.*\n",
"\n",
"I think **my h-index is 6**, but let's draw a plot and do a computation to confirm:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<Figure size 864x720 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"show(pct2, mph2, xlabel='Grade (percent)', degree=3) \n",
"plt.plot([6, 7, 8], [6, 7, 8], 'rD');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"My guess is confirmed: the leftmost red diamond indicates 6 mph at 6% grade, and we can see that about half my segments on 6% grades are above 6 mph. The term *regularly* in my definition is imprecise, but I think that's close enough. On the other hand, the next diamond is 7 mph at 7%, and there are only 3 segments that are up-and-to-the-right of that, so I wouldn't count that as *regularly*. And I have never achieved 8 mph at 8%.\n",
"\n",
"The other piece of confirmation is fitting the curve as the function `speed` and seeing that my predicted speed at 6% grade is 6.3 mph:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{6: 6.304162382032494, 7: 5.506903091328892}"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"speed = poly_fit(pct2, mph2, 3)\n",
"\n",
"{pct: speed(pct) for pct in (6, 7)}"
]
}
],
"metadata": {
@@ -321,7 +459,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
"version": "3.7.2"
}
},
"nbformat": 4,
+4 -3
View File
@@ -136,7 +136,7 @@ Ride Sun, 1/25/2015 Canada Rd 2:45:51 39.99 mi 1,772 ft
Ride Sat, 6/21/2014 Sierra to the Sea Day 7 3:36:53 39.77 mi 3,325 ft
Ride Sat, 9/23/2017 Canada / Crestview 3:25:13 39.77 mi 2,444 ft
Ride Fri, 12/27/2013 OLH to Page Mill 3:24:14 39.73 mi 3,365 ft
Ride Sat, 4/30/2016 Ridge to Bridge 5:40:57 39.67 mi 5,377 ft
Ride Sat, 4/30/2016 Ridge to Bridge MTB 5:40:57 39.67 mi 5,377 ft
Ride Fri, 10/30/2015 OLH - West Alpine 3:28:46 39.51 mi 4,505 ft
Ride Sat, 9/5/2015 Ring of Fire 3:31:55 39.18 mi 3,553 ft
Ride Wed, 8/28/2013 Train Track Crash 2:50:55 39.16 mi 928 ft
@@ -188,7 +188,7 @@ Ride Sun, 9/30/2018 Canada 2:48:41 36.12 mi 1,480 ft
Ride Fri, 3/30/2018 Morning Ride 2:38:07 36.11 mi 285 ft
Ride Sun, 11/5/2017 Lunch Ride 3:24:01 35.91 mi 2,231 ft
Ride Sun, 2/8/2015 Commute 2:28:46 35.85 mi 1,142 ft
Ride Tue, 6/26/2018 Return from Chabot Lake with Juliet 3:21:30 35.81 mi 817 ft
Ride Tue, 6/26/2018 Return from Chabot Lake with Juliet MTB 3:21:30 35.81 mi 817 ft
Ride Sat, 3/30/2019 Morning Ride 3:23:55 35.78 mi 2,861 ft
Ride Sun, 11/22/2015 Pigeon Point 3:14:41 35.73 mi 3,230 ft
Ride Mon, 9/19/2016 Sunnyvale 2:37:04 35.68 mi 745 ft
@@ -278,7 +278,7 @@ Ride Thu, 12/28/2017 Morning Ride 2:17:38 30.54 mi 430 ft
Ride Mon, 1/30/2017 Morning Ride 2:19:47 30.49 mi 696 ft
Ride Sun, 8/27/2017 Lunch Ride 2:16:36 30.47 mi 774 ft
Ride Fri, 10/12/2018 Lunch Ride 2:16:25 30.44 mi 348 ft
Ride Mon, 6/25/2018 Chabot Lake Overnight Bike packing with Juliet 3:02:49 30.41 mi 1,250 ft
Ride Mon, 6/25/2018 Chabot Lake Overnight Bike packing with Juliet MTB 3:02:49 30.41 mi 1,250 ft
Ride Sat, 2/28/2015 Palo Alto Cycling 2:40:24 30.37 mi 2,535 ft
Ride Sat, 6/24/2017 Afternoon Ride 2:06:05 30.31 mi 338 ft
Ride Tue, 6/2/2015 06/02/2015 Mountain View, California 2:09:58 30.30 mi 784 ft
@@ -435,3 +435,4 @@ Ride Sun, 1/19/2014 01/19/2014 Palo Alto, CA 1:36:55 25.01 mi 1,201 ft
Ride Mon, 9/5/2016 Afternoon Ride 1:42:56 25.00 mi 902 ft
Ride Sat, 11/8/2014 Atherton - Woodside 1:40:51 25.00 mi 972 ft
Ride Sun, 12/10/2017 Exercise Bike 1:30:00 25.00 mi 0 ft
Ride Sun, 6/2/2019 The Sequoia 6:40:43 77.51 mi 6,467 ft
1 Ride Thu, 6/14/2012 Coyote Creek Century with Juliet 8:08:15 100.07 mi 1,513 ft
136 Ride Sat, 6/21/2014 Sierra to the Sea Day 7 3:36:53 39.77 mi 3,325 ft
137 Ride Sat, 9/23/2017 Canada / Crestview 3:25:13 39.77 mi 2,444 ft
138 Ride Fri, 12/27/2013 OLH to Page Mill 3:24:14 39.73 mi 3,365 ft
139 Ride Sat, 4/30/2016 Ridge to Bridge Ridge to Bridge MTB 5:40:57 39.67 mi 5,377 ft
140 Ride Fri, 10/30/2015 OLH - West Alpine 3:28:46 39.51 mi 4,505 ft
141 Ride Sat, 9/5/2015 Ring of Fire 3:31:55 39.18 mi 3,553 ft
142 Ride Wed, 8/28/2013 Train Track Crash 2:50:55 39.16 mi 928 ft
188 Ride Fri, 3/30/2018 Morning Ride 2:38:07 36.11 mi 285 ft
189 Ride Sun, 11/5/2017 Lunch Ride 3:24:01 35.91 mi 2,231 ft
190 Ride Sun, 2/8/2015 Commute 2:28:46 35.85 mi 1,142 ft
191 Ride Tue, 6/26/2018 Return from Chabot Lake with Juliet Return from Chabot Lake with Juliet MTB 3:21:30 35.81 mi 817 ft
192 Ride Sat, 3/30/2019 Morning Ride 3:23:55 35.78 mi 2,861 ft
193 Ride Sun, 11/22/2015 Pigeon Point 3:14:41 35.73 mi 3,230 ft
194 Ride Mon, 9/19/2016 Sunnyvale 2:37:04 35.68 mi 745 ft
278 Ride Mon, 1/30/2017 Morning Ride 2:19:47 30.49 mi 696 ft
279 Ride Sun, 8/27/2017 Lunch Ride 2:16:36 30.47 mi 774 ft
280 Ride Fri, 10/12/2018 Lunch Ride 2:16:25 30.44 mi 348 ft
281 Ride Mon, 6/25/2018 Chabot Lake Overnight Bike packing with Juliet Chabot Lake Overnight Bike packing with Juliet MTB 3:02:49 30.41 mi 1,250 ft
282 Ride Sat, 2/28/2015 Palo Alto Cycling 2:40:24 30.37 mi 2,535 ft
283 Ride Sat, 6/24/2017 Afternoon Ride 2:06:05 30.31 mi 338 ft
284 Ride Tue, 6/2/2015 06/02/2015 Mountain View, California 2:09:58 30.30 mi 784 ft
435 Ride Mon, 9/5/2016 Afternoon Ride 1:42:56 25.00 mi 902 ft
436 Ride Sat, 11/8/2014 Atherton - Woodside 1:40:51 25.00 mi 972 ft
437 Ride Sun, 12/10/2017 Exercise Bike 1:30:00 25.00 mi 0 ft
438 Ride Sun, 6/2/2019 The Sequoia 6:40:43 77.51 mi 6,467 ft
+64
View File
@@ -0,0 +1,64 @@
Alma Mountain Charlie, 3.12, 875, 31:49
Alpine Westridge, 0.76, 99, 3:26, 3:29, 3:43
Alpine last kicker, 0.39, 114, 3:11, 3:36, 5:19
Arastradero, 1.19, 193, 6:41, 7:49, 7:55
Bring it On Home, 10.81, 237, 37:19
Cabrillo Hmy S, 0.46, 153, 4:31
Canada South Interval, 1.42, 54, 4:50, 5:08, 5:20
Canada to College, 1.37, 119, 5:55, 6:23, 6:35
Canon, 0.90, 295, 11:05, 11:56
Canon to No Cycling, 0.75, 198, 5:14, 5:41
El Camino, 0.50, 15, 2:11, 2:19, 2:22
Foothill Arastradero, 1.13, 37, 3:31, 3:44, 3:51
Foothill Homestead, 1.22, 126, 5:31, 6:36, 6:53
Foothill Magdalena, 1.66, 44, 5:51, 6:21, 6:29
Foothill Miramonte, 1.64, 39, 4:55, 5:29, 5:43
Haskins, 1.51, 566, 17:48, 18:43, 18:48
Highway 9, 0.56, 260, 8:33
Highway 9 Mantalvo, 0.45, 35, 1:36, 1:48, 1:53
Huddart, 0.92, 385, 10:15, 11:18, 12:55
Joaquin, 0.33, 253, 6:19, 7:27
Kaboom Portola Rd, 0.67, 102, 3:14, 3:26, 3:33
Kings half way, 2.89, 820, 27:26, 29:45, 32:43
Kings to Skeggs, 1.10, 273, 9:08, 10:39, 10:54
Limantour Spit, 0.47, 303, 5:20
Limantour steepest, 0.20, 159, 5:41
Lobitas Creek, 0.96, 430, 12:15, 12:07
Lower Redwood Gulch, 1.03, 474, 13:00
Mapache, 0.24, 111, 2:52, 2:56
Mt Eden climb, 1.02, 272, 8:32, 9:43, 11:59
Mt Eden to Archery, 0.54, 180, 5:20, 5:39, 6:12
Old La Honda, 2.98, 1255, 28:49, 34:04, 36:45
Old La Honda Mile 1, 0.99, 370, 8:02, 9:36, 9:51
Page Mill to Moody, 0.21, 112, 2:50, 2:55
Page Mill to Ventana, 0.47, 196, 4:54, 5:32, 6:05
Peach Hill, 0.60, 248, 7:30, 7:50
Pescadero Bean Hollow, 2.77, 51, 8:07, 10:48
Pomponio Creek, 0.38, 122, 2:47, 2:56, 3:16
Red Hill KOM, 0.34, 161, 4:15
Redwood Gulch hits, 0.18, 151, 3:36
Redwood Gulch wall, 0.43, 258, 6:39
Sand Gill Sharon-top, 0.85, 136, 4:04, 4:16, 4:24
Sand Hill 280 to horse, 0.49, 95, 2:34, 2:44, 2:51
Sand Hill Alpine to 280, 1.67, 180, 7:02, 7:40, 8:02
Stair Step, 0.32, 175, 5:25
Stanford Ave, 0.63, 85, 3:14, 3:32, 3:49
Stevens Canyon, 2.85, 127, 12:51, 13:46, 18:12
Stevens Country Park, 1.22, 112, 5:43, 5:59, 7:00
Stirrup Wall, 0.17, 125, 3:47, 4:33
Stirrup to Moon, 0.36, 159, 3:41, 6:07
Summit Rd Climb, 0.60, 275, 8:00
Tepa, 0.58, 248, 6:34, 7:14, 8:21
The Boneyard, 1.48, 135, 6:05, 6:36, 7:00
Try not to fall back, 0.71, 410, 12:45
Tunitas Knoll to Star, 1.55, 339, 12:28, 12:56, 13:51
Tunitas flattens, 0.42, 166, 3:16, 3:25, 3:51
Tunitas lower climb, 1.30, 421, 13:34, 16:00, 17:33
Tunitas steep, 1.20, 599, 16:16, 17:48, 20:44
Vickrey Fruitvale, 0.99, 68, 3:41, 3:58, 4:27
West Alpine switchback, 0.78, 322, 8:56, 10:52, 11:56
Westridge, 0.68, 385, 8:28, 9:52, 10:19
Westridge 3min, 0.37, 240, 4:41, 5:35, 6:31
Westridge Hill 1, 0.51, 104, 3:19, 3:58
Westridge Hill 2, 0.51, 166, 4:42, 5:10, 5:21
Woodside Climb, 1.71, 295, 8:05, 9:00, 9:35
1 Alma Mountain Charlie, 3.12, 875, 31:49
2 Alpine Westridge, 0.76, 99, 3:26, 3:29, 3:43
3 Alpine last kicker, 0.39, 114, 3:11, 3:36, 5:19
4 Arastradero, 1.19, 193, 6:41, 7:49, 7:55
5 Bring it On Home, 10.81, 237, 37:19
6 Cabrillo Hmy S, 0.46, 153, 4:31
7 Canada South Interval, 1.42, 54, 4:50, 5:08, 5:20
8 Canada to College, 1.37, 119, 5:55, 6:23, 6:35
9 Canon, 0.90, 295, 11:05, 11:56
10 Canon to No Cycling, 0.75, 198, 5:14, 5:41
11 El Camino, 0.50, 15, 2:11, 2:19, 2:22
12 Foothill Arastradero, 1.13, 37, 3:31, 3:44, 3:51
13 Foothill Homestead, 1.22, 126, 5:31, 6:36, 6:53
14 Foothill Magdalena, 1.66, 44, 5:51, 6:21, 6:29
15 Foothill Miramonte, 1.64, 39, 4:55, 5:29, 5:43
16 Haskins, 1.51, 566, 17:48, 18:43, 18:48
17 Highway 9, 0.56, 260, 8:33
18 Highway 9 Mantalvo, 0.45, 35, 1:36, 1:48, 1:53
19 Huddart, 0.92, 385, 10:15, 11:18, 12:55
20 Joaquin, 0.33, 253, 6:19, 7:27
21 Kaboom Portola Rd, 0.67, 102, 3:14, 3:26, 3:33
22 Kings half way, 2.89, 820, 27:26, 29:45, 32:43
23 Kings to Skeggs, 1.10, 273, 9:08, 10:39, 10:54
24 Limantour Spit, 0.47, 303, 5:20
25 Limantour steepest, 0.20, 159, 5:41
26 Lobitas Creek, 0.96, 430, 12:15, 12:07
27 Lower Redwood Gulch, 1.03, 474, 13:00
28 Mapache, 0.24, 111, 2:52, 2:56
29 Mt Eden climb, 1.02, 272, 8:32, 9:43, 11:59
30 Mt Eden to Archery, 0.54, 180, 5:20, 5:39, 6:12
31 Old La Honda, 2.98, 1255, 28:49, 34:04, 36:45
32 Old La Honda Mile 1, 0.99, 370, 8:02, 9:36, 9:51
33 Page Mill to Moody, 0.21, 112, 2:50, 2:55
34 Page Mill to Ventana, 0.47, 196, 4:54, 5:32, 6:05
35 Peach Hill, 0.60, 248, 7:30, 7:50
36 Pescadero Bean Hollow, 2.77, 51, 8:07, 10:48
37 Pomponio Creek, 0.38, 122, 2:47, 2:56, 3:16
38 Red Hill KOM, 0.34, 161, 4:15
39 Redwood Gulch hits, 0.18, 151, 3:36
40 Redwood Gulch wall, 0.43, 258, 6:39
41 Sand Gill Sharon-top, 0.85, 136, 4:04, 4:16, 4:24
42 Sand Hill 280 to horse, 0.49, 95, 2:34, 2:44, 2:51
43 Sand Hill Alpine to 280, 1.67, 180, 7:02, 7:40, 8:02
44 Stair Step, 0.32, 175, 5:25
45 Stanford Ave, 0.63, 85, 3:14, 3:32, 3:49
46 Stevens Canyon, 2.85, 127, 12:51, 13:46, 18:12
47 Stevens Country Park, 1.22, 112, 5:43, 5:59, 7:00
48 Stirrup Wall, 0.17, 125, 3:47, 4:33
49 Stirrup to Moon, 0.36, 159, 3:41, 6:07
50 Summit Rd Climb, 0.60, 275, 8:00
51 Tepa, 0.58, 248, 6:34, 7:14, 8:21
52 The Boneyard, 1.48, 135, 6:05, 6:36, 7:00
53 Try not to fall back, 0.71, 410, 12:45
54 Tunitas Knoll to Star, 1.55, 339, 12:28, 12:56, 13:51
55 Tunitas flattens, 0.42, 166, 3:16, 3:25, 3:51
56 Tunitas lower climb, 1.30, 421, 13:34, 16:00, 17:33
57 Tunitas steep, 1.20, 599, 16:16, 17:48, 20:44
58 Vickrey Fruitvale, 0.99, 68, 3:41, 3:58, 4:27
59 West Alpine switchback, 0.78, 322, 8:56, 10:52, 11:56
60 Westridge, 0.68, 385, 8:28, 9:52, 10:19
61 Westridge 3min, 0.37, 240, 4:41, 5:35, 6:31
62 Westridge Hill 1, 0.51, 104, 3:19, 3:58
63 Westridge Hill 2, 0.51, 166, 4:42, 5:10, 5:21
64 Woodside Climb, 1.71, 295, 8:05, 9:00, 9:35