简单分解帮助看清复杂问题

提出问题

  提问:卓大大,我想问一下,这个低通滤波重要性很大吗,如果不加的话,方波出来的不就是直流电了吗?我用万用表测加LC和不加LC测出来的电压是一样的,可以解释一下低通滤波的必要性在哪吗?


半桥PWM输出电路 | 图来自“如何将大象装进冰箱”推文插图

  提问:卓大大,我有一个想法,将电池电压升高,然后采用pwm调制,保证在常规调制时,电机上的电压达到额定电压,这样电机就有较高的转速。这样做是否合理?


图 | 来自于网络

  上面都涉猎到关于输出PWM(Pulse Width Modulation:脉宽调制)信号问题。应用信号与系统中信号分解的概念则相对比较容易回答上面的问题,并看清问题的本质,指导电路设计。

原理分析

一、信号的分解

  对与复杂的分析对象进行适当分解,可以省略对于问题不起作用的分量,抓住问题问题的矛盾。这个方法在很多学科中都有应用。比如下图所示的物体斜坡受力分析既如此。


斜坡物体受力运动分析 | 图来自“信号与系统”课件

  在所有的分解方方式中,正交分解可以保证分解前后的信号在能量方面守恒。

  对于信号也有很多分解的方式。例如将信号分解成直流和交流、偶分量与奇分量、脉冲分解、谐波分解、实部与虚部分解等。将信号分解成直流和交流分量就是常用到的分解方式。

  直流分量是信号的平均值。如果信号是周期信号,则直流分量定义为信号在一个周期内的积分除以周期。如果信号为非周期信号则取一段时间内的平均值在时间长度趋向于无穷大的时候的极限。信号的交流分量等于信号减去其直流分量。


  信号的直流与交流分解

  信号的直流分量与交流分量是正交的,即它们的功率和等于原来信号的功率。由此可以方便将来理论上通过已知信号的功率和测量得到的直流功率,计算出交流分量的功率。

二、PWM信号的直流与交流分解

  PWM信号是一个周期信号,在一个周期内,信号的取值为两个固定值。例如对于单极性PWM信号,两个值分别是0,E;对于双极性的PWM信号,两个值分别是E,-E。定义高电平在一个周期内所占的比例为占空比Duty。


  单极性PWM信号


  双极性PWM信号

  如果已知PWM波形的占空比以及峰峰值,便可以求出PWM信号的直流分量的大小。直流分量与占空比之间呈现线性函数关系。该直流分量与PWM信号的频率f(周期T)没有关系。

  直流分量比较容易计算得到,再根据直流功率加上交流功率等于原始信号的功率,可以近而分析出相应的交流分量的功率及其有效值。

三、惯性(低通)系统

  大部分动态系统都有储能环节,例如电机中的转子的存储机械动能;电枢中电感存储电磁能;RC电路中的电容存储电能。这些储能环节存在使得系统对于输入信号存在平滑作用:即对于快速变化的信号被极大的削弱;对于变化缓慢的信号(特别是直流信号)则能够进行放大传出。

  电机内的电枢以及转子

  例如,施加在直流电机上的交流信号,如果信号的频率比较高,在电机的电枢电感的平滑作用下,所产生的交变电流就会很小。这些交变电流所产生的力矩表现为震动作用,在转子以及传输结构中的机械惯性的作用下,输出的平均力矩为零。真正使得直流电机持续转动的是施加信号中的直流分量。

  万用表是一个可以测量多种电气参数的仪表。它在测量直流电压量的时候,会对输入信号进行低通滤波,去除信号中的交流干扰信号,保留信号中的直流分量。所以使用万用表测量PWM输出信号的时候,可以直接读出其中的直流量的大小。

问题解释

  第一个问题中,对于输出PWM信号是否需要LC低通滤波提出了质疑。理由是使用万用表测量LC前后的电压是一样的。

  根据电路原理中的分析,LC是一个二阶低通滤波器,即电气的惯性环节。它可以大大衰减交流信号,对于直流信号没有损失。所以在LC之前是PWM信号,在LC之后则只有PWM的直流分量,PWM交流分量被滤除。

  由于万用表的直流电压档只能测试信号中的直流分量,所以在LC前后的信号是分辨不出来的。使用万用表的交流电压档再对LC前后的电压信号测量,就会发现,LC滤波器具有很大的交流信号;在LC滤波后交流信号几乎为0.


  用于滤波的大电流电感

  LC的作用是滤除PWM中的交流分量,为后面直流用电电路,或者储能充电电路提供可调的直流电压。如果不加LC滤波,PWM信号中交流分量会对后面的直流用电电路产生很大的干扰。如果直接用于后面储能电容的充电的话,由于电容对于交流分量的阻抗比较低,PWM中的交流电压信号会产生非常大的交流电流,这会烧坏前面的PWM电路。

  所以在上面半桥充电电路中必须增加LC的滤波电路。为了减少滤波电路对于输出直流分量的衰减,其中的电感需要使用内阻小,大电流的电感。

  对于第二个问题的分析,可以知道,作用在电机运行力矩是PWM波形中的直流分量,与交流分量没有关系。所以无论驱动电路的工作电压多大,即输出的PWM的峰峰值多高,只要通过调整占空比使得输出的平均电压相同,所产生的电机力矩就相同。因此,不需要对电池进行升压。


  使用PWM信号驱动车模电机

  额外增加了电池升压电路还会带来额外的功率损失,增加驱动电路的输出阻抗。这远不如直接将电池接在驱动电路上所能够提供的电流强大。因此额外电池升压对于车模是画蛇添足。

