更高效:大数组或多个标量

发布于 2024-08-05 09:30:45 字数 511 浏览 3 评论 0原文

在嵌入式(PIC)环境中工作,用 c 进行编程。

我必须跟踪变量(历史)的 1000 个值并返回这些值的移动平均值。我只是想知道如果我使用数组或 1000 个 16 位变量,在速度、ROM 和 RAM 使用方面是否会更有效。对此有明确的答案吗?或者我必须两者都尝试一下,看看哪种效果最好?

谢谢。

编辑: 嗯...我已经遇到了另一个问题。编译器将我的数组大小限制为最大 256。

EDIT2:

为了澄清...代码每秒触发大约 1000 次。每次,都会计算并存储历史[n](或history_n)的值。每次我需要计算1000个最近历史值(包括当前)的平均值。所以 (history[1000] + History[999] + ... + History[1] + History[0]) / 1000; 或类似的东西。显然,每次我都需要剔除最旧的并添加最新的。

EDIT3:

我重新编写了代码,现在 256 数组大小不再是问题。现在 100 左右的样本量比较合适。

Working in an embedded (PIC) environment, programming in c.

I have to keep track of 1000 values for a variable (history) and return the moving average of those values. I'm just wondering if it will be more efficient in terms of speed, ROM and RAM usage if I use an array or 1000 16bit variables. Is there a difinitive answer to that? Or would i have to just try both and see what works best?

Thanks.

EDIT:
Hmm... I already ran into another problem. The compiler limits me to an array size maximum of 256.

EDIT2:

For clarification... the code fires about 1000 times a second. Each time, a value for history[n] (or history_n) is calculated and stored. Each time I need to calculate the average of the 1000 most recent history values (including current). So (history[1000] + history[999] + ... + history[1] + history[0]) / 1000; or something to that effect. Obviously each time I need to kick out the oldest and add the newest.

EDIT3:

I've re-worked the code such that now the 256 array size is not an issue. A sample size of around 100 is now suitable.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

浅黛梨妆こ 2024-08-12 09:30:45

假设您需要保留历史记录,并且考虑到 256 个元素数组的限制,以下是管理它的方法:

int history1[256];
int history2[256];
int history3[256];
int history4[256];
int* arrays[] = {history1,history2,history3,history4}
int idx=0;
int sum = 0;
int n = 0;

int updateAverage(int newValue)
{
  int ai = (idx++)>>8;
  int* target = arrays[ai]+(idx&0xFF);

  sum -=*target;
  *target = newValue;
  sum += *target;
  n++;
  n=n<1000?n:1000;
  idx = (idx<1000)?idx:0;
  return sum/n;
}

Assuming you need to keep the history, and given your 256 element array limit, here's a way to manage it:

int history1[256];
int history2[256];
int history3[256];
int history4[256];
int* arrays[] = {history1,history2,history3,history4}
int idx=0;
int sum = 0;
int n = 0;

int updateAverage(int newValue)
{
  int ai = (idx++)>>8;
  int* target = arrays[ai]+(idx&0xFF);

  sum -=*target;
  *target = newValue;
  sum += *target;
  n++;
  n=n<1000?n:1000;
  idx = (idx<1000)?idx:0;
  return sum/n;
}
︶葆Ⅱㄣ 2024-08-12 09:30:45

我不确定我是否完全理解你的问题。您是否想知道为“short History[1000]”生成的代码和“short History1,history2,...,history1000;”生成的代码之间的区别?

两者都应使用相似数量的 RAM:每个条目都将存储在单个文件寄存器中(假设您使用的是 16 位 PIC)。不过,计算后者平均值的代码将会很丑陋,并且可能会占用相当多的 ROM,因为它需要单独引用每个值(而不仅仅是偏移基数)。

编辑:
256 个元素限制的原因是 PIC 上的文件寄存器分页。您不能仅通过偏移基址寄存器来寻址更大的数组,因为您可能需要请求页面更改。

您绝对必须计算运行平均值吗?或者你可以做一个总体平均吗?如果总体平均值没问题,则使用 Alphaneo 答案的变体:只需保留总和以及在两个变量中收集的值的数量,并在需要平均值时随时除以。

I'm not sure if I completely understand your question. Are you asking for the difference between the code generated for 'short history[1000]', and 'short history1, history2, ..., history1000;'?

