第三讲:PWM核心原理——占空比、频率与周期的三角恋
各位同学,今天我们聊点硬核的。PWM——脉冲宽度调制,这玩意儿在按摩仪里就是灵魂。说白了,它就是通过快速开关信号,让负载(比如电机、加热片)感觉到的平均电压发生变化。你想想看,按摩仪的揉捏力度、加热温度,全靠它来调。
我个人习惯把PWM比作一个「开关灯」的游戏。你快速开关灯,人眼就会觉得灯变暗了。开关的速度(频率)和灯亮的时间比例(占空比),决定了你看到的亮度。按摩仪里的电机也是一样,只不过它感受到的是平均电压。
3.1 三个核心参数:占空比、频率、周期
先搞清楚这三个东西是什么,不然后面代码写出来你都不知道在调什么。
| 参数 | 符号 | 单位 | 说明 |
|---|---|---|---|
| 周期 | T | 秒 (s) | 一个完整脉冲波形的时间长度 |
| 频率 | f | 赫兹 (Hz) | 每秒产生的脉冲个数,f = 1/T |
| 占空比 | D | 百分比 (%) | 高电平时间占整个周期的比例 |
举个例子:假设周期 T = 10ms,那么频率 f = 100Hz。如果高电平持续了 7ms,占空比就是 70%。
核心公式:
占空比 D = (高电平时间 / 周期 T) × 100%
平均电压 = 峰值电压 × 占空比
嗯,这里要注意:占空比不是越高越好。我在项目中遇到过,有同事把占空比调到95%以上,结果电机直接烧了。为什么?因为高电平时间太长,MOS管散热跟不上。避坑指南:按摩仪电机一般建议占空比不要超过90%,留点余量给散热。
3.2 用Python生成PWM信号
光说不练假把式。我们用Python来模拟一下PWM波形。这里我用的是 matplotlib 和 numpy,这两个库你肯定装了吧?没装的话先 pip install matplotlib numpy。
先看代码:
import numpy as np
import matplotlib.pyplot as plt
# 参数设置
frequency = 50 # 频率 50Hz
period = 1 / frequency # 周期 0.02s = 20ms
duty_cycle = 0.6 # 占空比 60%
amplitude = 3.3 # 峰值电压 3.3V
# 时间轴:生成两个周期的数据
t = np.linspace(0, 2 * period, 1000)
pwm_signal = np.zeros_like(t)
# 计算每个时间点对应的PWM值
for i, time in enumerate(t):
# 取模运算,得到当前时间在一个周期内的位置
pos_in_period = time % period
if pos_in_period < duty_cycle * period:
pwm_signal[i] = amplitude
else:
pwm_signal[i] = 0
# 画图
plt.figure(figsize=(10, 4))
plt.plot(t * 1000, pwm_signal, 'b-', linewidth=2)
plt.title(f'PWM Signal (f={frequency}Hz, D={duty_cycle*100:.0f}%)')
plt.xlabel('Time (ms)')
plt.ylabel('Voltage (V)')
plt.ylim(-0.5, amplitude + 0.5)
plt.grid(True, alpha=0.3)
plt.show()
这段代码的逻辑很简单:
- 先生成时间轴,覆盖两个周期
- 对每个时间点,判断它在一个周期内的位置
- 如果位置小于占空比对应的时间,输出高电平;否则输出低电平
运行一下,你会看到一个方波。高电平占60%,低电平占40%。这就是PWM的原始形态。
小技巧: 我建议你把占空比改成0.2、0.5、0.8分别跑一次,观察波形变化。你会发现高电平的「宽度」在变,这就是「脉冲宽度调制」名字的由来。
3.3 不同占空比下的波形对比
光看一个波形不过瘾。我们来个多图对比,看看占空比从10%到90%的变化。
import numpy as np
import matplotlib.pyplot as plt
frequency = 50
period = 1 / frequency
amplitude = 3.3
duty_cycles = [0.1, 0.3, 0.5, 0.7, 0.9]
fig, axes = plt.subplots(5, 1, figsize=(10, 8))
t = np.linspace(0, 3 * period, 1500)
for idx, duty in enumerate(duty_cycles):
pwm = np.zeros_like(t)
for i, time in enumerate(t):
pos = time % period
pwm[i] = amplitude if pos < duty * period else 0
axes[idx].plot(t * 1000, pwm, 'b-', linewidth=1.5)
axes[idx].set_ylabel(f'D={duty*100:.0f}%')
axes[idx].set_ylim(-0.5, amplitude + 0.5)
axes[idx].set_yticks([])
axes[idx].grid(True, alpha=0.2)
axes[-1].set_xlabel('Time (ms)')
plt.suptitle('PWM Waveforms at Different Duty Cycles', fontsize=14)
plt.tight_layout()
plt.show()
跑完这段代码,你会看到5个波形从上到下排列。占空比10%的时候,脉冲窄得像一根针;占空比90%的时候,脉冲宽得几乎占满整个周期。
我记得第一次做按摩仪原型时,就是靠这个图来跟硬件工程师沟通的。我说「我要30%的力度」,他一看图就明白了。说白了,波形图就是工程师之间的通用语言。
3.4 频率对波形的影响
占空比决定了「量」,频率决定了「质」。频率太低,电机会一抖一抖的,像在打嗝。频率太高,MOS管开关损耗会变大,发热严重。
来看看不同频率下的波形:
import numpy as np
import matplotlib.pyplot as plt
duty_cycle = 0.5
amplitude = 3.3
frequencies = [20, 50, 100, 200]
fig, axes = plt.subplots(4, 1, figsize=(10, 8))
t = np.linspace(0, 0.1, 2000) # 固定100ms时间窗口
for idx, freq in enumerate(frequencies):
period = 1 / freq
pwm = np.zeros_like(t)
for i, time in enumerate(t):
pos = time % period
pwm[i] = amplitude if pos < duty_cycle * period else 0
axes[idx].plot(t * 1000, pwm, 'b-', linewidth=1.5)
axes[idx].set_ylabel(f'f={freq}Hz')
axes[idx].set_ylim(-0.5, amplitude + 0.5)
axes[idx].set_yticks([])
axes[idx].grid(True, alpha=0.2)
axes[-1].set_xlabel('Time (ms)')
plt.suptitle('PWM at Different Frequencies (D=50%)', fontsize=14)
plt.tight_layout()
plt.show()
你看,20Hz的时候,100ms内只有2个脉冲;200Hz的时候,100ms内有20个脉冲。脉冲越密集,电机运转越平滑。
避坑指南: 我曾经把频率调到500Hz以上,结果电机嗡嗡响,手摸上去发烫。后来查资料才知道,按摩仪电机的最佳频率范围是20-200Hz。低于20Hz会有明显抖动,高于200Hz效率下降。记住这个范围,少走弯路。
3.5 占空比与平均电压的关系
最后,我们来验证一下核心公式:平均电压 = 峰值电压 × 占空比。
import numpy as np
amplitude = 3.3
duty_cycles = np.linspace(0, 1, 11)
print("占空比 | 理论平均电压 | 实际平均电压")
print("-" * 40)
for duty in duty_cycles:
# 模拟一个周期的PWM信号
samples = 1000
t = np.linspace(0, 1, samples)
pwm = np.where(t < duty, amplitude, 0)
avg_voltage = np.mean(pwm)
theoretical = amplitude * duty
print(f"{duty*100:5.0f}% | {theoretical:5.2f}V | {avg_voltage:5.2f}V")
运行结果:
占空比 | 理论平均电压 | 实际平均电压
----------------------------------------
0% | 0.00V | 0.00V
10% | 0.33V | 0.33V
20% | 0.66V | 0.66V
30% | 0.99V | 0.99V
40% | 1.32V | 1.32V
50% | 1.65V | 1.65V
60% | 1.98V | 1.98V
70% | 2.31V | 2.31V
80% | 2.64V | 2.64V
90% | 2.97V | 2.97V
100% | 3.30V | 3.30V
完美吻合。这说明什么?说明PWM控制电压是线性可调的。你想想看,按摩仪要多大力度,直接算占空比就行,多方便。
好了,这一讲的核心内容就这些。总结一下:
- 占空比控制「量」,频率控制「质」
- 按摩仪电机频率建议20-200Hz
- 占空比不要超过90%,留散热余量
- 平均电压 = 峰值电压 × 占空比,线性关系
下一讲,我们会用树莓派的GPIO口实际输出PWM信号,让电机真正转起来。到时候你会看到,代码里调一个数字,电机转速就跟着变,那种掌控感,很爽。
公众号:蓝海资料掘金营,微信deep3321