实验设计原则:控制变量与重复性

做物理实验的人,最容易犯的错是什么?

我个人的经验是——以为自己在测同一个东西,实际上每次测的都不是同一回事。你明明调了初速度,结果连环境温度、夹具松紧、数据采集频率全变了,最后出一堆数据,谁都解释不了。

这一章,我们专门聊两个基本原则。你把这俩搞透了,后面的重复性评估才有根基。

为什么控制变量这么重要

说白了,实验的核心逻辑就是「只变一个,其他全锁死」。

如果你同时改了初速度和采样率,测出来的数据抖了,你根本分不清是谁在捣鬼。我在项目中遇到过最典型的一个案例——团队测一个滑块在不同初速度下的停止位置,结果数据乱成一锅粥。查了两天,发现是每次测试前导轨上的油膜没擦干净,摩擦系数都不一致。初速度再准也没用。

避坑指南:我曾经因为赶进度,同时调了两个参数,结果花了三周才把数据洗明白。从那以后,我所有实验都强制用「变化清单」——一张表,写清楚本轮变了什么,没变什么。

控制变量,具体要锁哪些?我建议至少管住这四类:

  • 环境变量:温度、湿度、气压、振动。特别是精密测量,温差一度,结果可能差好几个百分点。
  • 设备状态:供电电压、传感器校准值、夹具松紧度、线缆屏蔽。每次开机后先预热15分钟,别问为什么。
  • 操作流程:触发时机、采集时长、数据处理参数(滤波系数、采样率)。写成SOP,每一步都不能跳。
  • 数据后处理:异常值剔除规则、平滑方法、截断逻辑。这些在处理阶段锁死,别今天用中位数明天用均值。

你想想看,我们做的重复性评估,本质上是评估「相同条件下的测量一致性」。如果条件没锁住,评估的前提就不成立。

重复性:到底在重复什么

重复性,不是一个玄乎的概念。它是个工程指标。

定义很朴素:同一操作者,同一设备,同一方法,在短时间内对同一被测对象进行多次测量,结果的一致程度。

嗯,这里要注意——「同一对象」不是同一批零件里的两个。是同一个物理对象。你在同一个导轨上、用同一个滑块、同一个光电门,重复放100次,这才叫重复性。换一个滑块,那叫再现性,指标含义完全不同。

我个人的习惯:每次重复实验前,先做一轮「空跑」。就是不记录数据,只让系统跑几遍,让机械部件、传感器、信号链都进入稳定状态。空跑完再正式记录。这一步,帮我省了无数查数据的时间。

重复性评估,通常看三个统计量:

指标 含义 怎么算
标准差 σ 测量值的离散程度 各次测量值与均值偏差平方和的平方根
相对标准差 RSD 离散程度相对于均值的大小 σ / 均值 × 100%
极差 R 最大值与最小值的跨度 max - min

这三样,你每次算重复性都得列出来。光给平均值没意义。平均值漂亮、标准差炸裂,那叫表面功夫。

控制变量与重复性的关系图

我画了一张流程图,帮你把这套逻辑串起来。你照着走,不会乱。

控制变量与重复性评估流程图 实验目标设定 控制变量:锁定环境 / 设备 / 流程 / 后处理 重复测量 n 次(建议 n ≥ 30) 计算 σ / RSD / 极差 → Grubbs 检验异常值 结果判定:合格 / 不合格 说明:每个节点都靠前一个节点的输出。控制变量没锁住,重复性数据就是废的。 异常值剔除次数最多 1 次,且不得超过总样本数的 5%

实际操作中,我建议你按这个顺序来

  1. 写一份「变化清单」:本轮实验,自变量是什么(初速度),因变量是什么(停止位置 / 时间)。其余所有能变的东西,全列在「不变」那一栏。
  2. 做一次预实验:跑 5 个点,看数据毛不毛。如果标准偏差已经大到你不敢相信,先排查控制变量,别硬着头皮跑满 100 次。
  3. 正式采集时锁定采样参数:
# 示例:Python 中锁定数据采集参数
SAMPLE_RATE = 1000  # Hz,固定不变
ACQUISITION_TIME = 2.0  # 秒,每次采集长度固定
PRE_TRIGGER_SAMPLES = 100  # 触发前样本数,锁死
POST_TRIGGER_SAMPLES = 1900  # 触发后样本数,锁死

这些参数写死在代码里,每次跑实验之前 check 一遍。我习惯把它们写进一个配置文件中,实验开始前 load 一次。这样万一有人手滑改了,配置会报错。

核心要求:重复性评估,必须建立在「控制变量已锁定」的前提下。在报告中,你必须有一个章节专门说明「哪些变量被控制,控制方法是什么」。没有这一步,审稿人或者技术评审直接退回。

重复性实验的统计工具链

我自己常用的工具,基本上三段式:

  • 描述统计:均值、中位数、标准差、极差
  • 异常值检测:Grubbs 检验(单异常值)或 ESD 方法(多异常值)
  • 可视化确认:箱线图 + 概率图

这里贴一段我常用的 Grubbs 检验脚本,你直接改数据就能用:

import numpy as np
from scipy import stats

def grubbs_test(data, alpha=0.05):
    mean = np.mean(data)
    std = np.std(data, ddof=1)
    n = len(data)
    
    # 计算每个点与均值的偏差
    residuals = np.abs(data - mean)
    max_residual = np.max(residuals)
    
    # 计算 G 值
    G = max_residual / std
    
    # 查临界值
    t_crit = stats.t.ppf(1 - alpha/(2*n), n-2)
    G_crit = ((n-1) / np.sqrt(n)) * np.sqrt(t_crit**2 / (n - 2 + t_crit**2))
    
    return G > G_crit, np.argmax(residuals)

# 使用
data = [10.02, 10.01, 10.03, 10.02, 10.04, 10.01, 10.03, 10.05, 10.11]
is_outlier, idx = grubbs_test(data)
print(f"是否有异常值: {is_outlier}, 索引: {idx}")

提示:异常值不能无限制剔除。我个人的规矩是——最多剔除 1 次,且剔除点数不超过总样本的 5%。你想想看,如果数据需要踢掉 10% 才能满足重复性要求,那说明控制变量出了问题,而不是数据有问题。

重复性评估报告的骨架

每次提交实验报告,我建议至少包含这五个部分:

部分 内容
1. 变量控制声明 列出所有被控制的变量及其控制方法,附原始配置参数
2. 原始数据表 n 次测量的原始值,不允许隐藏或截断
3. 统计指标 均值、标准差、RSD、极差、95% 置信区间
4. 异常值处理记录 剔除点数、剔除依据、剔除前后的指标对比
5. 结论 重复性「合格」或「不合格」,附判定阈值

这份骨架,我用了十几年。不管是发论文还是做内部评审,只要按这个结构写,基本不会被人挑出硬伤。

最后一句

控制变量不是束缚,是保护。重复性不是吹毛求疵,是在帮你堵住数据中的炸弹。这一章节的内容你吃透了,后面关于不同初速度下的对比分析,就只是个数学问题了。