diff --git a/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.lfm b/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.lfm index 7d037ee84..9c4412232 100644 --- a/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.lfm +++ b/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.lfm @@ -3,6 +3,7 @@ inherited CUSUMChartForm: TCUSUMChartForm HelpKeyword = 'html/CUMSUMChart.htm' Caption = 'Cumulative Sum Control Chart' OnActivate = FormActivate + ShowHint = True inherited SpecsPanel: TPanel Width = 432 ClientWidth = 432 @@ -55,20 +56,21 @@ inherited CUSUMChartForm: TCUSUMChartForm end object GroupBox1: TGroupBox[8] AnchorSideLeft.Control = MeasEdit - AnchorSideTop.Control = MeasEdit + AnchorSideTop.Control = GroupBox2 AnchorSideTop.Side = asrBottom AnchorSideRight.Control = MeasEdit AnchorSideRight.Side = asrBottom Left = 228 - Height = 107 - Top = 120 + Height = 153 + Top = 202 Width = 204 Anchors = [akTop, akLeft, akRight] - BorderSpacing.Top = 24 - Caption = 'CUMSUM V-Mask Specifications' - ClientHeight = 87 + AutoSize = True + BorderSpacing.Top = 16 + Caption = 'V-Mask Specifications' + ClientHeight = 133 ClientWidth = 200 - TabOrder = 3 + TabOrder = 4 object Label4: TLabel AnchorSideLeft.Control = GroupBox1 AnchorSideTop.Control = DeltaEdit @@ -112,6 +114,7 @@ inherited CUSUMChartForm: TCUSUMChartForm AnchorSideRight.Side = asrBottom Left = 114 Height = 23 + Hint = 'Detection level for a shift in the process mean, '#13#10'expressed in data units (default), or'#13#10'as a multiple of the standard deviation of the '#13#10'data points (when "Normalized CUSUM" is checked).' Top = 2 Width = 78 Alignment = taRightJustify @@ -131,6 +134,7 @@ inherited CUSUMChartForm: TCUSUMChartForm AnchorSideRight.Side = asrBottom Left = 114 Height = 23 + Hint = 'Probability of concluding that a shift in the process has occurred, when in fact it did not. ' Top = 29 Width = 78 Alignment = taRightJustify @@ -150,6 +154,7 @@ inherited CUSUMChartForm: TCUSUMChartForm AnchorSideRight.Side = asrBottom Left = 114 Height = 23 + Hint = 'Probability of not detecting that a shift in the process mean has, in fact, occurred' Top = 56 Width = 78 Alignment = taRightJustify @@ -161,25 +166,52 @@ inherited CUSUMChartForm: TCUSUMChartForm TabOrder = 2 Text = 'BetaEdit' end + object VMaskScrollbar: TScrollBar + AnchorSideLeft.Control = Label1 + AnchorSideTop.Control = Label1 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = BetaEdit + AnchorSideRight.Side = asrBottom + Left = 12 + Height = 17 + Top = 104 + Width = 180 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Top = 2 + BorderSpacing.Bottom = 12 + PageSize = 0 + TabOrder = 3 + end + object Label1: TLabel + AnchorSideLeft.Control = Label4 + AnchorSideTop.Control = BetaEdit + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 15 + Top = 87 + Width = 100 + Caption = 'Position of V-Mask' + ParentColor = False + end end object GroupBox2: TGroupBox[9] AnchorSideLeft.Control = GroupBox1 - AnchorSideTop.Control = GroupBox1 + AnchorSideTop.Control = MeasEdit AnchorSideTop.Side = asrBottom AnchorSideRight.Control = MeasEdit AnchorSideRight.Side = asrBottom Left = 228 - Height = 51 - Top = 243 + Height = 74 + Top = 112 Width = 204 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 16 BorderSpacing.Bottom = 8 Caption = 'Option:' - ClientHeight = 31 + ClientHeight = 54 ClientWidth = 200 - TabOrder = 4 + TabOrder = 3 object TargetChk: TCheckBox AnchorSideLeft.Control = GroupBox2 AnchorSideTop.Control = TargetEdit @@ -207,11 +239,24 @@ inherited CUSUMChartForm: TCUSUMChartForm Anchors = [akTop, akLeft, akRight] BorderSpacing.Left = 8 BorderSpacing.Right = 8 - BorderSpacing.Bottom = 8 + BorderSpacing.Bottom = 4 Constraints.MinWidth = 64 TabOrder = 1 Text = 'TargetEdit' end + object ShowMeanDevChk: TCheckBox + AnchorSideLeft.Control = TargetChk + AnchorSideTop.Control = TargetEdit + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 19 + Top = 27 + Width = 169 + BorderSpacing.Top = 4 + BorderSpacing.Bottom = 8 + Caption = 'Show mean group deviation' + TabOrder = 2 + end end end inherited SpecsSplitter: TSplitter diff --git a/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.pas b/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.pas index 95a6468b8..bc8139d0b 100644 --- a/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.pas +++ b/applications/lazstats/source/forms/analysis/statistical_process_control/cusumunit.pas @@ -15,6 +15,9 @@ type TCUSUMChartForm = class(TBasicSPCForm) AlphaEdit: TEdit; BetaEdit: TEdit; + Label1: TLabel; + VMaskScrollbar: TScrollBar; + ShowMeanDevChk: TCheckBox; DeltaEdit: TEdit; GroupBox1: TGroupBox; GroupBox2: TGroupBox; @@ -26,6 +29,7 @@ type procedure FormActivate(Sender: TObject); private SEMean: Double; + k, h: Double; protected procedure Compute; override; procedure PlotMeans(ATitle, AXTitle, AYTitle, ADataTitle, AGrandMeanTitle: String; @@ -52,7 +56,8 @@ uses procedure TCUSUMChartForm.Compute; var i, j, grpIndex, numGrps, grpSize, oldGrpSize, numValues: Integer; - X, Xsq, Xmin, Xmax, target, grandMean, grandSum, grandSD, UCL, LCL: Double; + X, Xsq, Xmin, Xmax, target, diff, grandMean, grandSum, grandSD: Double; + deltaSD, alpha, beta: double; sizeError: Boolean; grp: String; groups: StrDyneVec = nil; @@ -140,8 +145,9 @@ begin grandSum := grandSum + (means[0] - target); for j := 1 to numGrps-1 do begin - cusums[j] := cusums[j-1] + (means[j] - target); - grandSum := grandSum + (means[j] - target); + diff := means[j] - target; + cusums[j] := cusums[j-1] + diff; + grandSum := grandSum + diff; end; SEMean := SEMean - sqr(grandMean)/numValues; @@ -150,9 +156,18 @@ begin SEMean := SEMean/sqrt(numValues); grandMean := grandMean/numValues; // mean of all observations grandSum := grandSum/numGrps; // mean of the group means - UCL := grandMean + 3.0*SEMean; - LCL := grandMean - 3.0*SEMean; - if (LCL < 0.0) then LCL := 0.0; + + if DeltaEdit.Text <> '' then + begin + deltaSD := StrToFloat(DeltaEdit.Text) / SEMean; + // This is in multiples of std deviations + + // see : https://www.itl.nist.gov/div898/handbook/pmc/section3/pmc323.htm + alpha := StrToFloat(AlphaEdit.Text); + beta := StrToFloat(BetaEdit.Text); + k := deltaSD * SEMean / 2.0; + h := SEMean / deltaSD * ln((1 - beta) / alpha); + end; // Print results lReport := TStringList.Create; @@ -160,19 +175,35 @@ begin lReport.Clear; lReport.Add('CUSUM Chart Results'); lReport.Add(''); - lReport.Add(' Group Size Mean Std.Dev. Cum.Dev. of' ); - lReport.Add(' Mean from Target'); - lReport.Add('------- ---- -------- -------- ----------------'); - for i := 0 to numGrps - 1 do - lReport.Add('%7d %4d %8.2f %8.2f %10.2f', [i+1, count[i], means[i], stddev[i], cusums[i]]); - lReport.Add(''); lReport.Add('Mean of group deviations: %8.3f', [grandSum]); lReport.Add('Mean of all observations: %8.3f', [grandMean]); lReport.Add('Std. Dev. of Observations: %8.3f', [grandSD]); lReport.Add('Standard Error of Mean: %8.3f', [SEMean]); lReport.Add('Target Specification: %8.3f', [target]); - lReport.Add('Lower Control Limit: %8.3f', [LCL]); - lReport.Add('Upper Control Limit: %8.3f', [UCL]); + + lReport.Add(''); + lReport.Add('Differences in data units'); + lReport.Add(''); + + lReport.Add('Group Size Mean Std.Dev. Mean-Dev Cum.Dev. of' ); + lReport.Add(' Mean from Target'); + lReport.Add('----- ---- -------- -------- -------- ----------------'); + for i := 0 to numGrps - 1 do + begin + lReport.Add('%5s %4d %8.3f %8.3f %8.3f %10.3f', [ + groups[i], count[i], means[i], stddev[i], means[i]-target, cusums[i] + ]); + end; + + if DeltaEdit.Text <> '' then + begin + lReport.Add(''); + lReport.Add('V-Mask parameters:'); + lReport.Add(' Alpha (Type I error) %8.3f', [alpha]); + lReport.Add(' Beta (Type II error) %8.3f', [beta]); + lReport.Add(' k: %8.3f (%.2f sigma)', [k, k/SEMean]); + lReport.Add(' h: %8.3f (%.2f sigma)', [h, h/SEMean]); + end; ReportMemo.Lines.Assign(lReport); finally @@ -180,6 +211,9 @@ begin end; // Show graph + VMaskScrollbar.Max := numGrps; + if not ShowMeanDevChk.Checked then + grandSum := NaN; PlotMeans( Format('Cumulative Sum Chart for "%s"', [GetFileName]), // chart title GroupEdit.Text, // x title @@ -218,61 +252,58 @@ begin end; end; - { Overridden to draw the V-Mark } procedure TCUSUMChartForm.PlotMeans(ATitle, AXTitle, AYTitle, ADataTitle, AGrandMeanTitle: String; const Groups: StrDyneVec; const Means: DblDyneVec; UCL, LCL, GrandMean, TargetSpec, LowerSpec, UpperSpec: double); var - alpha, beta, delta, deltaSD, gamma, d, h, k: Double; ser: TLineSeries; - ext: TDoubleRect; - x0, y0, x1, y1, x2, y2, x3, y3: Double; + xVM, yVM, x1, y1, x2, y2, x3, y3, x4, y4: Double; begin inherited; if DeltaEdit.Text = '' then exit; - alpha := StrToFloat(AlphaEdit.Text); - beta := StrToFloat(BetaEdit.Text); - delta := StrToFloat(DeltaEdit.Text); // This is in data units - deltaSD := delta / SEMean; // This is in multiples of std deviations - - // see : https://www.itl.nist.gov/div898/handbook/pmc/section3/pmc323.htm - d := 2.0 / sqr(deltaSD) * ln((1.0 - beta)/alpha); - k := deltaSD * SEMean / 2.0; - h := d * k; - ser := TLineSeries.Create(FChartFrame.Chart); FChartFrame.Chart.AddSeries(ser); ser.SeriesColor := clBlue; ser.Title := 'V-Mask'; - ext := FChartFrame.Chart.GetFullExtent; - x1 := Length(Means); // 1-based! - y1 := Means[High(Means)] + h; - x0 := 1; - y0 := y1 - k*(x0 - x1); + // Position of V mask point + xVM := VMaskScrollbar.Position; + yVM := Means[VMaskScrollbar.Position-1]; - x2 := x1; - y2 := Means[High(Means)] - h; - x3 := x0; - y3 := y2 + k*(x3 - x2); + // Upper part of V mask + x2 := xVM; + y2 := yVM + h; + x1 := 1; // x values begin with 1 + y1 := y2 - k*(x1 - x2); + + // Lower part of V mask + x3 := xVM; + y3 := yVM - h; + x4 := 1; + y4 := y3 + k*(x4 - x3); - ser.AddXY(x0, y0); ser.AddXY(x1, y1); ser.AddXY(x2, y2); + ser.AddXY(x2, NaN); // Do not draw the vertical line ser.AddXY(x3, y3); + ser.AddXY(x4, y4); end; procedure TCUSUMChartForm.Reset; begin inherited; - DeltaEdit.Clear; - AlphaEdit.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL); - BetaEdit.Text := FormatFloat('0.00', DEFAULT_BETA_LEVEL); + ShowMeanDevChk.Checked := false; TargetEdit.Clear; + DeltaEdit.Clear; + AlphaEdit.Text := FormatFloat('0.00000', 0.0027); //DEFAULT_ALPHA_LEVEL); + BetaEdit.Text := FormatFloat('0.00000', 0.01); //DEFAULT_BETA_LEVEL); + VMaskScrollbar.Min := 2; + VMaskScrollbar.Max := 1000; + VMaskScrollbar.Position := VMaskScrollbar.Max; end; diff --git a/applications/lazstats/source/forms/mainunit.pas b/applications/lazstats/source/forms/mainunit.pas index 3570799a2..53fddbc6c 100644 --- a/applications/lazstats/source/forms/mainunit.pas +++ b/applications/lazstats/source/forms/mainunit.pas @@ -2123,7 +2123,7 @@ procedure TOS3MainFrm.mnuAnalysisSPC_CChartClick(Sender: TObject); begin if CChartForm = nil then Application.CreateForm(TCChartForm, CChartForm); - CChartForm.ShowModal; + CChartForm.Show; end; @@ -2132,7 +2132,7 @@ procedure TOS3MainFrm.mnuAnalysisSPC_CUSUMClick(Sender: TObject); begin if CUSUMChartForm = nil then Application.CreateForm(TCUSUMChartForm, CUSUMChartForm); - CUSUMChartForm.ShowModal; + CUSUMChartForm.Show; end; @@ -2141,7 +2141,7 @@ procedure TOS3MainFrm.mnuAnalysisSPC_PChartClick(Sender: TObject); begin if PChartForm = nil then Application.CreateForm(TPChartForm, PChartForm); - PChartForm.ShowModal; + PChartForm.Show; end; @@ -2150,7 +2150,7 @@ procedure TOS3MainFrm.mnuAnalysisSPC_RangeClick(Sender: TObject); begin if RChartForm = nil then Application.CreateForm(TRChartForm, RChartForm); - RChartForm.ShowModal; + RChartForm.Show; end; @@ -2159,7 +2159,7 @@ procedure TOS3MainFrm.mnuAnalysisSPC_SChartClick(Sender: TObject); begin if SChartForm = nil then Application.CreateForm(TSChartForm, SChartForm); - SChartForm.ShowModal; + SChartForm.Show; end; @@ -2168,7 +2168,7 @@ procedure TOS3MainFrm.mnuAnalysisSPC_UChartClick(Sender: TObject); begin if UChartForm = nil then Application.CreateForm(TUChartForm, UChartForm); - UChartForm.ShowModal; + UChartForm.Show; end; @@ -2177,7 +2177,7 @@ procedure TOS3MainFrm.mnuAnalysisSPC_XBarClick(Sender: TObject); begin if XBarChartForm = nil then Application.CreateForm(TXBarChartForm, XBarChartForm); - XBarChartForm.ShowModal; + XBarChartForm.Show; end;