【问题标题】:Finding average of an array求数组的平均值
【发布时间】:2015-06-08 23:21:41
【问题描述】:

我真的很难从数组中找到加权和。 我有一个名为频率 [28] 的数组(一维大小 28)和一个名为 peak[28] 的相同大小的相同索引数组。数组总是有一个值或零。我想要实现的是遍历数组,从频率和幅度数组中检索两个值,同时忽略零。另外,我并不是要求整个数组的加权平均值。

我觉得我说得不够清楚。

比如说

frequency[n] = [0,0,0, a,b, 0,0,0, c,d,e, 0,0, f]
peak[n] = [0,0,0, z,y, 0,0,0, x,w,v, 0,0, u]

因此,我想忽略前三个箱,因为它们为零,并找到与 (z,y) 配对的 (a,b) 的加权平均值,然后忽略接下来的三个箱,然后再次找到 (c,d, e) 与 (x,w,v) 等配对。
请注意,我在数组中的值(大小是固定的)不是固定的。值可能出现的索引总是变化的。

我附上了检索数组的代码的 sn-p。 任何建议或指导都会有很大帮助!

// peak search
threshold = 0;
for (ctr=0; ctr<n1; ctr++)
{   
    peak[ctr] = 0; // initialise arrays
    freq_bin[ctr] =0;
    frequency[ctr] = 0;

    // magnitude calculation from fft output
    fft_mag[ctr] = 10*(sqrt((fft_output[ctr].r * fft_output[ctr].r) + (fft_output[ctr].i * fft_output[ctr].i)))/(n);
    threshold = 12; 
    if (fft_mag[ctr] >= threshold) // extract fft magnitudes only above threshold
    {
        peak[ctr] = fft_mag[ctr]; // store magnitude above threshold into peak array
        freq_bin[ctr] = ctr;        // location of each magnitude above threshold
        frequency[ctr] = (freq_bin[ctr]*(10989/n)); // frequency calculation from magnitude location        
    }
}

我很抱歉没有评论代码。

  • peak[ctr] 包含 fft 输出的峰值幅度
  • frequency[ctr] 包含相应 fft 峰值幅度的频率值。

我有多个来自 fft 的峰值,输出数组如下所示;

peak[28] =      [0 0 0 0 0 0 0 0 0 0  14 0 0 0 0 0 0  14 0 0 0  29  74   45 0 0 0 0]
frequency[28] = [0 0 0 0 0 0 0 0 0 0 462 0 0 0 0 0 0 714 0 0 0 924 966 1008 0 0 0 0]

因此,我需要计算:

  • 平均 1 = (14x462)/14 = 462 Hz
  • 平均 2 = (14x714)/14 = 714 Hz
  • 平均 3 = (29x924 + 74x966 + 45x1008)/(29+74+45) = 938.8 Hz

【问题讨论】:

  • 您能描述一下您的程序做错了什么吗?包括样本输入、预期输出和实际输出。编译和重现问题的实际程序也将帮助您获得答案。
  • 正如我在学校和尼克凯夫那里学到的:“零也是一个数字”(或一个值)。
  • 你真的需要解释一下peakfreq_binfft_magfft_output 数组的用途;您在问题中只提到了两个数组。我怀疑你需要两个数组索引。一是“输入”索引;你可以继续叫它ctr,它会保持不变。另一个可以叫out;您将其设置为零,并且仅当您在 if 语句主体中为 peak[out]freq_bin[out]frequency[out] 分配非零值时才递增它,在末尾添加 out++ 以递增 out当你有一个选择的价值。在循环之后,您将拥有包含值的元素 [0..out)。
  • 我刚刚详细阐述了这个问题。对不起,如果我让你感到困惑,我也很困惑。
  • 请研究如何创建一个 MCVE (How to create a Minimal, Complete, and Verifiable Example?) 或 SSCCE (Short, Self-Contained, Correct Example) — 两个名称和链接用于相同的基本思想。您仍然有未记录的变量(nn1fft_outputfft_magfreq_bin 等等),虽然我们可以对它们的含义做出有根据的猜测,但我们不应该这样做不得不猜测。也没有关于类型的文档。将threshold 设置为循环外部的0 和内部的12 似乎很奇怪。等等。

标签: c arrays algorithm average


【解决方案1】:

这里有一些近似于 MCVE (How to create a Minimal, Complete, and Verifiable Example?) 的代码。除其他外,我通过在非零数据集之前和之间留下一组零来压缩操作/有趣的数据。问题中 3 项加权平均值的计算似乎是错误的:

  • 平均 3 = (29x924 + 74x966 + 45x1008)/(29+74+45) = 938.8 Hz
  • 平均 3 = (26796 + 71484 + 45360) / 148
  • 平均 3 = 143640 / 148
  • 平均 3 = 970.54

