【发布时间】:2017-06-13 13:37:34
【问题描述】:
我正在构建一个设备来检测环境噪声的变化,使用 Arduino 并用 C 语言编写。
因为声音传感器每秒都会给我一个声级,我如何在不存储所有连续数据的情况下找到近似的中值?确定当前环境噪音水平发生变化的最佳方法是什么?
【问题讨论】:
-
你能告诉你要从多少输入中找到中位数。
-
@Billa 可能是无限的,因为除非设备关闭,否则每秒都会有一个输入
我正在构建一个设备来检测环境噪声的变化,使用 Arduino 并用 C 语言编写。
因为声音传感器每秒都会给我一个声级,我如何在不存储所有连续数据的情况下找到近似的中值?确定当前环境噪音水平发生变化的最佳方法是什么?
【问题讨论】:
听起来你想要的称为移动中位数(非常类似于moving average)。这将是您需要将最后一个 n 值存储在数组中并计算中位数的时候。
这就是它的样子:
int data[5] = {0, 0, 0, 0, 0};
int dataI = 0;
int sortedData[5] = {0, 0, 0, 0, 0};
void pushNewData(int d) {
data[dataI] = d;
dataI++;
if(dataI > 4) {
dataI = 0;
}
}
int median() {
for(int i = 0; i < 5; i++) {
sortedData[i] = data[i];
}
// Use a sorting algorithm here to sort sortedData
return sortedData[3];
}
另一方面,如果您想获得数百小时数据的中位数,则必须存储每个数据值。如果这是您的用例,我强烈建议您改用平均值。由于平均值只是 sum / n,因此您只能有两个变量并将它们相加。当然,你必须考虑溢出。
假设您仍然需要中位数(例如,如果您担心数据不对称或担心异常值)。在这种情况下,您可以轻松构建直方图并使用它来估计中位数。
你可以通过创建一个整数数组来做到这一点。索引 0 将用于值 0-5,索引 2 将用于值 6-10,依此类推。 (每个值范围的大小会根据您的设置而有所不同。)每次进入新数据点时,您将检查该点落入哪个“桶”(值范围),并增加该数组中的相应计数器。
根据这些数据很容易估算出您的中位数。假设您提取了这些数据:
Values 00-05: 1
Values 06-10: 7
Values 11-15: 8
Values 16-20: 2
Values 21-25: 1
Values 26-30: 5
由于 n = 24,中位数为 n=12。第 12 个数据点将在 11-15 范围内,因此您的中位数将在 11 到 15 之间。
您可以轻松地使用 3 或 1 来代替 5 的范围,但效果相同。请注意溢出和内存使用:除了确保不使用太多存储桶之外,还应使用无符号长数组。
【讨论】:
搜索“查找运行中位数”。先搜索stackoverflow。有多种方法,它们的适用性取决于数据的已知特征。
一种简单的方法是创建一个整数数组,例如 20 个等范围的元素。在获取每个样本时,将值映射到范围集,并将该计数器加 1。完成后,可以分析计数器值以计算近似中位数。
您可能需要尝试几种不同的方法以确定最适合您的方法。
【讨论】: