matlab模拟小球平抛
% 需求:模拟小球平抛运动过程,考虑惯性、旋转和与地面的碰撞,直到能量足够少弹不起来为止,用动画形式展示
% TODO:调整动画窗口和坐标轴以完整显示动画,并将动画保存为视频
% 基础参数设置
x0 = 0; % 初始水平位置
y0 = 10; % 初始垂直位置(高度)
vx0 = 5; % 初始水平速度
vy0 = 0; % 初始垂直速度
g = -9.81; % 重力加速度,单位:m/s^2
dt = 0.01; % 时间步长,单位:秒
e = 0.8; % 恢复系数(每次碰撞后的能量保留比例)
mu = 0.1; % 地面与小球之间的摩擦系数
radius = 0.2; % 小球半径,单位:米
mass = 0.5; % 小球质量,单位:kg
I = (2/5)*mass*radius^2; % 小球的转动惯量
threshold_vy = 0.1; % 判定小球停止弹跳的垂直速度阈值
threshold_vx = 0.01; % 判定小球停止滚动的水平速度阈值
% 初始化变量
x = x0;
y = y0;
vx = vx0;
vy = vy0;
omega = 0; % 初始角速度
t = 0;
% 用于存储轨迹数据
X = [];
Y = [];
% 设置动画
figure('Position', get(0, 'ScreenSize')); % 将窗口设置为全屏
hold on;
grid on;
xlabel('水平位置 (m)');
ylabel('垂直位置 (m)');
title('考虑惯性的小球平抛运动模拟(含能量损失)');
ball = plot(x, y, 'ro', 'MarkerSize', 15, 'MarkerFaceColor', 'r'); % 小球
trajectory = plot(NaN, NaN, 'b'); % 轨迹
% 初始化坐标轴范围
axis([x0-1 x0+10 0 y0+5]);
% 调整画面显示
set(gca, 'FontSize', 14); % 增大坐标轴字体
% 创建视频对象
video_filename = 'ball_motion.mp4'; % 视频文件名
video = VideoWriter(video_filename, 'MPEG-4');
video.FrameRate = 1/dt; % 设置帧率,与模拟时间步长匹配
open(video);
% 仿真循环
while true
% 更新速度
vy = vy + g * dt;
% 更新位置
x = x + vx * dt;
y = y + vy * dt;
% 存储数据
X(end+1) = x;
Y(end+1) = y;
% 碰撞检测
if y <= radius % 考虑小球的半径
y = radius; % 确保小球不穿过地面
vy = -e * vy; % 垂直速度反向并考虑能量损失
% 计算由于摩擦导致的水平速度变化和角速度变化
Fn = mass * abs(g); % 法向力
Ff = mu * Fn; % 摩擦力
dv = (Ff / mass) * dt; % 水平速度的变化量
domega = (Ff * radius / I) * dt; % 角速度的变化量
% 更新水平速度和角速度
if vx > 0
vx = vx - dv;
omega = omega + domega;
if vx < 0
vx = 0;
end
elseif vx < 0
vx = vx + dv;
omega = omega - domega;
if vx > 0
vx = 0;
end
end
% 判断是否停止弹跳
if abs(vy) < threshold_vy
vy = 0;
% 检查是否需要继续滚动
if abs(vx) < threshold_vx
break; % 水平速度过小,结束仿真
end
end
end
% 当小球在地面上滚动时,考虑摩擦力减速
if y == radius && vy == 0
Fn = mass * abs(g); % 法向力
Ff = mu * Fn; % 摩擦力
dv = (Ff / mass) * dt; % 水平速度的变化量
domega = (Ff * radius / I) * dt; % 角速度的变化量
% 更新水平速度和角速度
if vx > 0
vx = vx - dv;
omega = omega + domega;
if vx < 0
vx = 0;
end
elseif vx < 0
vx = vx + dv;
omega = omega - domega;
if vx > 0
vx = 0;
end
end
% 判断是否停止滚动
if abs(vx) < threshold_vx
break; % 水平速度过小,结束仿真
end
end
% 更新动画
set(ball, 'XData', x, 'YData', y);
set(trajectory, 'XData', X, 'YData', Y);
% 动态调整坐标轴范围
axis([min(X)-1 max(X)+1 0 y0+5]);
drawnow;
% 捕获当前帧并写入视频
frame = getframe(gcf);
writeVideo(video, frame);
% 更新时间
t = t + dt;
end
% 关闭视频对象
close(video);
% 最后绘制完整轨迹
plot(X, Y, 'LineWidth', 2);
ball_motion