实验验证

实验1:使用万用表测量PWM波形的直流分量和交流分量

  使用万用表的直流和交流电压档测量已知PWM信号,验证前面信号分解理论。

  应用电机驱动芯片MC33886输出频率为2kHz的单极性PWM波形。MC33886供电为8V,因此PWM输出波形峰值为8V左右。PWM的占空比为50%左右。根据前面分析,此时信号的直流分量应该为4V左右。


  实验电路以及输出的PWM波形

  使用FLUKE万用表的直流电压档测量PWM波形,显示测量的输出值为3.988V, 这与理论分析数值十分接近。


  动图 测量PWM波形的直流分量,与理论值很接近

  使用FLUKE表的交流电压档测量上述PWM波形的交流分量。信号的交流分量的功率加上直流分量的功率等于信号的总功率,经过理论分析可以知道对于实验中50% 占空比的PWM信号,其交流分量的有效值也应该等于4V。此处省去分析过程。

  但实际FLUKE万用表显示的交流有效值为4.42V,与理论值相差10% 左右。这是由于普通的手持万用表的交流档是按测量正弦波来从峰值测量推算出信号的有效值,不是真有效值测量,所以产生了较大的误差。更换台式的真有效值交流表重新测量上述PWM的交流信号,测得数值为3.998V,与计算值非常接近。


  使用万用表交流档测量PWM的交流信号,与理论值有10%的误差

实验2:观察PWM直接联系电容滤波效果

  提取PWM波形的直流分量,需要滤除其中的交流分量。是否可以将LC电路中的比较笨重的电感去掉呢?

  实验中,直接将输出的PWM信号使用一个1000uF的电容进行滤波。通过红外摄像头,观察输出电路的功率集成芯片的温度变化。


  实验电路的红外温度图像

  开始的时候,电容的一个管脚与电路是分开的。电路通电后,手将1000uF的电容管脚按在输出PWM焊盘上,此时可以看到电路供电的限流稳压直流电源以及处于输出电流饱和状态。下图显示输出MC33886集成芯片的温度急剧上升。


  输出PWM直接使用电容滤波造成电路发热

  提取PWM信号的直流分量,不能够直接将滤波电容加载PWM输出信号上。由于电容对于交流信号是低阻,PWM信号中的交流电压分量会在电容上产生大的交流电流,造成输出电路过热损坏。


  为了限制交流电流,需要使用电感限制。这里的电感也成为平波电感,取其将输出PWM交变电压进行平滑之意。显然,L取值越大,交流电流就越小,造成电能损耗就越小。由于实际电感总是存在着直流电阻,随着绕行越多,直流电阻就会增加。所以电感值需要根据实际电感绕行阻抗、PWM频率以及电容容值进行折中取值。

延伸讨论

  前面讨论了赛车车模上的直流电机,如果使用升压电路为它提供电源实际上是画蛇添足。但是在实际电动汽车中,往往为了提高电机的效率而采用升压电路为电机驱动提供高压电源。虽然其中的DCDC升压电路到来一定的功率损失,但汽车整体效率上还是提高了。


电动汽车电池配置 | 图来自于网络

  在PWM驱动直流电机时,虽然其中交流分量对于转动力矩没有什么贡献,但它所产生的震动有时会减少电机在静态时的摩擦力。特别在直立车模平时状态时,电机低速正反运行。减少静态摩擦力会减少系统非线性成分对控制的影响。

  PWM频率理论上越高,在后期进行滤波的时候,所需要的L,C的数值就会越低,进而减小元器件的体积,驱动电机时,所产生的震动噪声也越小。但是PWM频率提高,也会在功率输出级产生很大的开关损耗。有的电路芯片规定了PWM最高频率,比如MC33886要求输出频率不得高于10kHz。过高的PWM频率也会使得输出电路的电流输出能力下降。

