gpt4 book ai didi

delphi - 使用 Delphi 将缓冲区中的值集成

转载 作者:行者123 更新时间:2023-12-02 01:50:54 25 4
gpt4 key购买 nike

根据我关于差异化的问题:

Differentiation of a buffer with Delphi

我现在正在考虑进行集成。我不太明白这个问题。情况是我定期接收数据缓冲区,其中包含许多时间间隔固定的值。我需要区分它们。我已经很久没有在学校学过微积分了......

我想出的是这样的:

procedure IntegrateBuffer(ABuffer: TDoubleDynArray;
var AOutBuffer: TDoubleDynArray;
AVPS: integer);
const
SumSum: double = 0.0;
LastValue: double = NaN;
var
i: integer;
dt, aa, hl, hr: double;
begin
// protect from divide by zero
if (AVPS < 1) then exit;

dt := 1 / AVPS;

for i := 0 to high(ABuffer) do begin
if (i = 0) then begin
if (IsNaN(LastValue)) then begin
hl := ABuffer[0];
hr := ABuffer[0];
end else begin
hl := LastValue;
hr := ABuffer[i];
end;
end else begin
hl := ABuffer[i -1];
hr := ABuffer[i];
end;

aa := 0.5 * dt * (hl + hr);
SumSum := SumSum + aa;
AOutBuffer[i] := SumSum;
end;

// remember the last value for next time
LastValue := ABuffer[high(ABuffer)];
end;

我使用的是梯形规则,hl 和 hr 是梯形的左右高度。 dt 是基础。

AVPS 是每秒的值。该值的典型值在 10 到 100 之间。缓冲区的长度通常为 500 到 1000 个值。

我一次又一次地使用与前一个数据 block 连续的新数据调用缓冲区,因此保留该 block 的最后一个值以供下次使用。

我的做法正确吗?即,它会正确整合这些值(value)观吗?

谢谢。

最佳答案

看起来您需要一些测试代码的帮助。正如评论中所讨论的,这里是一个非常简单的测试。

{$APPTYPE CONSOLE}

uses
SysUtils, Math;

type
TDoubleDynArray = array of Double;

var
SumSum: double;
LastValue: double;

procedure Clear;
begin
SumSum := 0.0;
LastValue := NaN;
end;

procedure IntegrateBuffer(
ABuffer: TDoubleDynArray;
var AOutBuffer: TDoubleDynArray;
AVPS: integer
);
var
i: integer;
dt, aa, hl, hr: double;
begin
// protect from divide by zero
if (AVPS < 1) then exit;

dt := 1 / AVPS;

for i := 0 to high(ABuffer) do begin
if (i = 0) then begin
if (IsNaN(LastValue)) then begin
hl := ABuffer[0];
hr := ABuffer[0];
end else begin
hl := LastValue;
hr := ABuffer[i];
end;
end else begin
hl := ABuffer[i -1];
hr := ABuffer[i];
end;

aa := 0.5 * dt * (hl + hr);
SumSum := SumSum + aa;
AOutBuffer[i] := SumSum;
end;

// remember the last value for next time
LastValue := ABuffer[high(ABuffer)];
end;

var
Buffer: TDoubleDynArray;
OutBuffer: TDoubleDynArray;

begin
// test y = 1 for a single call, expected output = 1, actual output = 2
Clear;
Buffer := TDoubleDynArray.Create(1.0, 1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);

Readln;
end.

我正在 [0..1] 范围内对函数 y(x) = 1 进行积分。因此,预期输出为 1。但实际输出为 2。

所以,出了什么问题?您可以在调试器中解决它,但通过检查代码很容易看到。您正在对第一个样本求和一个三角形。当 IsNaN(LastValue) 为 true 时,您不应该对积分做出贡献。此时,您还没有经过 x 轴上的任何距离。

为了修复代码,让我们试试这个:

....
if (IsNaN(LastValue)) then begin
hl := 0.0;//no contribution to sum
hr := 0.0;
end else begin
hl := LastValue;
hr := ABuffer[i];
end;
....

这解决了问题。

现在让我们稍微扩展一下测试并测试y(x) = x:

// test y = x, expected output = 12.5
Clear;
Buffer := TDoubleDynArray.Create(0.0, 1.0, 2.0, 3.0, 4.0, 5.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);

所以,看起来不错。

好的,多次调用怎么样:

// test y = x for multiple calls, expected output = 18
Clear;
Buffer := TDoubleDynArray.Create(0.0, 1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := TDoubleDynArray.Create(2.0, 3.0, 4.0, 5.0, 6.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);

一次一个值怎么样?

// test y = x for multiple calls, one value at a time, expected 0.5
Clear;
Buffer := TDoubleDynArray.Create(0.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := TDoubleDynArray.Create(1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);

传递一个空数组怎么样?

// test y = x for multiple calls, some empty arrays, expected 0.5
Clear;
Buffer := TDoubleDynArray.Create(0.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := nil;
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Buffer := TDoubleDynArray.Create(1.0);
SetLength(OutBuffer, Length(Buffer));
IntegrateBuffer(Buffer, OutBuffer, 1);
Writeln(OutBuffer[high(OutBuffer)]);

呃,哦,访问冲突。如果缓冲区为空,只需在开始时跳过该函数即可更好地保护它:

if (AVPS < 1) then exit;
if (Length(ABuffer) = 0) then exit;

好的,现在最后一个测试通过了

希望您现在明白了。我刚刚使用了基于 Writeln 的 noddy 测试,但这无法扩展。为自己准备一个单元测试框架(我推荐 DUnitX)并构建适当的测试用例。这也将迫使您考虑代码,以便其设计良好。使代码可测试通常会带来意想不到的好处之一,那就是它通常会改进界面的设计。

对于您的下一个问题,我请求您提供 SSCCE与测试代码! ;-)

<小时/>

对代码的一些评论:

  1. 通过 constvar 传递动态数组。在您的情况下,您希望通过 const 传递输入缓冲区。
  2. 不要使用可写的类型常量。使用参数或其他一些更合理的状态管理。

同样,正如我在上一个问题中所说,编写测试来证明代码,并通过肉眼检查它。编写测试的关键是从您能想到的最简单的事情开始。事情如此简单,以至于您 100% 确定答案。然后,一旦你让它发挥作用,就将测试扩展到更复杂的情况。

关于delphi - 使用 Delphi 将缓冲区中的值集成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19176702/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com