第 008 篇

周末小记

约 4 分钟 1720 字 Markdown写作项目笔记
两种频率叠加形成的合成信号波形,横轴为时间,纵轴为幅度
两种频率叠加形成的合成信号波形,横轴为时间,纵轴为幅度

设想一个不需要赶进度的周末:给自己做一本小小的声音笔记。第一版不碰复杂设备,只生成一段合成信号,把思路、代码和结果放在同一页里。

这个项目的目标很克制:做出能够复现的一小步,并且让几个月后的自己还能理解它。写下来,也是实验的一部分。

出发前,先给项目减负

最初的念头可能是做一个完整的音乐分析平台。换成“画出两个正弦波叠加后的曲线”,事情就容易开始了。

好笔记不只是记录答案,也记录当时在问什么。

当结果不符合预期时,原来的问题往往比最后一张图更值得保留。

这次给自己留三条边界:

  • 使用合成数据,避免把环境噪声当成算法问题。
  • 保存参数,保证下次能生成同一段信号。
    • 采样率写清单位。
    • 样本数量与观测时长分开记录。
  • 每张图旁边都解释它能说明什么。

计划里也可以保留尚未完成的事:

  • 写出合成信号的定义
  • 画出时域波形
  • 核对两个已知的频率分量
  • 换一段真实录音
  • 比较不同窗函数对频谱的影响

打勾代表这一份演示记录已经验证的步骤。没打勾的项目,就是后续可以继续探索的方向。

把参数摆在桌面上

先列出本次实验用到的设置。右侧的数字对齐后,也更容易发现单位有没有写错。

参数 记号 本次取值
采样率 fsf_s 128 Hz
样本数量 NN 128
第一分量频率 ν1\nu_1 5 Hz
第二分量频率 ν2\nu_2 12 Hz
第二分量幅度 a2a_2 0.5

信号定义为:

x(t)=sin⁡(2π⋅5t)+0.5sin⁡(2π⋅12t).x(t)=\sin(2\pi\cdot5t)+0.5\sin(2\pi\cdot12t).

采样点是 tn=n/fst_n=n/f_s,其中 n=0,…,N−1n=0,\ldots,N-1。本例的 DFT 观测时长按 N/fsN/f_s 计算为一秒;最后一个样本的时间戳则是 127/128127/128 秒,两个说法并不矛盾。

先听问题,再看曲线

这里的“听”是一种提醒:先决定自己想观察什么,再选择图表。这个示例只使用低频合成信号来说明计算,不把它当成真实乐器或人声。

半秒钟内的合成波形:较慢的起伏上叠加了较快的振动

图里的纹理来自两个已知分量的叠加。它可以帮助理解时域形状,却不能仅凭肉眼精确读出所有频率。想继续拆解,可以接着读傅里叶变换那篇笔记。

让过程有一个明确顺序

  1. 生成时间坐标。
  2. 分别计算两个正弦分量。
  3. 把它们相加,并保留原始样本。
  4. 计算频谱,核对已知的频率。
  5. 最后才考虑真实数据里的复杂情况。

把步骤排成顺序,比在正文里反复使用“然后”更容易查找。

一个足够小的实现

核心计算可以很短:

import numpy as np

fs = 128
t = np.arange(128) / fs
slow = np.sin(2 * np.pi * 5 * t)
fast = 0.5 * np.sin(2 * np.pi * 12 * t)
signal = slow + fast

写代码时,变量名 signal 比 a 更能提醒后来者它代表什么。代码块负责保留缩进;正文里的行内代码则用来点出某个具体名字。

让一条检查跟着代码留下来

可以在笔记里保存一个简单的断言:

assert signal.shape == (128,)
assert np.isclose(np.mean(signal), 0.0)

这个零均值检查适用于当前选定的完整周期示例。换一个截取区间以后,就不能机械地要求它依旧为零。

再留一条给未来自己的提醒

保存结果时,也记下软件版本。下面是一条查看环境的命令,不需要把安装过程混进分析结论:

python -c "import numpy; print(numpy.__version__)"

六级标题只适合真正需要分层的细节。多数笔记到二级或三级标题就足够;这里把实验、实现、检查和提醒依次展开,方便沿着思路回看。


一张图,还需要一段解释

如果只留下一张曲线,时间一长很容易忘记它来自哪组参数。图后面最好跟上几句话:数据从哪里来,处理了什么,哪些现象符合预期。

这份示例使用的是确定的合成数据。若需要记录离散样本的均方值,可以使用:

E=1N∑n=0N−1∣xn∣2.E=\frac1N\sum_{n=0}^{N-1}|x_n|^2.

对当前这组完整周期、彼此正交的正弦分量,有:

E=122+0.522=0.625.E=\frac{1^2}{2}+\frac{0.5^2}{2}=0.625.

这给频谱之外增加了一个独立的数值检查。它是本例有限序列的均方值,不能脱离采样和定义,直接当成任意实际声学系统的物理能量。

参数、代码与解释一起留下来,笔记才比较完整。漂亮的图并不会自动替代清楚的实验条件。

给资料留一条找得回去的路

外部资料可以写成有名字的链接,也可以直接保留地址:https://numpy.org/doc/stable/reference/routines.fft.html。

当正文不想被长网址打断时,就用编号引用。NumPy 文档中对 DFT 的符号、频率顺序和归一化方式都有说明。[1]

还可以把常用链接统一定义在文末,例如这个项目首页。如果笔记模板需要一个联系地址,可以先写成示例地址 hello@example.com,等真正使用时再替换。

展开查看本次实验的简短复盘

最有用的选择,是从已知答案的合成信号开始。这样出现异常时,可以先检查代码、采样与归一化,而不用同时猜测录音环境。

下一步可以比较整数周期与非整数周期的截取结果,再研究加窗带来的变化。

留白、换行和一些小细节

有些内容适合换行但不另起一个段落。比如给当天的记录留两行:

第一行:先把一个小问题算明白。
第二行:再把计算条件写清楚。

写字面符号时,可以转义星号:*这句话保留星号*。写示例价格时,也可以用 $5 和 $10,避免把美元符号误当成公式的边界。

在表格里记录竖线,要记得转义:

记录项 示例
选择分隔符 A | B
删除旧计划 先搭平台
保留关键结论 先验证最小示例

如果要展示 Markdown 本身,外层可以使用更长的代码围栏:

## 一段小笔记

- 先记录问题
- 再留下证据

```python
print("hello, notebook")
```

这些小约定减少的是未来重新理解的成本。周末项目未必需要一个庞大的结尾;留下能运行的代码、能解释的图,以及一个清楚的下一步,就已经值得把这一页保存下来。

资料

  1. NumPy 的离散傅里叶变换文档

评论

还没有评论。 来写第一条。

留下一条评论

选填,不会公开

纯文本,链接会自动识别。