这与程序的计算一致。

代码:

#include <stdio.h>

int main(void)
{
    enum { NUM_ENTRIES = 28 };

    /* Input data */
    double peak[NUM_ENTRIES] = { 0,  14, 0,  14, 0,  29,  74,   45, 0, };
    double freq[NUM_ENTRIES] = { 0, 462, 0, 714, 0, 924, 966, 1008, 0, };

    /* Output data */
    double bin_av[NUM_ENTRIES];
    int bin_lo[NUM_ENTRIES];
    int bin_hi[NUM_ENTRIES];
    int out = 0;

    int ctr = 0;
    while (ctr < NUM_ENTRIES)
    {
        /* Skip zeroed entries */
        while (ctr < NUM_ENTRIES && (peak[ctr] == 0.0 || freq[ctr] == 0.0))
            ctr++;
        if (ctr < NUM_ENTRIES)
        {
            bin_lo[out] = ctr;
            bin_hi[out] = ctr;
            double w_sum = 0.0;
            double f_sum = 0.0;
            while (ctr < NUM_ENTRIES && (peak[ctr] != 0.0 && freq[ctr] != 0.0))
            {
                bin_hi[out] = ctr;
                w_sum += peak[ctr] * freq[ctr];
                f_sum += peak[ctr];
                ctr++;
            }
            bin_av[out++] = w_sum / f_sum;
        }
    }

    for (int i = 0; i < out; i++)
        printf("%d .. %d: %6.1f\n", bin_lo[i], bin_hi[i], bin_av[i]);

    return 0;
}

示例输出:

1 .. 1:  462.0
3 .. 3:  714.0
5 .. 7:  970.5

还有很多改进输出的空间(例如,回显输入数据的相关子集并不是一个坏主意)。

有了这个框架,您可以通过根据 FFT 输出中的值计算 peakfreq 中的值,而不是使用硬编码数组,从而使场景复杂化。

【讨论】:

    【解决方案2】:

    您可以将其视为状态机。它一次读入一个符号,并根据它改变状态。

    有两种状态:开始状态和已经读取了一些数据的状态。

    在起始状态下,如果下一个符号为零,则保持此状态。如果不是,则处理符号并更改状态。

    在另一种状态下,如果下一个符号为零,则发出结果并更改状态。如果没有,请处理它。如果在此状态下遇到结束,则发出结果。

    这是一个非常干净的 Python 实现:

    class Averager:
    
        def __init__(self):
    
            self.averages = []
    
            self.sumOfNumbers = 0
            self.count = 0
    
        def addToAverage(self, number, weight):
            self.sumOfNumbers += number * weight
            self.count += weight
    
        def emitAverage(self):
            self.averages.append(self.sumOfNumbers / self.count)
            self.sumOfNumbers = 0
            self.count = 0
    
    
    def averagesOf(data, weights):
    
        averager = Averager()
        dataRead = False
    
        def emitIfData():
            if dataRead:
                averager.emitAverage()
    
        for number, weight in zip(data, weights):
            if number == 0:
                emitIfData()
                dataRead = False
            else:
                averager.addToAverage(number, weight)
                dataRead = True
    
        emitIfData()
    
        return averager.averages
    
    print(averagesOf([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 462, 0, 0, 0, 0, 0, 0, 714, 0, 0, 0, 924, 966, 1008, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  14, 0, 0, 0, 0, 0, 0,  14, 0, 0, 0,  29,  74,   45, 0, 0, 0, 0]))
    

    输出:

    [462.0, 714.0, 970.5405405405405]
    

    【讨论】:

    • 感谢您的回复,但这不会给我整个数组的平均值吗?让我详细说明一下,因此对于上面的示例,我需要 3 个平均值,来自 ab 的 avg1、来自 cde 的 avg2 和来自 f 的 avg3。基本上,这些是 fft 输出,可以通过条形图来说明。我想从幅度条中找到中心频率。
    • 已编辑答案。这是否更好?您是否需要有关如何实现所描述算法的更多详细信息?
    • 我在问题中添加了更多内容,以使自己对此更加清楚。你能详细说明一下吗?编程不是我的专长,所以如果你能多解释一下就好了。
    • 谢谢!真的很感激
    猜你喜欢
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    • 2015-06-01
    • 1970-01-01
    • 2016-01-10
    • 2022-11-19
    • 2019-04-05
    • 1970-01-01
    相关资源
    最近更新 更多