Both should use similar amounts of RAM: each entry is going to take be stored in a single file register (assuming you're using a 16-bit PIC). The code to calculate the average of the latter is going to be ugly though, and will likely take quite a bit of ROM, as it is going to need to reference each value separately (rather than just offsetting the base).

Edit:
The reason for the 256 element limit is because of file register paging on the PIC. You can't address a larger array by just offsetting the base register, because you may need to request a page change.

Do you absolutely have to calculate a running average? Or can you do an overall average? If an overall average is okay, then use a variant of Alphaneo's answer: just keep the sum, and the number of values collected in two variables, and divide any time you need the average.

梦里人 2024-08-12 09:30:45

如果使用数组,生成的代码会小得多。我对此不确定,但我认为数组访问会使用更少的内存,因为您不必跟踪多个变量,您只需一个指向一个块的指针。如果堆栈大小是一个问题,则堆上的数组可能是最好的方法,因为 C 变量存储在堆栈上。

If you use an array the generated code will be much smaller. I'm not sure on this but I think an array access would use less memory since you don't have to keep track of multiple variables you just have a pointer to one Chunk. If your stack size is an issue an Array on the heap may be the best way to go since C variables are stored on the stack.

故事和酒 2024-08-12 09:30:45

如果你想通过将其存储在数组中来计算平均值,肯定会比运行时计算更昂贵。

原因 1:如果您在运行时计算它,您只需不断添加,例如查看以下流程

    init-0: _tempSum_ = 0
    step-1: Read current value to _currVal_
    step-2: Add current value to _tempSum_
    step-3: Check if we have required of values _num_ (eg. 1000), if not goto-1
    step-4: Calculate _avg_ = _tempSum_ / _num_ and return
    step-5: goto init-0

如果您存储在包含 1000 个值的临时数组中,实际上您将执行从 init-0 到 step- 的所有步骤5,只不过您最终将使用 1000 个值的数组。

根据数组访问时间,它可能会更慢......所以小心

If you want to calculate an average by storing it in an array, will be definitely more expensive than calculating at run-time.

Reason-1: If you calculate it at run-time, you will justing keep adding for example look at the following flow

    init-0: _tempSum_ = 0
    step-1: Read current value to _currVal_
    step-2: Add current value to _tempSum_
    step-3: Check if we have required of values _num_ (eg. 1000), if not goto-1
    step-4: Calculate _avg_ = _tempSum_ / _num_ and return
    step-5: goto init-0

If you store in a temp array of 1000 values, actually things you will all the steps from init-0 to step-5, except that you will end up using a 1000 value array.

It might be slower, based on the array access timing ... so beware

夜声 2024-08-12 09:30:45

首先,您可以更改链接器文件以允许更大的部分。然后,您必须使用编译指示将历史数组放入该部分。

其次,数组方法要好得多。为了提高性能,您还需要一个 32 位整数来保存历史数组的运行总计。

对于历史函数的每次触发,您将从 HistoryRunningTotal 中减去最旧的值并添加新的历史值。您还需要一个 OldestHistoryIndex 变量来跟踪最新值的去向(并覆盖旧历史记录)。

First, you can change your linker file to allow a larger section. You will then have to put your history array in that section using pragmas.

Second, the array method is much better. To improve the performance you will also need a 32-bit integer to keep a running total of the history array.

For each firing of the history function you will subtract the oldest value from the HistoryRunningTotal and add in the new history value. You will also need a OldestHistoryIndex variable to keep track of where the newest value will go (and overwrite the old history).

断爱 2024-08-12 09:30:45

如果您有足够的内存来容纳 1000 个值,那么为什么不静态分配内存、创建一个旋转缓冲区并在值中移动指针来计算总和。 (如果运行平均值不是您需要的)。只需继续将新值放在最旧的值上,计算 1000 个值的总和并除以 1000。因此实际上有两个指针,一个用于插入新值,另一个用于迭代整个缓冲区。

If you have enough memory for the 1000 values, then why not statically allocate the memory, make a rotating buffer and move a pointer through the values to calculate the sum. (if the running avg isn't what you need). Just keep putting the new value over the oldest value, calculate the sum of the 1000 values and divide by 1000. So actually two pointers, one for inserting the new value and one to iterate over the whole buffer.

冰雪之触 2024-08-12 09:30:45

编译器将数组限制为 256?那真是太糟糕了。这给程序员带来了编译器真正应该照顾的负担。您确定没有用于例如“大”内存模型的编译器选项吗?如果没有,请研究不同的微控制器和/或编译器。

或者,为了保持较小的尺寸,请考虑使用小型 IIR 滤波器而不是大型 FIR 滤波器。

无论如何,回答你原来的问题:数组是这种算法的逻辑选择,因为它具有明智(可维护)代码和较小代码大小的优点。

The compiler limits arrays to 256? That's pretty bad. That imposes a burden on the programmer that the compiler really should be taking care of. Are you sure there isn't a compiler option for e.g. a "large" memory model? If not, investigate a different micro and/or compiler.

Or, to keep things small, consider using a small IIR filter rather than a large FIR filter.

Anyway, to answer your original question: an array is the logical choice for such an algorithm, for the benefits of sensible (maintainable) code and small code size.

简单 2024-08-12 09:30:45

如果数组是动态分配的,那么使用静态变量会更快。如果数组是静态分配的,那么编译器应该能够将其优化为与静态变量一样快。在一些简单的代码上尝试并分析它。

If the array is dynamically allocated, then using the static variables will be faster. If the array is statically allocated, then the compiler should be able to optimize it to be equivalently fast as static variables. Try both on some trivial code and profile it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文