import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%load_ext autoreload
pd.options.display.float_format = '{:,.5f}'.format
pd.options.display.max_columns = 100
plt.style.use('seaborn-darkgrid')
# General Markdown Formatting Functions
from IPython.display import Markdown, display, HTML, JSON
def printmd(string: str, level: int=1):
'''Display Markdown text with a default header value of 1.'''
header_level = '#'*level + ' '
display(Markdown(header_level + string))
%autoreload
import friction_experiment
# Initialize each experiment.
static_big = friction_experiment.FrictionExperiment(type='static', surface='big', trials=9)
static_small = friction_experiment.FrictionExperiment(type='static', surface='small', trials=9)
kinetic_big = friction_experiment.FrictionExperiment(type='kinetic', surface='big', trials=9)
kinetic_small = friction_experiment.FrictionExperiment(type='kinetic', surface='small', trials=9)
Angle of Decline $$\begin{aligned} \bar{r}_{\mathrm{Base}} &= \bar{r}_{\mathrm{Green}} - \bar{r}_{\mathrm{Orange}} \\ \bar{r}_{\mathrm{Ramp}} &= \bar{r}_{\mathrm{Pink}} - \bar{r}_{\mathrm{Orange}}\\ \theta &= \frac{ \bar{r}_{\mathrm{Base}} \cdot \bar{r}_{\mathrm{Ramp}} }{ \| \bar{r}_{\mathrm{Base}} \| \cdot \| \bar{r}_{\mathrm{Ramp}} \| } \end{aligned}$$
Static Friction Coefficient
$$\begin{aligned}
\sum \bar{F} &= \bar{F_N} + \bar{F_f} + \bar{F_{g_{\parallel}}} + \bar{F_{g_{\perp}}} = 0 \\
\bar{F_f} &= \bar{F_{g_{\parallel}}} \\
\mu_s \bar{F_N} &= \bar{F_{g_{\parallel}}} \\
\mu_s m g \cos(\theta) &= m g \sin(\theta) \\
\mu_s &= \tan(\theta)
\end{aligned}$$
Kinetic Friction Coefficient
$$\begin{aligned}
m a &= \bar{F_{g_{\parallel}}} - \bar{F_f}\\
m a &= m g \sin(\theta) - \mu_k m g \cos(\theta)\\
\mu_k &= \frac{1}{\cos(\theta)} \times (\sin(\theta) - \frac{a}{g})
\end{aligned}$$
# Show and summarize the contents of one of the trials.
printmd("Static Friction - Small Area: Trial 1 - Raw Data Collected", 3)
print('Units: timestamp (ms), px-(px), r-(m), v-(m/s), a-(m/s^2)')
display(static_small.trials[0].raw_data)
display(static_small.trials[0].raw_data.describe())
# Display a plot comparing the position of the block over time for each trial.
# Then, display a plot comparing the angle of the ramp over time for each trial.
static_big.plot_raw_data(legend=True)
static_big.plot_calculations(legend=True)
static_small.plot_raw_data(legend=True)
static_small.plot_calculations(legend=True)
# Display a plot comparing the position of the block over time for each trial.
# Then, display a plot comparing the acceleration of the block over time for each trial.
# Finally, display a plot comparing the angle of the ramp over time for each trial.
kinetic_big.plot_raw_data(legend=True)
kinetic_big.plot_raw_data(x='ax-yellowneon', y='ay-yellowneon', legend=True)
kinetic_big.plot_calculations(legend=True)
kinetic_small.plot_raw_data(legend=True)
kinetic_small.plot_raw_data(x='ax-yellowneon', y='ay-yellowneon', legend=True)
kinetic_small.plot_calculations(legend=True)
# Tabulate the calculated friction coefficient of each trial in each experiment.
# Tabulate the mean and confidence interval of the friction coefficient in each experiment.
static_results = pd.DataFrame({
'Large Area': static_big.mu,
'Small Area': static_small.mu,
'Trial': range(1, 10)
}).set_index('Trial')
static_avg = pd.DataFrame({
'Large Area':
[f"{static_big.mu_avg:.5f} ± {static_big.mu_error:.5f}",
f"{static_big.mu_confidence_interval(.95)[0]:.5f} ≥ µ ≥ {static_big.mu_confidence_interval(.95)[1]:.5f}"],
'Small Area':
[f"{static_small.mu_avg:.5f} ± {static_small.mu_error:.5f}",
f"{static_small.mu_confidence_interval(.95)[0]:.5f} ≥ µ ≥ {static_small.mu_confidence_interval(.95)[1]:.5f}"]},
index=['Average', '95% Conf']
).style.set_properties(**{'text-align': 'center'}
).set_table_styles([dict(selector='th', props=[('text-align', 'center')])])
kinetic_results = pd.DataFrame({
'Large Area': kinetic_big.mu,
'Small Area': kinetic_small.mu,
'Trial': range(1, 10)
}).set_index('Trial')
kinetic_avg = pd.DataFrame({
'Large Area':
[f"{kinetic_big.mu_avg:.5f} ± {kinetic_big.mu_error:.5f}",
f"{kinetic_big.mu_confidence_interval(.95)[0]:.5f} ≥ µ ≥ {kinetic_big.mu_confidence_interval(.95)[1]:.5f}"],
'Small Area':
[f"{kinetic_small.mu_avg:.5f} ± {kinetic_small.mu_error:.5f}",
f"{kinetic_small.mu_confidence_interval(.95)[0]:.5f} ≥ µ ≥ {kinetic_small.mu_confidence_interval(.95)[1]:.5f}"]},
index=['Average', '95% Conf']
).style.set_properties(**{'text-align': 'center'}
).set_table_styles([dict(selector='th', props=[('text-align', 'center')])])
printmd("Coefficient of Static Friction", 3)
display(static_results)
display(static_avg)
printmd("Coefficient of Kinetic Friction", 3)
display(kinetic_results)
display(kinetic_avg)
# Plot the calculated coefficients and analyze any trends.
static_results['Large Area Rolling Mean'] = static_results['Large Area'].expanding(1).mean()
static_results['Small Area Rolling Mean'] = static_results['Small Area'].expanding(1).mean()
plt.plot('Large Area', '.', data = static_results, c='green', label='Static - Large Area')
plt.plot('Small Area', '.', data = static_results, c='red', label='Static - Small Area')
kinetic_results['Large Area Rolling Mean'] = kinetic_results['Large Area'].expanding(1).mean()
kinetic_results['Small Area Rolling Mean'] = kinetic_results['Small Area'].expanding(1).mean()
plt.plot('Large Area', '.', data = kinetic_results, c='lightgreen', label='Kinetic - Large Area')
plt.plot('Small Area', '.', data = kinetic_results, c='pink', label='Kinetic - Small Area')
plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
plt.plot('Large Area Rolling Mean', data = static_results, c='green',)
plt.plot('Small Area Rolling Mean', data = static_results, c='red')
plt.plot('Large Area Rolling Mean', data = kinetic_results, c='lightgreen', label=None)
plt.plot('Small Area Rolling Mean', data = kinetic_results, c='pink')
plt.title('Coefficient of Friction of a Wood Block')
plt.xlabel('Trial #')
plt.ylabel('Coefficient of Friction')
plt.show()
The Kinetic - Large Area and Kinetic - Small Area values has a strong correlation, supporing the hypothesis that $\mu$ is not dependent on surface area, and it is only dependent on surface material and mass. These calculated values of $\mu_k$ trends towards a converging value.
The calculated values of $\mu_s$ in the Static - Large Area exeperiment indicates that $\mu_s$ is greater than $\mu_k$. The calculated values of $\mu_s$ in the Static - Small Area exeperiment, however, do not support this. Observing the plot above, these values of $\mu_s$ (red) are shown to get lower for each subsequent trial. As this trend line has a steady negative slope, it can be speculated that if more trials were taken in this way, the data would become even less accurate, before it improve.
This was likely caused a flaw in the experiment's execution, potentially due to human error.