当前位置: 首页 > news >正文

python中学物理实验模拟:斜面受力分析

python中学物理实验模拟:斜面受力分析
 

中学物理中斜面受力分析是一个非常重要的基础内容,也是牛顿运动定律应用的核心场景之一。

现在简要介绍斜面物体受力分析情况

重力分解

重力 G = mg

沿斜面平行分量:G∥ = G·sinθ = mg·sinθ

垂直斜面分量:G⊥ = G·cosθ = mg·cosθ

支持力

支持力 N = G⊥ = mg·cosθ

支持力总是垂直于接触面,大小等于重力的垂直斜面分量。

考虑静摩擦情况:

  • 最大静摩擦力:fₘₐₓ = μN = μmg·cosθ
  • 如果 G∥ ≤ fₘₐₓ,物体静止,实际静摩擦力 f = G∥

动摩擦情况:

  • 如果 G∥ > fₘₐₓ,物体滑动,动摩擦力 f = μN = μmg·cosθ

运动状态判断

静止条件:

G∥ ≤ μN

即:mg·sinθ ≤ μmg·cosθ

简化为:tanθ ≤ μ

滑动条件:

G∥ > μN

合力 = G∥ - f = mg·sinθ - μmg·cosθ

加速度 a = (mg·sinθ - μmg·cosθ)/m = g(sinθ - μcosθ)

运行截图:

程序主要功能

1. 参数控制

  • 质量调节:可设置物体质量(1-20 kg)
  • 角度调节:可设置斜面角度(0-60°)
  • 摩擦系数调节:可设置摩擦系数(0-1)
  • 摩擦开关:可选择是否考虑摩擦力

2. 实时计算与显示

  • 文字分析:详细显示各种力的计算过程和结果
  • 图形显示
    • 斜面受力示意图:直观显示物体在斜面上的受力情况
    • 重力分解图:展示重力如何分解为平行和垂直分量

3. 动态效果

  • 物体状态显示:"静止"或"滑动"
  • 滑动时文字动画效果,营造运动感

核心物理原理

源码如下:

