簡體   English   中英

使用Delphi將值集成到緩沖區中

[英]Integration of values in a buffer with Delphi

接下來是我關於差異的問題:

用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個值。

我用新數據一次又一次地調用緩沖時間,新數據與上一個數據塊是連續的,因此下次將保留該塊的最后一個值。

我做的正確嗎? 即,它將適當地整合價值觀嗎?

謝謝。

您似乎需要測試代碼方面的幫助。 正如評論中所討論的,這里是一個非常簡單的測試。

{$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的測試,但是這種測試無法擴展。 為自己准備一個單元測試框架(我推薦DUnitX)並構建適當的測試用例。 這也將迫使您分解代碼,以便對其進行精心設計。 使代碼可測試的通常出乎意料的好處之一是,它通常會導致改進接口的設計。

對於您的下一個問題,我要求您向SSCCE提供測試代碼! ;-)


對代碼的一些注釋:

  1. 通過constvar傳遞動態數組。 在您的情況下,您想通過const傳遞輸入緩沖區。
  2. 不要使用可寫的類型常量。 使用參數或其他一些更合理的狀態管理。

再次,正如我在上一個問題中所說的那樣,編寫測試以證明代碼,並肉眼檢查。 編寫測試的關鍵是從您可能想到的最簡單的東西開始。 如此簡單,以至於您100%都知道答案。 然后,一旦使它起作用,就將測試擴展到更復雜的情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM