|
|
import streamlit as st |
|
|
import numpy as np |
|
|
import matplotlib.pyplot as plt |
|
|
import pandas as pd |
|
|
import seaborn as sns |
|
|
|
|
|
class FrictionSimulation: |
|
|
def __init__(self): |
|
|
|
|
|
self.g = 9.8 |
|
|
self.mass = 10.0 |
|
|
self.angle = 0.0 |
|
|
self.coefficient_static = 0.5 |
|
|
self.coefficient_kinetic = 0.3 |
|
|
|
|
|
def calculate_forces(self): |
|
|
""" |
|
|
Calculate forces acting on an object on an inclined plane |
|
|
""" |
|
|
|
|
|
theta = np.deg2rad(self.angle) |
|
|
|
|
|
|
|
|
normal_force = self.mass * self.g * np.cos(theta) |
|
|
|
|
|
|
|
|
weight_parallel = self.mass * self.g * np.sin(theta) |
|
|
weight_perpendicular = self.mass * self.g * np.cos(theta) |
|
|
|
|
|
|
|
|
max_static_friction = self.coefficient_static * normal_force |
|
|
|
|
|
|
|
|
kinetic_friction = self.coefficient_kinetic * normal_force |
|
|
|
|
|
return { |
|
|
'Normal Force': normal_force, |
|
|
'Weight Parallel': weight_parallel, |
|
|
'Weight Perpendicular': weight_perpendicular, |
|
|
'Max Static Friction': max_static_friction, |
|
|
'Kinetic Friction': kinetic_friction |
|
|
} |
|
|
|
|
|
def plot_force_diagram(self, forces): |
|
|
""" |
|
|
Create a force diagram visualization |
|
|
""" |
|
|
plt.figure(figsize=(10, 6)) |
|
|
|
|
|
|
|
|
force_names = list(forces.keys()) |
|
|
force_values = list(forces.values()) |
|
|
|
|
|
plt.bar(force_names, force_values) |
|
|
plt.title('Forces Acting on Object') |
|
|
plt.xlabel('Force Types') |
|
|
plt.ylabel('Force Magnitude (N)') |
|
|
plt.xticks(rotation=45, ha='right') |
|
|
plt.tight_layout() |
|
|
|
|
|
return plt |
|
|
|
|
|
def main(): |
|
|
st.title('Interactive Friction Simulation') |
|
|
|
|
|
|
|
|
st.sidebar.header('Simulation Parameters') |
|
|
|
|
|
|
|
|
sim = FrictionSimulation() |
|
|
|
|
|
|
|
|
sim.mass = st.sidebar.slider('Object Mass (kg)', 1.0, 50.0, 10.0, 0.5) |
|
|
|
|
|
|
|
|
sim.angle = st.sidebar.slider('Incline Angle (degrees)', 0, 90, 30, 1) |
|
|
|
|
|
|
|
|
sim.coefficient_static = st.sidebar.slider('Static Friction Coefficient', 0.0, 1.0, 0.5, 0.01) |
|
|
sim.coefficient_kinetic = st.sidebar.slider('Kinetic Friction Coefficient', 0.0, 1.0, 0.3, 0.01) |
|
|
|
|
|
|
|
|
forces = sim.calculate_forces() |
|
|
|
|
|
|
|
|
st.header('Force Calculations') |
|
|
force_df = pd.DataFrame.from_dict(forces, orient='index', columns=['Force (N)']) |
|
|
st.dataframe(force_df) |
|
|
|
|
|
|
|
|
st.header('Force Diagram') |
|
|
fig = sim.plot_force_diagram(forces) |
|
|
st.pyplot(fig) |
|
|
|
|
|
|
|
|
st.header('Friction Explanation') |
|
|
st.markdown(""" |
|
|
### Understanding Friction on an Inclined Plane |
|
|
|
|
|
- **Normal Force**: The force perpendicular to the surface, supporting the object's weight |
|
|
- **Weight Parallel**: Component of weight pushing the object down the slope |
|
|
- **Max Static Friction**: Maximum friction force that prevents object from sliding |
|
|
- **Kinetic Friction**: Friction force when the object is moving |
|
|
|
|
|
#### When will the object start sliding? |
|
|
- If the parallel component of weight exceeds maximum static friction |
|
|
- The critical angle can be calculated using the static friction coefficient |
|
|
""") |
|
|
|
|
|
|
|
|
critical_angle = np.arctan(sim.coefficient_static) * 180 / np.pi |
|
|
st.info(f"Critical Angle: {critical_angle:.2f} degrees") |
|
|
|
|
|
if __name__ == '__main__': |
|
|
main() |