0%

Useless Knowledge

Useless Knowledge

先叠甲,不是知识无用,只是对我来说用不上。纯当课外读物了解着玩,包括一些朋友对我作为计算机专业人士的神奇提问,和我觉得很离谱的新闻,我就想看看它是不是真的。

PWM 脉冲宽度调制

Pulse width modulation,https://en.wikipedia.org/wiki/Pulse-width_modulation

突然想到了大学实验课上的呼吸灯实验,联想起来自己还是不太理解当时为什么要那么写代码,所以这次来深度了解一下。当时只是知道代码写法,并不理解原理,现在才查到是PWM。

首先,PWM并不唯一,它可以用在很多地方,它本身的实现也很多,呼吸灯就是个简单实验而已。

模拟电路的缺点不多说了,总之是希望用数字电路来顶替模拟电路,但是数字电路的输出是高电平或低电平,而模拟电路的输出是连续的,可以是高低电平范围内的任何一个值,PWM就是来解决这个取值问题的。

硬件,比如LED灯,本来就是可以接收一个范围的电压,并给与相应的亮度,当然,此处还是理想地说,电压是稳定的一个值,LED就在那里亮着。如果LED接受的电压不是稳定的,是脉冲呢?假设脉冲很慢,1s高,1s低,我们就能看到LED在闪烁,但是如果脉冲很快,比如10ms高,10ms低,我们就看到LED是亮的,但是亮度不是100%,而是50%(10ms仅仅是个假设,我不知道具体什么频率才能让人眼看到,频率过快应该跟常亮没有区别)。100Hz应该就看不到闪烁了。这就是PWM呼吸灯的基础,PWM调光,PWM Dimming。

有了Dimming,我们可以在LED上实现各种亮度,比如50%,75%等等,只要每一小段时间变换亮度,就能实现呼吸灯。

那么,PWM Dimming具体什么样子?

可以想象,如果当前给一条高电平直线,我们看到的是常亮;如果直线中每个1s只出现1ms的低电平,那个时候LED肯定是熄灭的,但持续低电平时间太短了,人眼根本无法察觉,而且LED还可能有余晖,不会瞬间黑了,就更加容易掩盖熄灭的时间,也就是视觉残留。

但为何视觉残留,就能完美模拟出0-100%的亮度呢?我们为什么不能从50%空占比(Duty Cycle)中捕捉到那么一瞬的高于50%的亮度?这个从经验上有人总结过,就是说,人眼看到的是一种平均值,而不是瞬间的值,所以,如果LED的空占比是50%,那么人眼看到的就是50%的亮度,而不是瞬间的100%亮度。这个叫做Talbot-Plateau Law,中文名不统一,可能叫塔尔博特-普拉托定律。它是由实验支撑的,就是下图的黑白盘,又称扇形实验。

圆盘

圆盘的一个环和PWM调光的某个亮度是类似的,转起来后,我们人眼就是看到了一个平均值,而不是瞬间的值。背后的生物理论还不了解,但这个实验还是能让人理解,我们人眼确实是被这么骗了。

我们将这个定律作为前提条件,相信它,那么,可以得到下图所示的结论,我如果恒定频率,将会得到不同亮度。

PWM调光

顺带一提,PWM虽然骗过人眼感受,但实际还是让我们的眼部细胞被迫处理瞬时的变化。所以有些PWM频率过低,会让人眼睛类,甚至头疼。说起来,有些手机就是被人吐槽PWM频率过低,瞎眼睛。不知道为何,它们不适用高频,可能和功耗有关?

PWM调光,应该可以代码模拟一下。不知道电脑显示器的刷新频率是否会拖后腿,但先尝试一下吧。学校时期还真有单片机、arduino一类的开发板,和LED灯,目前就只能电脑模拟一下了。

首先看看能不能一步到位,Python中使用画图的工具,最终要能达到做动画的效果,限制为只使用某个亮度,那么它就作为本实验的100%亮度。比如matplotlib就可以做类似事情,而展示图片wsl也适配了,可以弹出图片框。但测试了一下频率,做不到人眼感受不到闪烁的程度,人眼还是牛啊。

那就只能做PWM波形了,这个用matplotlib画图,并不断更新图片就可以。假设这个生成程序可以用于控制LED硬件,它应该是可以设置频率和占空比,然后持续生成电平值的。我们就以这个角度来写代码,再找个方法做图片。

https://www.electronicwings.com/raspberry-pi/raspberry-pi-pwm-generation-using-python-and-c

