@@ -84,7 +84,7 @@ internal static class Defaults
84
84
{
85
85
public const double Threshold = 0.3 ;
86
86
public const int BatchSize = 2000 ;
87
- public const double Sensitivity = 55 ;
87
+ public const double Sensitivity = 70 ;
88
88
public const SrCnnDetectMode DetectMode = SrCnnDetectMode . AnomalyOnly ;
89
89
public const int Period = 0 ;
90
90
public const SrCnnDeseasonalityMode DeseasonalityMode = SrCnnDeseasonalityMode . Stl ;
@@ -349,36 +349,55 @@ internal sealed class SrCnnEntireModeler
349
349
private static readonly int _judgementWindowSize = 40 ;
350
350
private static readonly double _eps = 1e-8 ;
351
351
private static readonly double _deanomalyThreshold = 0.35 ;
352
- private static readonly double _boundSensitivity = 70.0 ;
353
-
354
- // A fixed lookup table which returns factor using sensitivity as index.
355
- // Since Margin = BoundaryUnit * factor, this factor is calculated to make sure Margin == Boundary when sensitivity is 50,
356
- // and increases/decreases exponentially as sensitivity increases/decreases.
357
- // The factor array is generated by formula:
358
- // f(x)=1, if x=50;
359
- // f(x)=f(x+1)*(1.25+0.001*x), if 0<=x<50;
360
- // f(x)=f(x+1)/(1.25+0.001*(x-50)), if 50<x<60;
361
- // f(x)=f(x+1)/(1.15+0.001*(x-50)),, if 60<=x<=100.
352
+ private static readonly double _boundSensitivity = 93.0 ;
353
+ private static readonly double _unitForZero = 0.3 ;
354
+
355
+ // pseudo-code to generate the factors.
356
+ // factors = []
357
+ // for i in range(0, 30):
358
+ // sen = 0.8 * (i - 30) ** 2 + 32
359
+ // factors.append(sen)
360
+ // for i in range(30, 50):
361
+ // sen = -1.25 * i + 67.5
362
+ // factors.append(sen)
363
+ // for i in range(50, 60):
364
+ // sen = -0.4 * i + 25
365
+ // factors.append(sen)
366
+ // for i in range(60, 70):
367
+ // sen = -0.04 * i + 3.4
368
+ // factors.append(sen)
369
+ // for i in range(70, 80):
370
+ // sen = -0.03 * i + 2.7
371
+ // factors.append(sen)
372
+ // for i in range(80, 90):
373
+ // sen = -0.015 * i + 1.4999999999999998
374
+ // factors.append(sen)
375
+ // for i in range(90, 98):
376
+ // sen = -0.011818181818181818 * i + 1.2136363636363636
377
+ // factors.append(sen)
378
+ // ratio.append(-0.011818181818181818 * 99 + 1.2136363636363636)
379
+ // ratio.append(0.01200000000000001)
380
+ // for i in range(5):
381
+ // sen= -0.001925*i+ 0.008
382
+ // ratio.append(sen)
383
+ // ratio.append(0)
384
+ // ratio=ratio[5:]
362
385
private static readonly double [ ] _factors = new double [ ] {
363
- 184331.62871148242 , 141902.71648305038 , 109324.12672037778 , 84289.9974713784 , 65038.57829581667 , 50222.84038287002 ,
364
- 38812.08684920403 , 30017.081863266845 , 23233.035497884553 , 17996.15452973242 , 13950.50738738947 , 10822.736530170265 ,
365
- 8402.745753237783 , 6528.939979205737 , 5076.93622022219 , 3950.92312857758 , 3077.042935029268 , 2398.318733460069 ,
366
- 1870.7634426365591 , 1460.393007522685 , 1140.9320371270976 , 892.0500681212648 , 698.0047481387048 , 546.5972968979678 ,
367
- 428.36778753759233 , 335.97473532360186 , 263.71643275007995 , 207.16137686573444 , 162.8627176617409 , 128.13746472206208 ,
368
- 100.8956415134347 , 79.50799173635517 , 62.70346351447568 , 49.48971074544253 , 39.09139869308257 , 30.90229145698227 ,
369
- 24.448015393182175 , 19.35709849024717 , 15.338429865489042 , 12.163703303322 , 9.653732780414286 , 7.667778221139226 ,
370
- 6.095213212352326 , 4.8490160798347866 , 3.8606815922251485 , 3.076240312529999 , 2.4531421949999994 , 1.9578149999999996 ,
371
- 1.5637499999999998 , 1.25 , 1.0 , 0.8695652173913044 , 0.7554867223208555 , 0.655804446459076 , 0.5687809596349316 ,
372
- 0.4928777813127657 , 0.4267340097946024 , 0.36914706729636887 , 0.3190553736355825 , 0.27552277516026125 , 0.23772456873189068 ,
373
- 0.20493497304473338 , 0.17651591132190647 , 0.1519069804835684 , 0.13061649224726435 , 0.11221348131208278 , 0.09632058481723846 ,
374
- 0.08260770567516164 , 0.0707863801843716 , 0.06060477755511267 , 0.051843265658779024 , 0.0443104834690419 , 0.03783986632710667 ,
375
- 0.03228657536442549 , 0.027524787181948417 , 0.02344530424356765 , 0.019953450420057577 , 0.01696721974494692 , 0.014415649740821513 ,
376
- 0.012237393667929978 , 0.010379468759906684 , 0.008796159966022614 , 0.0074480609365136455 , 0.006301235986898177 ,
377
- 0.00532648857725966 , 0.004498723460523362 , 0.0037963911059268884 , 0.0032010043051660104 , 0.002696718032995797 ,
378
- 0.0022699646742388863 , 0.0019091376570554135 , 0.0011570531254881296 , 0.000697019955113331 , 0.00041737721863073713 ,
379
- 0.000248438820613534 , 0.00014700521929794912 , 8.647365841055832e-05 , 5.056939088336744e-05 , 2.9400808653120604e-05 ,
380
- 1.6994687082728674e-05 , 9.767061541798089e-06
381
- } ;
386
+ 532.0 , 492.8 , 455.20000000000005 , 419.20000000000005 , 384.8 , 352.0 , 320.8 , 291.2 , 263.20000000000005 ,
387
+ 236.8 , 212.0 , 188.8 , 167.20000000000002 , 147.2 , 128.8 , 112.0 , 96.8 , 83.2 , 71.2 , 60.8 , 52.0 , 44.8 , 39.2 ,
388
+ 35.2 , 32.8 , 30.0 , 28.75 , 27.5 , 26.25 , 25.0 , 23.75 , 22.5 , 21.25 , 20.0 , 18.75 , 17.5 , 16.25 , 15.0 , 13.75 ,
389
+ 12.5 , 11.25 , 10.0 , 8.75 , 7.5 , 6.25 , 5.0 , 4.599999999999998 , 4.199999999999999 , 3.799999999999997 ,
390
+ 3.3999999999999986 , 3.0 , 2.599999999999998 , 2.1999999999999993 , 1.7999999999999972 , 1.3999999999999986 ,
391
+ 1.0 , 0.96 , 0.9199999999999999 , 0.8799999999999999 , 0.8399999999999999 , 0.7999999999999998 ,
392
+ 0.7599999999999998 , 0.7199999999999998 , 0.6799999999999997 , 0.6399999999999997 , 0.6000000000000001 ,
393
+ 0.5700000000000003 , 0.54 , 0.5100000000000002 , 0.4800000000000004 , 0.4500000000000002 , 0.4200000000000004 ,
394
+ 0.3900000000000001 , 0.3600000000000003 , 0.33000000000000007 , 0.2999999999999998 , 0.2849999999999999 ,
395
+ 0.2699999999999998 , 0.2549999999999999 , 0.23999999999999977 , 0.22499999999999987 , 0.20999999999999974 ,
396
+ 0.19499999999999984 , 0.17999999999999994 , 0.1649999999999998 , 0.1499999999999999 , 0.13818181818181818 ,
397
+ 0.12636363636363646 , 0.1145454545454545 , 0.10272727272727278 , 0.09090909090909083 , 0.0790909090909091 ,
398
+ 0.06727272727272737 , 0.043636363636363695 , 0.01200000000000001 , 0.008 , 0.0060750000000000005 , 0.00415 ,
399
+ 0.0022249999999999995 , 0.0002999999999999999 , 0.0
400
+ } ;
382
401
383
402
private readonly double _threshold ;
384
403
private readonly double _sensitivity ;
@@ -387,6 +406,8 @@ internal sealed class SrCnnEntireModeler
387
406
private readonly IDeseasonality _deseasonalityFunction ;
388
407
389
408
//used in all modes
409
+ private double _minimumOriginValue ;
410
+ private double _maximumOriginValue ;
390
411
private readonly double [ ] _predictArray ;
391
412
private double [ ] _backAddArray ;
392
413
private double [ ] _fftRe ;
@@ -449,10 +470,15 @@ public void Train(double[] values, ref double[][] results)
449
470
Array . Resize < double [ ] > ( ref results , values . Length ) ;
450
471
}
451
472
473
+ _minimumOriginValue = Double . MaxValue ;
474
+ _maximumOriginValue = Double . MinValue ;
475
+
452
476
Array . Resize ( ref _seriesToDetect , values . Length ) ;
453
477
for ( int i = 0 ; i < values . Length ; ++ i )
454
478
{
455
479
_seriesToDetect [ i ] = values [ i ] ;
480
+ _minimumOriginValue = Math . Min ( _minimumOriginValue , values [ i ] ) ;
481
+ _maximumOriginValue = Math . Max ( _maximumOriginValue , values [ i ] ) ;
456
482
}
457
483
458
484
if ( _period > 0 )
@@ -641,7 +667,7 @@ private void GetExpectedValue(double[] values, double[][] results)
641
667
642
668
for ( int i = 0 ; i < results . Length ; ++ i )
643
669
{
644
- results [ i ] [ 3 ] = _ifftRe [ i ] ;
670
+ results [ i ] [ 3 ] = AdjustExpectedValueBasedOnOriginalDataRange ( _ifftRe [ i ] ) ;
645
671
}
646
672
}
647
673
@@ -650,7 +676,7 @@ private void GetExpectedValuePeriod(double[] values, double[][] results, IReadOn
650
676
//Step 8: Calculate Expected Value
651
677
for ( int i = 0 ; i < values . Length ; ++ i )
652
678
{
653
- results [ i ] [ 3 ] = values [ i ] - residual [ i ] ;
679
+ results [ i ] [ 3 ] = AdjustExpectedValueBasedOnOriginalDataRange ( values [ i ] - residual [ i ] ) ;
654
680
}
655
681
}
656
682
@@ -762,7 +788,8 @@ private void GetMargin(double[] values, double[][] results, double sensitivity)
762
788
{
763
789
//Step 10: Calculate UpperBound and LowerBound
764
790
var margin = CalculateMargin ( _units [ i ] , sensitivity ) ;
765
- results [ i ] [ 3 ] = _ifftRe [ i ] ;
791
+ results [ i ] [ 3 ] = AdjustExpectedValueBasedOnOriginalDataRange ( _ifftRe [ i ] ) ;
792
+
766
793
results [ i ] [ 4 ] = _units [ i ] ;
767
794
results [ i ] [ 5 ] = _ifftRe [ i ] + margin ;
768
795
results [ i ] [ 6 ] = _ifftRe [ i ] - margin ;
@@ -783,6 +810,21 @@ private void GetMargin(double[] values, double[][] results, double sensitivity)
783
810
}
784
811
}
785
812
813
+ // Adjust the expected value if original data range is non-negative or non-positive
814
+ private double AdjustExpectedValueBasedOnOriginalDataRange ( double expectedValue )
815
+ {
816
+ if ( _minimumOriginValue >= 0 && expectedValue < 0 )
817
+ {
818
+ expectedValue = 0 ;
819
+ }
820
+ else if ( _maximumOriginValue <= 0 && expectedValue > 0 )
821
+ {
822
+ expectedValue = 0 ;
823
+ }
824
+
825
+ return expectedValue ;
826
+ }
827
+
786
828
// Adjust the expected value so that it is within the bound margin of value
787
829
private double AdjustExpectedValueBasedOnBound ( double value , double expectedValue , double unit )
788
830
{
@@ -880,18 +922,20 @@ private void CalculateExpectedValueByFft(double[] data)
880
922
FftUtils . ComputeBackwardFft ( _fftRe , _fftIm , _ifftRe , _ifftIm , length ) ;
881
923
}
882
924
883
- private void CalculateBoundaryUnit ( double [ ] data , bool [ ] isAnomalys )
925
+ private void CalculateBoundaryUnit ( double [ ] data , bool [ ] isAnomalies )
884
926
{
885
927
int window = Math . Min ( data . Length / 3 , 512 ) ;
886
928
double trendFraction = 0.5 ; // mix trend and average of trend
887
929
double trendSum = 0 ;
888
930
int calculationSize = 0 ;
931
+ bool closeToZero = true ;
889
932
890
933
MedianFilter ( data , window , true ) ;
891
934
for ( int i = 0 ; i < _trends . Length ; ++ i )
892
935
{
893
- if ( ! isAnomalys [ i ] )
936
+ if ( ! isAnomalies [ i ] )
894
937
{
938
+ closeToZero = closeToZero && _trends [ i ] < _eps ;
895
939
trendSum += Math . Abs ( _trends [ i ] ) ;
896
940
++ calculationSize ;
897
941
}
@@ -910,10 +954,17 @@ private void CalculateBoundaryUnit(double[] data, bool[] isAnomalys)
910
954
Array . Resize ( ref _units , _trends . Length ) ;
911
955
for ( int i = 0 ; i < _units . Length ; ++ i )
912
956
{
913
- _units [ i ] = Math . Max ( 1 , averageTrendPart + Math . Abs ( _trends [ i ] ) * trendFraction ) ;
914
- if ( double . IsInfinity ( _units [ i ] ) )
957
+ if ( closeToZero )
958
+ {
959
+ _units [ i ] = _unitForZero ;
960
+ }
961
+ else
915
962
{
916
- throw new ArithmeticException ( "Not finite unit value" ) ;
963
+ _units [ i ] = averageTrendPart + Math . Abs ( _trends [ i ] ) * trendFraction ;
964
+ if ( double . IsInfinity ( _units [ i ] ) )
965
+ {
966
+ throw new ArithmeticException ( "Not finite unit value" ) ;
967
+ }
917
968
}
918
969
}
919
970
}
@@ -1031,19 +1082,14 @@ private double CalculateAnomalyScore(double value, double exp, double unit, bool
1031
1082
return anomalyScore ;
1032
1083
}
1033
1084
1034
- double distance = Math . Abs ( exp - value ) ;
1035
- List < double > margins = new List < double > ( ) ;
1036
- for ( int i = 100 ; i >= 0 ; -- i )
1037
- {
1038
- margins . Add ( CalculateMargin ( unit , i ) ) ;
1039
- }
1085
+ double distanceFactor = Math . Abs ( exp - value ) / unit ;
1040
1086
1041
1087
int lb = 0 ;
1042
1088
int ub = 100 ;
1043
1089
while ( lb < ub )
1044
1090
{
1045
1091
int mid = ( lb + ub ) / 2 ;
1046
- if ( margins [ mid ] < distance )
1092
+ if ( _factors [ 100 - mid ] < distanceFactor )
1047
1093
{
1048
1094
lb = mid + 1 ;
1049
1095
}
@@ -1053,15 +1099,15 @@ private double CalculateAnomalyScore(double value, double exp, double unit, bool
1053
1099
}
1054
1100
}
1055
1101
1056
- if ( Math . Abs ( margins [ lb ] - distance ) < _eps || lb == 0 )
1102
+ if ( _factors [ 100 - lb ] == distanceFactor || lb == 0 )
1057
1103
{
1058
1104
anomalyScore = lb ;
1059
1105
}
1060
1106
else
1061
1107
{
1062
- double lowerMargin = margins [ lb - 1 ] ;
1063
- double upperMargin = margins [ lb ] ;
1064
- anomalyScore = lb - 1 + ( distance - lowerMargin ) / ( upperMargin - lowerMargin ) ;
1108
+ double lowerMargin = _factors [ 101 - lb ] ;
1109
+ double upperMargin = _factors [ 100 - lb ] ;
1110
+ anomalyScore = lb - 1 + ( distanceFactor - lowerMargin ) / ( upperMargin - lowerMargin ) ;
1065
1111
}
1066
1112
1067
1113
return anomalyScore / 100.0f ;
0 commit comments