import tkinter as tk
from tkinter import ttk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
import mathclass InclinedPlaneSimulator:def __init__(self, root):self.root = rootself.root.title("中学物理斜面受力分析模拟程序")self.root.geometry("1000x800")# 物理参数self.mass = tk.DoubleVar(value=5.0)  # 质量 kgself.angle = tk.DoubleVar(value=30.0)  # 角度 度self.friction_coeff = tk.DoubleVar(value=0.2)  # 摩擦系数self.has_friction = tk.BooleanVar(value=True)  # 是否有摩擦self.g = 9.8  # 重力加速度# 动画参数self.animation_time = 0  # 动画时间参数self.setup_ui()self.update_analysis()self.start_animation()  # 启动动画def start_animation(self):"""启动动画"""def update_animation():forces = self.calculate_forces()if forces['state'] == "滑动":self.animation_time += 0.3  # 控制动画速度if self.animation_time > 2 * math.pi:self.animation_time = 0self.update_plots(forces)self.root.after(150, update_animation)  # 每150ms更新一次update_animation()def setup_ui(self):# 主框架main_frame = ttk.Frame(self.root)main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)# 左侧控制面板control_frame = ttk.LabelFrame(main_frame, text="参数设置", padding=10)control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))# 质量设置ttk.Label(control_frame, text="物体质量 (kg):").pack(anchor=tk.W)mass_scale = ttk.Scale(control_frame, from_=1, to=20, variable=self.mass, orient=tk.HORIZONTAL, length=200, command=self.on_parameter_change)mass_scale.pack(fill=tk.X, pady=5)self.mass_label = ttk.Label(control_frame, text=f"{self.mass.get():.1f} kg")self.mass_label.pack(anchor=tk.W)# 角度设置ttk.Label(control_frame, text="斜面角度 (°):").pack(anchor=tk.W, pady=(20, 0))angle_scale = ttk.Scale(control_frame, from_=0, to=60, variable=self.angle, orient=tk.HORIZONTAL, length=200, command=self.on_parameter_change)angle_scale.pack(fill=tk.X, pady=5)self.angle_label = ttk.Label(control_frame, text=f"{self.angle.get():.1f}°")self.angle_label.pack(anchor=tk.W)# 摩擦力设置friction_frame = ttk.Frame(control_frame)friction_frame.pack(fill=tk.X, pady=(20, 0))friction_check = ttk.Checkbutton(friction_frame, text="考虑摩擦力", variable=self.has_friction, command=self.on_parameter_change)friction_check.pack(anchor=tk.W)ttk.Label(control_frame, text="摩擦系数:").pack(anchor=tk.W, pady=(10, 0))friction_scale = ttk.Scale(control_frame, from_=0, to=1, variable=self.friction_coeff, orient=tk.HORIZONTAL, length=200, command=self.on_parameter_change)friction_scale.pack(fill=tk.X, pady=5)self.friction_label = ttk.Label(control_frame, text=f"{self.friction_coeff.get():.2f}")self.friction_label.pack(anchor=tk.W)# 分析结果显示result_frame = ttk.LabelFrame(control_frame, text="受力分析结果", padding=10)result_frame.pack(fill=tk.BOTH, expand=True, pady=(20, 0))self.result_text = tk.Text(result_frame, height=15, width=35, font=("宋体", 10))scrollbar = ttk.Scrollbar(result_frame, orient=tk.VERTICAL, command=self.result_text.yview)self.result_text.configure(yscrollcommand=scrollbar.set)self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)scrollbar.pack(side=tk.RIGHT, fill=tk.Y)# 右侧图形显示plot_frame = ttk.Frame(main_frame)plot_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)# 创建matplotlib图形self.fig, (self.ax1, self.ax2) = plt.subplots(2, 1, figsize=(8, 10))self.canvas = FigureCanvasTkAgg(self.fig, plot_frame)self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文字体plt.rcParams['axes.unicode_minus'] = Falsedef on_parameter_change(self, event=None):# 更新标签显示self.mass_label.config(text=f"{self.mass.get():.1f} kg")self.angle_label.config(text=f"{self.angle.get():.1f}°")self.friction_label.config(text=f"{self.friction_coeff.get():.2f}")# 更新分析self.update_analysis()def calculate_forces(self):"""计算各种力的大小"""m = self.mass.get()theta = math.radians(self.angle.get())mu = self.friction_coeff.get()# 重力及其分量G = m * self.gG_parallel = G * math.sin(theta)  # 沿斜面向下G_perpendicular = G * math.cos(theta)  # 垂直斜面向下# 支持力N = G_perpendicular# 摩擦力if self.has_friction.get():f_max = mu * N  # 最大静摩擦力if G_parallel <= f_max:# 静止状态,静摩擦力等于重力沿斜面分量f = G_parallelstate = "静止"a = 0else:# 滑动状态,动摩擦力f = mu * Nstate = "滑动"a = (G_parallel - f) / melse:f = 0state = "滑动"a = G_parallel / mreturn {'G': G, 'G_parallel': G_parallel, 'G_perpendicular': G_perpendicular,'N': N, 'f': f, 'state': state, 'acceleration': a}def update_analysis(self):"""更新受力分析"""forces = self.calculate_forces()# 更新文本结果self.update_result_text(forces)# 更新图形self.update_plots(forces)def update_result_text(self, forces):"""更新文本分析结果"""self.result_text.delete(1.0, tk.END)text = f"""受力分析结果:物理量:
• 质量:{self.mass.get():.1f} kg
• 斜面角度:{self.angle.get():.1f}°
• 摩擦系数:{self.friction_coeff.get():.2f}力的计算:
• 重力 G = mg = {forces['G']:.2f} N• 重力沿斜面分量:G∥ = G·sinθ = {forces['G_parallel']:.2f} N• 重力垂直斜面分量:G⊥ = G·cosθ = {forces['G_perpendicular']:.2f} N• 支持力:N = G⊥ = {forces['G_perpendicular']:.2f} N"""if self.has_friction.get():text += f"""• 摩擦力:f = {forces['f']:.2f} N最大静摩擦力 = μN = {self.friction_coeff.get() * forces['N']:.2f} N"""text += f"""运动状态:
• 物体状态:{forces['state']}
• 加速度:{forces['acceleration']:.2f} m/s²力的平衡分析:
"""if forces['state'] == "静止":text += "• 沿斜面方向:G∥ = f (静摩擦力)\n"text += "• 垂直斜面方向:N = G⊥\n"text += "• 物体处于平衡状态"else:if self.has_friction.get():text += f"• 沿斜面方向:合力 = G∥ - f = {forces['G_parallel'] - forces['f']:.2f} N\n"else:text += f"• 沿斜面方向:合力 = G∥ = {forces['G_parallel']:.2f} N\n"text += "• 垂直斜面方向:N = G⊥\n"text += f"• 物体沿斜面向下加速运动"self.result_text.insert(1.0, text)def update_plots(self, forces):"""更新图形显示"""self.ax1.clear()self.ax2.clear()# 第一个图:斜面和力的示意图self.draw_inclined_plane(self.ax1, forces)# 第二个图:力的分解图self.draw_force_decomposition(self.ax2, forces)# 调整布局避免重叠self.fig.tight_layout(pad=2.0)self.canvas.draw()def draw_inclined_plane(self, ax, forces):"""绘制斜面受力示意图"""theta = math.radians(self.angle.get())theta_deg = self.angle.get()# 斜面起点和终点incline_start_x, incline_start_y = 1, 1incline_length = 3incline_end_x = incline_start_x + incline_length * math.cos(theta)incline_end_y = incline_start_y + incline_length * math.sin(theta)# 绘制斜面(改为细线)ax.plot([incline_start_x, incline_end_x], [incline_start_y, incline_end_y], 'k-', linewidth=2, label='斜面')  # 改为linewidth=2,比之前的4细了一半# 绘制水平地面ax.plot([0, 5], [1, 1], 'k-', linewidth=2, alpha=0.7)# 物体位置(在斜面中点)t = 0.5  # 物体在斜面中点obj_center_x = incline_start_x + t * incline_length * math.cos(theta)obj_center_y = incline_start_y + t * incline_length * math.sin(theta)# 绘制物体(正方形,底边平行于斜面且紧贴斜面)obj_size = 0.2# 计算正方形的四个顶点,使底边平行于斜面# 正方形底边中心点就在斜面上bottom_center_x = obj_center_xbottom_center_y = obj_center_y# 沿斜面方向的单位向量slope_unit_x = math.cos(theta)slope_unit_y = math.sin(theta)# 垂直斜面向上的单位向量normal_unit_x = -math.sin(theta)normal_unit_y = math.cos(theta)# 正方形的四个顶点half_size = obj_size / 2# 底边两个顶点bottom_left_x = bottom_center_x - half_size * slope_unit_xbottom_left_y = bottom_center_y - half_size * slope_unit_ybottom_right_x = bottom_center_x + half_size * slope_unit_xbottom_right_y = bottom_center_y + half_size * slope_unit_y# 顶边两个顶点top_left_x = bottom_left_x + obj_size * normal_unit_xtop_left_y = bottom_left_y + obj_size * normal_unit_ytop_right_x = bottom_right_x + obj_size * normal_unit_xtop_right_y = bottom_right_y + obj_size * normal_unit_y##        # 根据运动状态选择物体颜色
##        if forces['state'] == "静止":
##            obj_color = 'red'
##            obj_alpha = 0.7
##        else:
##            obj_color = 'orange'  # 滑动时变成橙色
##            obj_alpha = 0.9obj_color = 'red'obj_alpha = 0.7       # 绘制正方形square_x = [bottom_left_x, bottom_right_x, top_right_x, top_left_x, bottom_left_x]square_y = [bottom_left_y, bottom_right_y, top_right_y, top_left_y, bottom_left_y]ax.plot(square_x, square_y, color=obj_color, linewidth=2)ax.fill(square_x, square_y, color=obj_color, alpha=obj_alpha)# 力的作用点是物体的重心(正方形中心)force_point_x = bottom_center_x + (obj_size / 2) * normal_unit_xforce_point_y = bottom_center_y + (obj_size / 2) * normal_unit_y# 绘制状态标识文字,角度与斜面一致if forces['state'] == "静止":# 静止状态:文字固定在物体上方status_text = "静止"status_color = 'green'text_x = force_point_x + 0.4 * normal_unit_xtext_y = force_point_y + 0.4 * normal_unit_yax.text(text_x, text_y, status_text, fontsize=12, color=status_color, fontweight='bold', ha='center', va='center',rotation=theta_deg,  # 文字角度与斜面一致bbox=dict(boxstyle="round,pad=0.3", facecolor='lightgreen', alpha=0.8))else:# 滑动状态:文字单向向后飘动status_text = "滑动"status_color = 'red'# 飘动参数drift_amplitude = 0.8  # 飘动距离cycle_duration = 2 * math.pi  # 一个完整周期# 计算当前周期内的进度 (0 到 1)cycle_progress = (self.animation_time % cycle_duration) / cycle_duration# 生成多个错开的文字,营造连续效果for i, phase_offset in enumerate([0, 0.3, 0.6]):# 计算当前文字的进度text_progress = (cycle_progress + phase_offset) % 1.0# 只在进度0-0.7之间显示文字,0.7-1.0之间隐藏(用于重置)if text_progress <= 0.7:# 计算文字位置(线性向后移动)drift_offset = text_progress * drift_amplitude# 基础位置:物体上方base_text_x = force_point_x + 0.4 * normal_unit_xbase_text_y = force_point_y + 0.4 * normal_unit_y# 向后飘动(沿着斜面向上的方向)text_x = base_text_x + drift_offset * slope_unit_xtext_y = base_text_y + drift_offset * slope_unit_y# 透明度:开始清晰,向后逐渐变淡text_alpha = max(0.2, 1.0 - text_progress * 1.2)# 字体大小:向后逐渐变小font_size = max(8, 12 - int(text_progress * 6))ax.text(text_x, text_y, status_text, fontsize=font_size, color=status_color, fontweight='bold', ha='center', va='center',rotation=theta_deg,  # 文字角度与斜面一致alpha=text_alpha,bbox=dict(boxstyle="round,pad=0.2", facecolor='lightyellow', alpha=text_alpha*0.4, edgecolor=status_color))# 力的缩放因子scale = 0.02arrow_width = 0.08arrow_length = 0.1# 绘制重力(竖直向下)G_length = forces['G'] * scaleax.arrow(force_point_x, force_point_y, 0, -G_length, head_width=arrow_width, head_length=arrow_length, fc='blue', ec='blue', linewidth=2)ax.text(force_point_x + 0.2, force_point_y - G_length/2, 'G', fontsize=12, color='blue', fontweight='bold')# 绘制支持力(垂直斜面向上)normal_x = -math.sin(theta) * forces['N'] * scalenormal_y = math.cos(theta) * forces['N'] * scaleax.arrow(force_point_x, force_point_y, normal_x, normal_y, head_width=arrow_width, head_length=arrow_length, fc='green', ec='green', linewidth=2)ax.text(force_point_x + normal_x - 0.3, force_point_y + normal_y + 0.1, 'N', fontsize=12, color='green', fontweight='bold')# 绘制摩擦力(如果有)if self.has_friction.get() and forces['f'] > 0:friction_x = math.cos(theta) * forces['f'] * scalefriction_y = math.sin(theta) * forces['f'] * scaleax.arrow(force_point_x, force_point_y, friction_x, friction_y, head_width=arrow_width, head_length=arrow_length, fc='orange', ec='orange', linewidth=2)ax.text(force_point_x + friction_x + 0.1, force_point_y + friction_y + 0.1, 'f', fontsize=12, color='orange', fontweight='bold')# 绘制角度标记arc_radius = 0.4arc_angles = np.linspace(0, theta, 30)arc_x = incline_start_x + arc_radius * np.cos(arc_angles)arc_y = incline_start_y + arc_radius * np.sin(arc_angles)ax.plot(arc_x, arc_y, 'k-', linewidth=1.5)# 角度标注text_x = incline_start_x + arc_radius + 0.2text_y = incline_start_y + 0.1ax.text(text_x, text_y, f'θ={self.angle.get():.1f}°', fontsize=11, fontweight='bold')# 设置图形范围,确保完整显示ax.set_xlim(0, 6)ax.set_ylim(0.5, 4)ax.set_aspect('equal')ax.grid(True, alpha=0.3)ax.set_title('斜面受力示意图', fontsize=14, fontweight='bold')ax.set_xticks([])  # 隐藏x轴刻度ax.set_yticks([])  # 隐藏y轴刻度ax.set_xlabel('')ax.set_ylabel('')def draw_force_decomposition(self, ax, forces):"""绘制重力分解图"""G_scale = 0.08origin_x, origin_y = 0, 0# 获取斜面角度theta_deg = self.angle.get()theta_rad = math.radians(theta_deg)# 重力(竖直向下,蓝色)G_length = forces['G'] * G_scaleax.arrow(origin_x, origin_y, 0, -G_length, head_width=0.15, head_length=0.15, fc='blue', ec='blue', linewidth=3)ax.text(-0.3, -G_length/2, f'G={forces["G"]:.1f}N', fontsize=11, color='blue', fontweight='bold')# 平行于斜面分量(紫色)parallel_length = forces['G_parallel'] * G_scaleparallel_x = -parallel_length * math.cos(-theta_rad)  # 翻转x分量parallel_y = parallel_length * math.sin(-theta_rad)ax.arrow(origin_x, origin_y, parallel_x, parallel_y, head_width=0.12, head_length=0.12, fc='purple', ec='purple', linewidth=2)ax.text(parallel_x - 0.2, parallel_y - 0.3, f'G∥={forces["G_parallel"]:.1f}N', fontsize=10, color='purple', fontweight='bold')# 垂直于斜面分量(红色)perp_length = forces['G_perpendicular'] * G_scaleperp_x = perp_length * math.sin(theta_rad)  # 翻转x分量perp_y = -perp_length * math.cos(theta_rad)ax.arrow(origin_x, origin_y, perp_x, perp_y, head_width=0.12, head_length=0.12, fc='red', ec='red', linewidth=2)ax.text(perp_x + 0.8, perp_y + 0.1, f'G⊥={forces["G_perpendicular"]:.1f}N', fontsize=10, color='red', fontweight='bold')# 绘制虚线构成的平行四边形ax.plot([parallel_x, parallel_x + perp_x], [parallel_y, parallel_y + perp_y], 'k--', alpha=0.6, linewidth=1)ax.plot([perp_x, parallel_x + perp_x], [perp_y, parallel_y + perp_y], 'k--', alpha=0.6, linewidth=1)# 重新绘制角度弧线 arc_radius = 0.6# 重力方向:-π/2(向下)gravity_angle = -math.pi/2# 垂直分量方向perp_angle = math.atan2(perp_y, perp_x)# 角度弧线从垂直分量到重力start_angle = perp_angleend_angle = gravity_angle# 确保角度方向正确if abs(start_angle - end_angle) > math.pi:if start_angle > end_angle:end_angle += 2 * math.pielse:start_angle += 2 * math.piarc_angles = np.linspace(start_angle, end_angle, 30)arc_x = arc_radius * np.cos(arc_angles)arc_y = arc_radius * np.sin(arc_angles)ax.plot(arc_x, arc_y, 'k-', linewidth=2)# 角度标注mid_angle = (start_angle + end_angle) / 2text_radius = arc_radius + 0.2angle_text_x = text_radius * math.cos(mid_angle)angle_text_y = text_radius * math.sin(mid_angle)ax.text(angle_text_x, angle_text_y, f'θ={theta_deg:.1f}°', fontsize=11, fontweight='bold', ha='center', va='center')# 设置显示 - 调整x轴范围ax.axhline(y=0, color='k', linestyle='-', alpha=0.3, linewidth=0.5)ax.axvline(x=0, color='k', linestyle='-', alpha=0.3, linewidth=0.5)max_val = G_length + 0.8ax.set_xlim(-max_val*0.8, max_val*0.6)  # 翻转x轴范围ax.set_ylim(-max_val, max_val*0.3)ax.set_aspect('equal')ax.grid(True, alpha=0.3)ax.set_title('重力分解图', fontsize=14, fontweight='bold')#ax.set_xlabel('水平方向')#ax.set_ylabel('竖直方向')ax.set_xticks([])  # 隐藏x轴刻度ax.set_yticks([])  # 隐藏y轴刻度ax.set_xlabel('')ax.set_ylabel('')        if __name__ == "__main__":root = tk.Tk()app = InclinedPlaneSimulator(root)root.mainloop()

相关文章:

  • IDEA + Spring Boot + javadoc 实例应用
  • Java底层原理:深入理解JVM性能调优与监控
  • 腾讯云产品都有哪些
  • 永磁无刷电机旋转原理
  • 大脑感官:视觉系统中将感观信息转换为神经信号
  • 苍穹外卖day3--公共字段填充+新增菜品
  • Python打卡:Day36
  • 《告别一换就崩:前端游戏物理引擎适配层设计哲学》
  • Redis-set集合
  • Altera PCI IP target设计分享
  • dockers virbox 安装
  • MySQL多表关系
  • 【已解决】Android Studio gradle遇到unresolved reference错误
  • 归因问答-如何进行人类评估
  • 桌面小屏幕实战课程:DesktopScreen 11 SPI 水墨屏
  • Docker安装Mysql、配置文件挂载、修改Mysql编码
  • Spark 之 QueryStage
  • 高标准通信国际接轨,Ethercat与PROFINET网关实现全自动化生产线
  • 【Pandas】pandas DataFrame first_valid_index
  • 大厂测开实习和小厂开发实习怎么选