但其实真正的硬件控制,是有些高度封装的。但为了好画图,我还是当作是set value的,而不是set frequency的。并且是持续输出,最大频率先定一个,一段时间为高电平,体现为很多个1。得到代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import matplotlib.pyplot as plt

resolution = 1000 # Hz
# 1 / resolution = 1ms 1 value in the list is 1ms

def pwm(freq, duty_cycle):
# gen a list of 0 and 1
period = int(1 / freq * resolution)
on = int(period * duty_cycle)
off = int(period * (1 - duty_cycle))
print(on, off)
while True:
for i in range(on):
yield 1
for i in range(off):
yield 0


data = []
for i in range(30, 100, 10):
gen = pwm(10, i / 100)
data += [next(gen) for j in range(1000)]
for i in range(100, 30, -10):
gen = pwm(10, i / 100)
data += [next(gen) for j in range(1000)]
# plot
xs = [x for x in range(len(data))]
print(len(data))
plt.plot(xs, data)
plt.show()
plt.close()

芯片制程

学校中曾经了解过一点皮毛,但我的速度已经跟不上2023年前后的芯片厂们了,怎么能2nm都出来,它不会失效么?而这一问题,还真有人问过我,那时我只记得它们是虚标,工艺是在进步但废片率也高,所以虽然说得很先进,但目前还不会变成产品到我们手上。

突然想起这事,想要了解多一点细节,比如哪里假了,为什么虽然假,还是可以这么命名。搜到很多营销号千篇一律的话,完全没有解释,只是说了一些芯片制程的历史,然后就说了一句,这是虚标。知乎上的回答才稍微找到一点靠谱的,我也读的不深入,此处也不引用了,免得我的错误解读曲解了知乎回答。

我就大致写下我想要了解的问题解释,不加太细节的名词,以免误导。

首先,最早的芯片是planar的,要往里塞更多单元,当然是把单元做的越来越小,这样就能让单位面积里密度越来越高。但当初并没有用密度来衡量芯片,而是用了单元的尺寸来描述。可能从硬件制作来讲,如何做出一个小的单元,才是工艺的最直接体现吧。造单元的时候,衡量它用密度也很奇怪。但进一步的,也就用这个尺寸来描述芯片了,我们并没去在意芯片有多大,有多少个单元,密度多少,而是用单元的尺寸来说这个芯片有多强。这里就是误解的第一步了。即使还是planar,制程的Xnm(应该一直是Gate Length吧,不知道有没有改变过指标,还需要订正,本文只做虚指)已经不代表单元的尺寸了,因为它比单元尺寸缩减地快。可能因为单元尺寸、制程尺寸都是在缩减,正相关。Gate好像跟耗电量也有关,功耗也是一个很重要的点。反正一通下来,可能没找着更合适的,就没有换。

第二步,设计革新,芯片不再是planar了,它变造型了,还开始立体叠甲了。从设计造型改变后,Gate尺寸大概可以理解为能直接缩的很小很小,这时候还用它当指标,当然就很明显不对了。你说你电脑超薄,结果是电脑的最边缘超薄(joke)。那么,它就开始是理论指标了。比如,新的芯片密度是随便什么面积单位下有100M个单元,那么它的制程就是换算成planar,如果planar设计下要5nm才能塞下这么多单元,我就叫5nm制程的芯片。根据好几个人的说法,是2012年22nm后开始无法标志实际尺寸,而是只能做等效计算的。

但既然都是等效制程了,为什么又出现了英特尔和吹水厂们两派?这个地方我还不确定,有空读一下图做一下计算。目前看来,是英特尔完全遵循等效计算法,但其他吹水厂又换了个玩法,就是摩尔定律坐标图。它们的下一代就一定是摩尔定律的下一个点,于是,16nm是某年的一代,我下一代进步了,只进步了一点点,但我一定要叫下一代的名字,也就是12nm/10nm。(摩尔是翻倍,那么芯片二维来看,面积变成上一代的0.5倍,等于边长变为上一代的0.7),所以16*0.7=11.2nm,反正都是虚假的了,向上取整向下取整随便来。这一招6啊,没有人比他们更懂摩尔。

这故事告诉我们营销的重要性,我身边的人不知道有多少人被这些名词忽悠了,还说某厂掌握核心科技,远超国外。太猛了,我解释了,但我感觉也并没有改变他的观点,因为他已经信了。

希望我能有一天负责任地夸奖国产芯片,主要是说热门的那些。(没有说全都不好的意思)