<think>好的,用户想实现汉诺塔的可视化,用编程语言来实现。首先,我需要回忆一下汉诺塔问题的基本解决方法和递归过程。汉诺塔的递归算法通常是将n个盘子从A柱移动到C柱,借助B柱作为辅助。每次移动分为三步:移动n-1个盘子到中间柱,移动最大的盘子到目标柱,再将n-1个盘子从中间柱移动到目标柱。 用户提到可视化,所以需要考虑如何将这个过程用图形展示出来。根据用户提供的引用,有Python和Java的例子。比如引用[3]提到用Python的turtle库来实现动画效果,而引用[2]是Java的Swing程序。用户可能更倾向于Python,因为问题里提到了Python的例子,但需要确认。 接下来需要确定使用哪种编程语言和图形库。Python的turtle库适合初学者,可以绘制简单的动画。另外,也可以考虑使用Pygame或者Tkinter来创建更复杂的界面。Java的话,可以用Swing或JavaFX,但用户提供的引用中有Java代码,可能用户也考虑过Java。不过根据用户提供的示例中的Python代码,可能更倾向于Python。 然后是步骤分解:首先需要实现汉诺塔的递归算法,并在每次移动时触发界面更新。每次移动时,需要记录盘子的位置,并在图形界面中更新它们的位置。例如,在Python中,可以使用turtle的图形绘制功能,每次移动时移动对应的图形对象。 需要注意的难点包括:如何将递归步骤与图形渲染结合,如何控制动画的速度,以及如何表示不同大小的盘子。例如,可以用不同长度的矩形表示盘子,颜色区分不同层。每次移动时,需要将盘子从当前柱子移动到目标柱子的顶部,这涉及到坐标的计算。 根据引用[3],使用turtle库需要初始化窗口,设置柱子的位置,绘制柱子,然后为每个盘子创建turtle对象,记录它们的初始位置。在移动时,将盘子抬起,移动到目标柱子的顶部,再放下。同时需要控制移动的速度,以便观察动画效果。 此外,递归过程中需要在每次移动后调用图形更新函数,可能需要使用延迟函数如time.sleep()来减缓速度,让用户看清移动过程。另外,可能需要使用栈结构来记录每个柱子的当前盘子状态,以方便绘制。 另一个考虑是用户可能对编程语言的熟悉程度。如果用户更熟悉Java,可以参考引用[2]中的代码结构,使用Swing组件来绘制柱子,并在移动时更新GUI组件的位置。但Java的实现可能比Python复杂一些,尤其是线程和图形更新的处理。 总结步骤: 1. 实现汉诺塔递归算法,并在每次移动时触发图形更新。 2. 使用图形库绘制柱子,初始化盘子的位置。 3. 在每次移动时,更新盘子的图形位置,形成动画效果。 4. 控制动画速度,确保可视化过程清晰可见。 可能的问题包括:图形库的选择、坐标计算、动画同步等。需要根据用户提供的引用和示例代码,给出具体的实现步骤和代码示例,帮助用户完成可视化。</think>实现汉诺塔可视化需要结合递归算法与图形界面编程,以下是分步实现思路和示例(以Python为例): --- ### 一、实现步骤 1. **递归算法框架** ```python def hanoi(n, source, target, auxiliary, move_disk): if n > 0: hanoi(n-1, source, auxiliary, target, move_disk) move_disk(source, target) # 关键:移动时触发图形更新 hanoi(n-1, auxiliary, target, source, move_disk) ``` 2. **图形界面设计** - **柱子绘制**:固定三个垂直柱子的位置 - **圆盘绘制**:用不同宽度/颜色的矩形表示不同层级的圆盘 - **动画效果**:使用`turtle`库的平滑移动函数实现动画过渡[^3] --- ### 二、Python完整示例(基于turtle库) ```python import turtle import time # 初始化画布 screen = turtle.Screen() screen.setup(800, 600) screen.title("汉诺塔可视化") # 初始化柱子位置和圆盘数据 towers = {"A": [], "B": [], "C": []} poles = {'A': -200, 'B': 0, 'C': 200} def setup_towers(n): # 绘制柱子 t = turtle.Turtle() t.speed(0) for x in poles.values(): t.penup() t.goto(x-10, -150) t.pendown() t.goto(x+10, -150) t.goto(x, -150) t.goto(x, 100) # 初始化圆盘 for i in range(n, 0, -1): disk = turtle.Turtle() disk.shape("square") disk.shapesize(1, i*1.5) # 宽度随层级变化 disk.color("blue") disk.penup() disk.goto(poles['A'], -140 + 20*(n-i)) towers['A'].append(disk) def move_disk(source, target): disk = towers[source].pop() # 抬起圆盘 disk.goto(poles[source], 100) time.sleep(0.3) # 横向移动 disk.goto(poles[target], 100) time.sleep(0.3) # 放下圆盘 y_pos = -140 + 20*len(towers[target]) disk.goto(poles[target], y_pos) towers[target].append(disk) time.sleep(0.5) # 启动程序 setup_towers(5) hanoi(5, 'A', 'C', 'B', move_disk) turtle.done() ``` --- ### 三、关键实现细节 1. **坐标计算**:通过`poles`字典存储三根柱子的x坐标,y坐标根据当前柱子上已有的圆盘数量动态计算 2. **动画时序**:通过`time.sleep()`控制移动步骤的间隔时间,保证动画可见性 3. **状态同步**:`towers`字典实时记录每个柱子上的圆盘对象,确保逻辑状态与图形状态一致 --- ### 四、优化方向 1. **交互控制**:添加滑动条调节动画速度 2. **颜色梯度**:使用HSV颜色空间生成渐变色圆盘 3. **步骤回放**:记录移动历史实现回退功能 4. **3D渲染**:改用`pygame`或`OpenGL`实现三维效果 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卓晴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值