mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2026-01-04 01:22:46 +01:00
TAChart: Add smoothed derivative source. Update demo.
git-svn-id: trunk@32412 -
This commit is contained in:
parent
0271730391
commit
979e916f7b
@ -329,6 +329,15 @@ object Form1: TForm1
|
||||
TabOrder = 1
|
||||
Text = 'Backward'
|
||||
end
|
||||
object cbSmooth: TCheckBox
|
||||
Left = 332
|
||||
Height = 17
|
||||
Top = 5
|
||||
Width = 56
|
||||
Caption = 'Smooth'
|
||||
OnChange = cbSmoothChange
|
||||
TabOrder = 2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -34,6 +34,7 @@ type
|
||||
chCalcLineSeriesAvg: TLineSeries;
|
||||
chCalcLineSeriesSum: TLineSeries;
|
||||
cbAccDirStatistics: TComboBox;
|
||||
cbSmooth: TCheckBox;
|
||||
seAccumulationRange: TSpinEdit;
|
||||
lblAccumulationRange: TLabel;
|
||||
ListChartSource1: TListChartSource;
|
||||
@ -52,6 +53,7 @@ type
|
||||
procedure cbAccDirDerivativeChange(Sender: TObject);
|
||||
procedure cbAccDirStatisticsChange(Sender: TObject);
|
||||
procedure cbCumulativeChange(Sender: TObject);
|
||||
procedure cbSmoothChange(Sender: TObject);
|
||||
procedure CreateData;
|
||||
procedure seAccumulationRangeChange(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
@ -88,6 +90,14 @@ begin
|
||||
chCalcLineSeriesSum.Active := cbCumulative.Checked;
|
||||
end;
|
||||
|
||||
procedure TForm1.cbSmoothChange(Sender: TObject);
|
||||
begin
|
||||
if cbSmooth.Checked then
|
||||
ccsDerivative.AccumulationMethod := camSmoothDerivative
|
||||
else
|
||||
ccsDerivative.AccumulationMethod := camDerivative;
|
||||
end;
|
||||
|
||||
procedure TForm1.CreateData;
|
||||
const
|
||||
N = 100;
|
||||
|
||||
@ -157,7 +157,8 @@ type
|
||||
property Sorted: Boolean read FSorted write FSorted default false;
|
||||
end;
|
||||
|
||||
TChartAccumulationMethod = (camNone, camSum, camAverage, camDerivative);
|
||||
TChartAccumulationMethod = (
|
||||
camNone, camSum, camAverage, camDerivative, camSmoothDerivative);
|
||||
TChartAccumulationDirection = (cadBackward, cadForward, cadCenter);
|
||||
|
||||
{ TCalculatedChartSource }
|
||||
@ -183,6 +184,7 @@ type
|
||||
procedure Changed(ASender: TObject);
|
||||
function EffectiveAccumulationRange: Cardinal;
|
||||
procedure ExtractItem(AIndex: Integer);
|
||||
function IsDerivative: Boolean; inline;
|
||||
procedure RangeAround(AIndex: Integer; out ALeft, ARight: Integer);
|
||||
procedure SetAccumulationDirection(AValue: TChartAccumulationDirection);
|
||||
procedure SetAccumulationMethod(AValue: TChartAccumulationMethod);
|
||||
@ -915,14 +917,12 @@ begin
|
||||
FHistory.GetSum(FItem);
|
||||
FItem.MultiplyY(1 / (newRight - newLeft + 1));
|
||||
end;
|
||||
camDerivative:
|
||||
camDerivative, camSmoothDerivative:
|
||||
CalcDerivative(AIndex);
|
||||
end;
|
||||
FIndex := AIndex;
|
||||
end;
|
||||
|
||||
// Derivative is approximated by finite differences
|
||||
// with accuracy order of (AccumulationRange - 1).
|
||||
procedure TCalculatedChartSource.CalcDerivative(AIndex: Integer);
|
||||
|
||||
procedure WeightedSum(const ACoeffs: array of Double; ADir, ACount: Integer);
|
||||
@ -938,21 +938,40 @@ procedure TCalculatedChartSource.CalcDerivative(AIndex: Integer);
|
||||
end;
|
||||
end;
|
||||
|
||||
// Derivative is approximated by finite differences
|
||||
// with accuracy order of (AccumulationRange - 1).
|
||||
// Smoothed derivative coefficients are based on work
|
||||
// by Pavel Holoborodko (http://www.holoborodko.com/pavel/).
|
||||
const
|
||||
COEFFS_BF: array [2..7, 0..6] of Double = (
|
||||
( -1, 1, 0, 0, 0, 0, 0),
|
||||
( -3/2, 2, -1/2, 0, 0, 0, 0),
|
||||
( -11/6, 3, -3/2, 1/3, 0, 0, 0),
|
||||
( -25/12, 4, -3, 4/3, -1/4, 0, 0),
|
||||
(-137/60, 5, -5, 10/3, -5/4, 1/5, 0),
|
||||
( -49/20, 6, -15/2, 20/3, -15/4, 6/5, -1/6));
|
||||
COEFFS_C: array [2..5, 0..4] of Double = (
|
||||
(0, 1/2, 0, 0, 0),
|
||||
(0, 2/3, -1/12, 0, 0),
|
||||
(0, 3/4, -3/20, 1/60, 0),
|
||||
(0, 4/5, -1/5, 4/105, -1/280));
|
||||
COEFFS_BF: array [Boolean, 2..7, 0..6] of Double = (
|
||||
( ( -1, 1, 0, 0, 0, 0, 0),
|
||||
( -3/2, 2, -1/2, 0, 0, 0, 0),
|
||||
( -11/6, 3, -3/2, 1/3, 0, 0, 0),
|
||||
( -25/12, 4, -3, 4/3, -1/4, 0, 0),
|
||||
(-137/60, 5, -5, 10/3, -5/4, 1/5, 0),
|
||||
( -49/20, 6, -15/2, 20/3, -15/4, 6/5, -1/6)
|
||||
),
|
||||
( ( -1, 1, 0, 0, 0, 0, 0),
|
||||
( -1/2, 0, 1/2, 0, 0, 0, 0),
|
||||
( -1/4, -1/4, 1/4, 1/4, 0, 0, 0),
|
||||
( -1/8, -1/4, 0, 1/4, 1/8, 0, 0),
|
||||
(-1/16, -3/16, -1/8, 1/8, 3/16, 1/16, 0),
|
||||
(-1/32, -1/8, -5/32, 0, 5/32, 1/8, 1/32)
|
||||
));
|
||||
COEFFS_C: array [Boolean, 2..5, 0..4] of Double = (
|
||||
( (0, 1/2, 0, 0, 0),
|
||||
(0, 2/3, -1/12, 0, 0),
|
||||
(0, 3/4, -3/20, 1/60, 0),
|
||||
(0, 4/5, -1/5, 4/105, -1/280)
|
||||
),
|
||||
( (0, 1/2, 0, 0, 0),
|
||||
(0, 1/4, 1/8, 0, 0),
|
||||
(0, 5/32, 1/8, 1/32, 0),
|
||||
(0, 7/64, 7/64, 3/64, 1/128)
|
||||
));
|
||||
var
|
||||
ar, iLeft, iRight, dir: Integer;
|
||||
isSmooth: Boolean;
|
||||
dx: Double;
|
||||
begin
|
||||
RangeAround(AIndex, iLeft, iRight);
|
||||
@ -961,17 +980,17 @@ begin
|
||||
dx := Max(
|
||||
FItem.X - FHistory.GetPtr(AIndex - iLeft - 1)^.X,
|
||||
FHistory.GetPtr(AIndex - iLeft + 1)^.X - FItem.X);
|
||||
ar := Min(Min(AIndex - iLeft, iRight - AIndex) + 1, High(COEFFS_C));
|
||||
ar := Min(Min(AIndex - iLeft, iRight - AIndex) + 1, High(COEFFS_C[false]));
|
||||
dir := 0;
|
||||
end;
|
||||
cotFirst: begin
|
||||
dx := FHistory.GetPtr(1)^.X - FItem.X;
|
||||
ar := Min(iRight - AIndex + 1, High(COEFFS_C));
|
||||
ar := Min(iRight - AIndex + 1, High(COEFFS_BF[false]));
|
||||
dir := 1;
|
||||
end;
|
||||
cotSecond: begin
|
||||
dx := FItem.X - FHistory.GetPtr(AIndex - iLeft - 1)^.X;
|
||||
ar := Min(AIndex - iLeft + 1, High(COEFFS_C));
|
||||
ar := Min(AIndex - iLeft + 1, High(COEFFS_BF[false]));
|
||||
dir := -1;
|
||||
end;
|
||||
cotBoth: begin
|
||||
@ -985,12 +1004,13 @@ begin
|
||||
end;
|
||||
FItem.SetY(0.0);
|
||||
AIndex -= iLeft;
|
||||
isSmooth := AccumulationMethod = camSmoothDerivative;
|
||||
if dir = 0 then begin
|
||||
WeightedSum(COEFFS_C[ar], -1, ar);
|
||||
WeightedSum(COEFFS_C[ar], +1, ar);
|
||||
WeightedSum(COEFFS_C[isSmooth][ar], -1, ar);
|
||||
WeightedSum(COEFFS_C[isSmooth][ar], +1, ar);
|
||||
end
|
||||
else
|
||||
WeightedSum(COEFFS_BF[ar], dir, ar);
|
||||
WeightedSum(COEFFS_BF[isSmooth][ar], dir, ar);
|
||||
FItem.MultiplyY(1 / dx);
|
||||
end;
|
||||
|
||||
@ -1038,7 +1058,7 @@ function TCalculatedChartSource.EffectiveAccumulationRange: Cardinal;
|
||||
const
|
||||
MAX_DERIVATIVE_RANGE = 10;
|
||||
begin
|
||||
if (AccumulationMethod = camDerivative) and (AccumulationRange = 0) then
|
||||
if IsDerivative and (AccumulationRange = 0) then
|
||||
Result := MAX_DERIVATIVE_RANGE
|
||||
else
|
||||
Result := AccumulationRange;
|
||||
@ -1076,6 +1096,11 @@ begin
|
||||
CalcPercentage;
|
||||
end;
|
||||
|
||||
function TCalculatedChartSource.IsDerivative: Boolean;
|
||||
begin
|
||||
Result := AccumulationMethod in [camDerivative, camSmoothDerivative];
|
||||
end;
|
||||
|
||||
function TCalculatedChartSource.IsSorted: Boolean;
|
||||
begin
|
||||
if Origin <> nil then
|
||||
|
||||
Loading…
Reference in New Issue
Block a user