Skip to content

Instantly share code, notes, and snippets.

@jhh
Created September 26, 2018 13:26
Show Gist options
  • Save jhh/6e173c50c6c80263d16b45c4a2c9a3e5 to your computer and use it in GitHub Desktop.
Save jhh/6e173c50c6c80263d16b45c4a2c9a3e5 to your computer and use it in GitHub Desktop.
Wheel Test 2018-09-25
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Wheel Test 2018-09-25\n",
"Testing new magic wheels on Jif."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import psycopg2 as pg\n",
"import pandas as pd\n",
"%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"connection = pg.connect(\"dbname=jeff user=jeff\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"date = '2018-09-25'\n",
"\n",
"activity_sql = \"\"\"\n",
"SELECT id, name, timestamp, meta->'direction' AS direction\n",
"FROM tc_activity\n",
"WHERE timestamp::date = date '{}' AND data[3] <> 0\n",
"\"\"\".format(date)\n",
"\n",
"activity_meta = pd.read_sql(activity_sql, index_col='id', con=connection)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"activity_data_sql = \"\"\"\n",
"SELECT id, name, timestamp, measure, value\n",
"FROM tc_activity, unnest(activity_measures, data) AS u(measure, value)\n",
"WHERE timestamp::date = date '{}' AND data[3] <> 0\n",
"\"\"\".format(date)\n",
"\n",
"activity_data = pd.read_sql(activity_data_sql, con=connection)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## TPI Grouped by Direction\n",
"Select and pivot summary data for an activity."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead tr th {\n",
" text-align: left;\n",
" }\n",
"\n",
" .dataframe thead tr:last-of-type th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th></th>\n",
" <th colspan=\"8\" halign=\"left\">actual_distance</th>\n",
" <th colspan=\"8\" halign=\"left\">tpi</th>\n",
" </tr>\n",
" <tr>\n",
" <th></th>\n",
" <th>count</th>\n",
" <th>mean</th>\n",
" <th>std</th>\n",
" <th>min</th>\n",
" <th>25%</th>\n",
" <th>50%</th>\n",
" <th>75%</th>\n",
" <th>max</th>\n",
" <th>count</th>\n",
" <th>mean</th>\n",
" <th>std</th>\n",
" <th>min</th>\n",
" <th>25%</th>\n",
" <th>50%</th>\n",
" <th>75%</th>\n",
" <th>max</th>\n",
" </tr>\n",
" <tr>\n",
" <th>direction</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>-90.0</th>\n",
" <td>10.0</td>\n",
" <td>131.5</td>\n",
" <td>0.5</td>\n",
" <td>130.8</td>\n",
" <td>131.3</td>\n",
" <td>131.4</td>\n",
" <td>131.9</td>\n",
" <td>132.2</td>\n",
" <td>10.0</td>\n",
" <td>1904.5</td>\n",
" <td>8.0</td>\n",
" <td>1889.7</td>\n",
" <td>1899.3</td>\n",
" <td>1904.8</td>\n",
" <td>1909.3</td>\n",
" <td>1918.4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0.0</th>\n",
" <td>10.0</td>\n",
" <td>131.4</td>\n",
" <td>0.6</td>\n",
" <td>130.5</td>\n",
" <td>131.0</td>\n",
" <td>131.5</td>\n",
" <td>131.9</td>\n",
" <td>132.2</td>\n",
" <td>10.0</td>\n",
" <td>1908.5</td>\n",
" <td>8.6</td>\n",
" <td>1893.4</td>\n",
" <td>1902.1</td>\n",
" <td>1909.9</td>\n",
" <td>1914.4</td>\n",
" <td>1920.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>180.0</th>\n",
" <td>10.0</td>\n",
" <td>133.4</td>\n",
" <td>0.5</td>\n",
" <td>132.4</td>\n",
" <td>133.0</td>\n",
" <td>133.4</td>\n",
" <td>133.8</td>\n",
" <td>134.0</td>\n",
" <td>10.0</td>\n",
" <td>1876.2</td>\n",
" <td>8.9</td>\n",
" <td>1863.2</td>\n",
" <td>1870.5</td>\n",
" <td>1876.4</td>\n",
" <td>1880.6</td>\n",
" <td>1893.2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>90.0</th>\n",
" <td>10.0</td>\n",
" <td>131.6</td>\n",
" <td>0.6</td>\n",
" <td>130.8</td>\n",
" <td>131.2</td>\n",
" <td>131.7</td>\n",
" <td>132.1</td>\n",
" <td>132.5</td>\n",
" <td>10.0</td>\n",
" <td>1901.4</td>\n",
" <td>9.5</td>\n",
" <td>1886.5</td>\n",
" <td>1894.3</td>\n",
" <td>1901.8</td>\n",
" <td>1909.2</td>\n",
" <td>1913.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" actual_distance \\\n",
" count mean std min 25% 50% 75% max \n",
"direction \n",
"-90.0 10.0 131.5 0.5 130.8 131.3 131.4 131.9 132.2 \n",
"0.0 10.0 131.4 0.6 130.5 131.0 131.5 131.9 132.2 \n",
"180.0 10.0 133.4 0.5 132.4 133.0 133.4 133.8 134.0 \n",
"90.0 10.0 131.6 0.6 130.8 131.2 131.7 132.1 132.5 \n",
"\n",
" tpi \n",
" count mean std min 25% 50% 75% max \n",
"direction \n",
"-90.0 10.0 1904.5 8.0 1889.7 1899.3 1904.8 1909.3 1918.4 \n",
"0.0 10.0 1908.5 8.6 1893.4 1902.1 1909.9 1914.4 1920.0 \n",
"180.0 10.0 1876.2 8.9 1863.2 1870.5 1876.4 1880.6 1893.2 \n",
"90.0 10.0 1901.4 9.5 1886.5 1894.3 1901.8 1909.2 1913.0 "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pivot = activity_data.pivot(index='id', columns='measure', values='value')\n",
"activity = pd.merge(activity_meta, pivot, on='id')\n",
"activity['tpi'] = activity['actual_ticks'] / activity['actual_distance']\n",
"activity[['direction','actual_distance', 'tpi']].groupby('direction').describe().round(1)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x1134cfb38>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 792x576 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"activity.boxplot(column='tpi', by=['name', 'direction'], rot=15, figsize=(11, 8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## TPI Estimated Error by Direction\n",
"A resonable choice for nominal TPI is either *forward* TPI or TPI *grand mean*. We'll assume the TPI nominal value is the grand mean of all TPI measurements.\n",
"\n",
"\\begin{equation*}\n",
"error_{TPI} = \\frac{TPI_{experimental} - TPI_{nominal}}{TPI_{nominal}} \\times 100\\%\n",
"\\end{equation*}\n",
"\n",
"A positive error is more ticks per inch (conversely fewer inches per tick), therefore the robot travels less distance with postive error. The `100 in.` column below is how far we'd expect the robot to travel if we converted 100 in to ticks using the forward (0.0) TPI as our benchmark."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>tpi</th>\n",
" <th>error</th>\n",
" <th>error (%)</th>\n",
" <th>100 in.</th>\n",
" </tr>\n",
" <tr>\n",
" <th>direction</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>-90.0</th>\n",
" <td>1904.5</td>\n",
" <td>0.004</td>\n",
" <td>0.36%</td>\n",
" <td>100.21</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0.0</th>\n",
" <td>1908.5</td>\n",
" <td>0.006</td>\n",
" <td>0.57%</td>\n",
" <td>100.00</td>\n",
" </tr>\n",
" <tr>\n",
" <th>180.0</th>\n",
" <td>1876.2</td>\n",
" <td>-0.011</td>\n",
" <td>-1.13%</td>\n",
" <td>101.72</td>\n",
" </tr>\n",
" <tr>\n",
" <th>90.0</th>\n",
" <td>1901.4</td>\n",
" <td>0.002</td>\n",
" <td>0.20%</td>\n",
" <td>100.37</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" tpi error error (%) 100 in.\n",
"direction \n",
"-90.0 1904.5 0.004 0.36% 100.21\n",
"0.0 1908.5 0.006 0.57% 100.00\n",
"180.0 1876.2 -0.011 -1.13% 101.72\n",
"90.0 1901.4 0.002 0.20% 100.37"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tpi_grand_mean = activity['tpi'].mean()\n",
"tpi_error = activity[['direction', 'tpi']].groupby('direction').mean()\n",
"tpi_error['error'] = (tpi_error['tpi'] - tpi_grand_mean) / tpi_grand_mean\n",
"tpi_error['error (%)'] = pd.Series([\"{0:.2f}%\".format(val * 100) for val in tpi_error['error']], index = tpi_error.index)\n",
"\n",
"ticks_100_in = tpi_error.loc['0.0','tpi'] * 100 # ticks to travel 100in using 0.0 TPI\n",
"tpi_error['100 in.'] = ticks_100_in / tpi_error['tpi']\n",
"tpi_error = tpi_error.round({'tpi':1, 'error': 3, '100 in.': 2})\n",
"tpi_error"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment