【Bonjour】竹知了 · 一转就哇哇叫 —— MATLAB 完整模拟版技术详解
竹知了 · 一转就哇哇叫 —— MATLAB 完整模拟版技术详解
一、项目概述
竹知了(又称竹蝉、拉线蝉)是一种传统民间玩具:竹筒一端蒙上竹膜,膜心系一根涂了松香的线,线的另一头拴在小竹签上。抓着竹签甩起来转圈,线在松香上“黏—滑”交替摩擦,振动沿传到竹膜,再经竹筒空腔共鸣放大,便发出那声酷似蝉鸣的“哇——哇——”。
本文介绍一个用 MATLAB 编写的交互式物理模拟游戏,完整再现了竹知了的甩动发声过程。项目包含绳系质点物理引擎、基于摩擦发声的音频合成算法、图形界面与实时反馈。
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
二、物理引擎:绳系质点模拟
竹知了的物理核心是一个绳系质点:竹筒视为质点,受重力、绳的拉力(只拉不推)和空气阻力共同作用。
2.1 物理参数
%% 物理参数
g = 980; % 重力加速度 (px/s^2)
L = 220; % 绳长 (px)
damping = 0.992; % 空气阻力系数
maxForce = 8000; % 最大用户施力
重力加速度设为 980 px/s²,使竹蝉的下坠感接近真实。绳长 220 像素,阻力系数 0.992 让甩动有适度的惯性延续。
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
2.2 状态变量与运动方程
竹蝉的状态由角度 θ 和角速度 ω 描述:
theta = -pi/2; % 当前角度 (rad)
omega = 0; % 角速度 (rad/s)
每一帧的物理更新分为三步:
% 1. 重力产生的切向力
gravityForce = -gui.g / gui.L * sin(gui.theta);
% 2. 用户施加的力(来自鼠标拖拽)
alpha = gravityForce + gui.userForce / gui.L;
% 3. 更新角速度和角度(欧拉积分 + 阻尼)
gui.omega = gui.omega + alpha * dt;
gui.omega = gui.omega * gui.damping;
gui.theta = gui.theta + gui.omega * dt;
重力切向力 -g/L * sin(θ) 让竹蝉在最低点达到平衡。用户施力通过鼠标移动产生,经阻尼衰减后形成自然的甩动感。
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
2.3 鼠标交互:施力映射
鼠标拖拽时,通过计算鼠标角度变化率来施加切向力:
function onMouseMove(src, ~)
gui = getappdata(src, 'guiData');
if ~gui.isDragging, return; end
cp = get(gui.ax, 'CurrentPoint');
mx = cp(1,1); my = cp(1,2);
dx = mx - gui.pivotX; dy = my - gui.pivotY;
newAngle = atan2(dx, -dy);
dAngle = angdiff(newAngle, gui.mouseAngle);
gui.mouseAngle = newAngle;
% 限制最大角速度变化,防止数值爆炸
maxDTheta = 0.5;
dAngle = max(-maxDTheta, min(maxDTheta, dAngle));
% 角度变化率 → 力
force = dAngle / gui.dt * 100;
force = max(-gui.maxForce, min(gui.maxForce, force));
gui.userForce = force;
setappdata(src, 'guiData', gui);
end
angdiff 函数计算角度差,确保结果在 [-π, π] 范围内:
function d = angdiff(a, b)
d = mod(a - b + pi, 2*pi) - pi;
end
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
三、音频合成:重现“哇哇”声
项目采用纯合成方式产生声音,无需外部音频文件。合成算法模拟了真实竹知了的发声链条:
松香黏滑摩擦 → 锯齿波脉冲 → 低频调幅(颗粒感)→ 共振峰滤波(膜腔共鸣)
3.1 主振荡器:锯齿波 + 软削波
真实玩具的松香摩擦产生非正弦的粗糙脉冲,用锯齿波模拟:
% 基础频率随转速升高 (55~195 Hz)
baseFreq = 55 + (speed / 5) * 140;
baseFreq = min(195, max(55, baseFreq));
signal = sawtooth(2*pi * baseFreq * t);
% tanh 软削波增加谐波,模拟摩擦的粗糙感
signal = tanh(signal * 1.5);
转速越快,基础频率越高,声音越尖越急促。
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
3.2 低频调幅:蝉鸣的颗粒感
真实竹知了的声音带有颗粒感,用低频正弦调幅实现:
amFreq = 24 + speed * 3;
amFreq = min(45, max(24, amFreq));
am = 0.5 + 0.5 * sin(2*pi * amFreq * t);
signal = signal .* am;
调幅频率随转速从 24 Hz 升至 45 Hz,模拟蝉鸣的脉冲节奏。
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
3.3 共振峰滤波:膜腔共鸣
竹膜和竹筒空腔对特定频率有共振增强效应,用三个并联带通滤波器模拟:
% 滤波器系数 (固定共振峰: 1050, 2150, 3350 Hz)
[b1, a1] = butter(2, [800 1300]/(fs/2), 'bandpass');
[b2, a2] = butter(2, [1800 2500]/(fs/2), 'bandpass');
[b3, a3] = butter(2, [3000 3700]/(fs/2), 'bandpass');
% 三个共振峰加权混合
sig1 = filter(b1, a1, signal);
sig2 = filter(b2, a2, signal);
sig3 = filter(b3, a3, signal);
signal = (sig1 * 1.2 + sig2 * 0.8 + sig3 * 0.5) / 2.5;
三个共振峰中心频率分别为 1050 Hz、2150 Hz、3350 Hz,对应竹膜与筒腔的共鸣特性。
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
3.4 包络与播放
最后添加淡入淡出包络,避免爆音:
env = linspace(0.3, 1, length(t)) .* linspace(1, 0.3, length(t));
signal = signal .* env;
signal = signal / max(abs(signal)) * 0.7;
% 异步播放
sound(signal, fs);
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
四、图形交互与视觉反馈
4.1 竹蝉的旋转与定位
竹蝉通过 hggroup 实现整体旋转,膜心(绳结)作为旋转原点:
group = hggroup(ax);
% 所有竹蝉部件相对于膜心 (0,0) 绘制
% ...
% 每帧更新位置和旋转角度
cx = gui.pivotX + gui.L * sin(gui.theta);
cy = gui.pivotY - gui.L * cos(gui.theta);
angle = atan2(cy - gui.pivotY, cx - gui.pivotX);
M = makehgtform('translate', [cx, cy, 0], 'zrotate', angle);
set(gui.group, 'Matrix', M);
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
4.2 翅膀动态
翅膀的张开幅度随转速变化,并叠加高频振翅:
spread = 0.3 + min(speed/5, 0.6);
flutter = min(speed/2, 1) * sin(now*50) * 0.25;
wingAng = angle + pi/2;
set(gui.wing1, 'XData', [0, 30*cos(wingAng + spread + flutter)], ...
'YData', [0, 30*sin(wingAng + spread + flutter)]);
set(gui.wing2, 'XData', [0, 30*cos(wingAng - spread - flutter)], ...
'YData', [0, 30*sin(wingAng - spread - flutter)]);
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
4.3 功德计数
每完整旋转一圈,功德加 1(自动甩模式不计入功德):
dTheta = angdiff(gui.theta, gui.lastTheta);
gui.totalRotation = gui.totalRotation + dTheta;
if abs(gui.totalRotation) >= 2*pi
numRot = floor(abs(gui.totalRotation) / (2*pi));
gui.merit = gui.merit + numRot;
gui.totalRotation = gui.totalRotation - sign(gui.totalRotation) * numRot * 2*pi;
end
gui.lastTheta = gui.theta;
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
五、运行与使用
运行环境
- MATLAB R2016b 及以上版本(推荐 R2020a 以上)
- 操作系统:Windows / macOS / Linux
- 音频输出设备
使用方法
- 将
zhuzhiliao_game.m保存到 MATLAB 工作目录 - 在命令窗口输入
zhuzhiliao_game并回车 - 按住鼠标左键在绘图区域画圈,竹蝉旋转并发声
- 按 空格键 切换自动甩模式
- 点击 重置 按钮归零
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
六、总结
本项目用约 400 行 MATLAB 代码实现了竹知了的完整模拟,涵盖:
| 模块 | 核心技术 |
|---|---|
| 物理引擎 | 绳系质点、欧拉积分、重力/阻尼/弹性约束 |
| 音频合成 | 锯齿波 + 调幅 + 三共振峰滤波 |
| 交互控制 | 鼠标拖拽施力、空格切换自动模式 |
| 视觉反馈 | hggroup 旋转、动态翅膀、轨迹残影、功德计数 |
项目纯 MATLAB 实现,无需任何附加工具箱,可作为物理模拟、信号处理或 MATLAB GUI 开发的教学示例。
📥 完整代码下载:竹知了 · 一转就哇哇叫 - MATLAB 完整模拟版
作者:zixia shang
单位:Xidian University
邮箱:zixia.shang@ieee.org
日期:2026-08-09
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)