forked from ddrilling/AsbCloudServer
Новые расчёты для автоматического определения операций
1. Поправел excel шаблон 2. Доработаны алгоритмы определения операций бурения 3. Небольшой рефакторинг DetectorAbstract, добавил метод для валидации 4. Закомментированы неиспользуемые детекторы. 5. Обновлена спецификация определения операций бурения 6. Добавлены тесты для определения операций бурения
This commit is contained in:
parent
afccdafebc
commit
8bbaca0d0c
Binary file not shown.
@ -14,7 +14,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations;
|
||||
|
||||
public class DetectedOperationExportService
|
||||
{
|
||||
private readonly DetectorAbstract[] detectors = { new DetectorDrilling(), new DetectorSlipsTime() };
|
||||
private readonly DetectorAbstract[] detectors = { new DetectorDrilling() };
|
||||
|
||||
private readonly IDictionary<int, string> domains = new Dictionary<int, string>
|
||||
{
|
||||
@ -122,10 +122,17 @@ public class DetectedOperationExportService
|
||||
row.Cell(columnDepthStart).Value = detectedOperations[i].DepthStart;
|
||||
row.Cell(columnDepthEnd).Value = detectedOperations[i].DepthEnd;
|
||||
row.Cell(columnDepth).Value = detectedOperations[i].DepthEnd - detectedOperations[i].DepthStart;
|
||||
row.Cell(columnIdReasonOfEnd).Value = detectedOperations[i].IdReasonOfEnd;
|
||||
row.Cell(columnIdReasonOfEnd).Value = detectedOperations[i].IdReasonOfEnd switch
|
||||
{
|
||||
0 => "Не определена",
|
||||
1 => "Не определено начало операции",
|
||||
101 => "Разница глубин забоя и положением долота",
|
||||
300 => "Низкое давление",
|
||||
_ => detectedOperations[i].IdReasonOfEnd
|
||||
};
|
||||
|
||||
var link =
|
||||
$"{domains[idDomain]}/well/{well.Id}/telemetry/monitoring?end={Uri.EscapeDataString(dateStart.AddSeconds(3544).ToString("yyyy-MM-ddTHH:mm:ss.fff"))}&range=3600";
|
||||
$"{domains[idDomain]}/well/{well.Id}/telemetry/monitoring?end={Uri.EscapeDataString(dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff"))}&range=1800";
|
||||
|
||||
row.Cell(columnDateStart).Value = dateStart;
|
||||
row.Cell(columnDateStart).SetHyperlink(new XLHyperlink(link));
|
||||
@ -191,10 +198,8 @@ public class DetectedOperationExportService
|
||||
var isDetected = false;
|
||||
var positionBegin = 0;
|
||||
var positionEnd = data.Length - gap;
|
||||
var step = 10;
|
||||
while (positionEnd > positionBegin)
|
||||
{
|
||||
step++;
|
||||
foreach (var detector in detectors)
|
||||
{
|
||||
if (!detector.TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out var result))
|
||||
@ -203,14 +208,11 @@ public class DetectedOperationExportService
|
||||
detectedOperations.Add(result!.Operation);
|
||||
lastDetectedOperation = result.Operation;
|
||||
isDetected = true;
|
||||
step = 1;
|
||||
positionBegin = result.TelemetryEnd;
|
||||
break;
|
||||
}
|
||||
|
||||
if (step > 20)
|
||||
step = 10;
|
||||
positionBegin += step;
|
||||
|
||||
positionBegin += 1;
|
||||
}
|
||||
|
||||
if (isDetected)
|
||||
|
@ -4,8 +4,7 @@ using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
|
||||
internal abstract class DetectorAbstract
|
||||
public abstract class DetectorAbstract
|
||||
{
|
||||
private readonly int stepLength = 3;
|
||||
|
||||
@ -34,14 +33,15 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
protected const int IdReasonOfEnd_Drilling = 600;
|
||||
|
||||
protected const int IdReasonOfEnd_Custom1 = 10_000;
|
||||
|
||||
public abstract Func<DetectableTelemetry[], int, int, int> GetIdOperation { get; }
|
||||
|
||||
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperation? previousOperation, out OperationDetectorResult? result)
|
||||
protected abstract Func<DetectableTelemetry[], int, int, int> GetIdOperation { get; }
|
||||
|
||||
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperation? previousOperation,
|
||||
out OperationDetectorResult? result)
|
||||
{
|
||||
// Проверка соответствия критерию начала операции
|
||||
if (DetectBegin(telemetry, begin, previousOperation))
|
||||
{
|
||||
{
|
||||
// Поиск окончания соответствия критерию
|
||||
int idReasonOfEnd = 0;
|
||||
var positionEnd = begin;
|
||||
@ -52,30 +52,31 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
break;
|
||||
|
||||
idReasonOfEnd = DetectEnd(telemetry, positionEnd, previousOperation);
|
||||
|
||||
if(idReasonOfEnd is IdReasonOfEnd_DeltaDepthIsHi or IdReasonOfEnd_PressureIsLo &&
|
||||
!IsValidByWellDepthDoesNotChange(telemetry, begin, positionEnd))
|
||||
break;
|
||||
|
||||
if (idReasonOfEnd != IdReasonOfEnd_NotDetected)
|
||||
|
||||
if (idReasonOfEnd != IdReasonOfEnd_NotDetected)
|
||||
break;
|
||||
}
|
||||
|
||||
result = null;
|
||||
result = MakeOperation(idTelemetry, telemetry, begin, positionEnd, idReasonOfEnd);
|
||||
return true;
|
||||
return result is not null;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation);
|
||||
protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
=> DetectBegin(telemetry, position, previousOperation)
|
||||
? IdReasonOfEnd_NotDetected
|
||||
: IdReasonOfEnd_NotDetectBegin;
|
||||
protected virtual bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult) =>
|
||||
operationDetectorResult.Operation.IdReasonOfEnd != IdReasonOfEnd_NotDetected;
|
||||
|
||||
private OperationDetectorResult MakeOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, int idReasonOfEnd)
|
||||
protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation);
|
||||
|
||||
protected virtual int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
=> DetectBegin(telemetry, position, previousOperation)
|
||||
? IdReasonOfEnd_NotDetected
|
||||
: IdReasonOfEnd_NotDetectBegin;
|
||||
|
||||
private OperationDetectorResult? MakeOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end,
|
||||
int idReasonOfEnd)
|
||||
{
|
||||
var pBegin = telemetry[begin];
|
||||
var pEnd = telemetry[end];
|
||||
@ -96,10 +97,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
IdReasonOfEnd = idReasonOfEnd,
|
||||
},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract bool IsValid(DetectableTelemetry[] telemetry, int begin, int end);
|
||||
return !IsValidOperationDetectorResult(result) ? null : result;
|
||||
}
|
||||
|
||||
protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end);
|
||||
|
||||
@ -118,16 +118,16 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
int fragmentLength)
|
||||
{
|
||||
var end = begin + fragmentLength;
|
||||
end = end < telemetry.Length
|
||||
? end
|
||||
end = end < telemetry.Length
|
||||
? end
|
||||
: telemetry.Length;
|
||||
var subData = telemetry[begin..end].Select(yGetter);
|
||||
if (end - begin > 10)
|
||||
{
|
||||
var ratio = (end - begin) / 5;
|
||||
subData = subData.Where((_,i) => i % ratio > 0);
|
||||
}
|
||||
|
||||
subData = subData.Where((_, i) => i % ratio > 0);
|
||||
}
|
||||
|
||||
var avg = subData.Average();
|
||||
return avg;
|
||||
}
|
||||
@ -189,9 +189,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
protected static (double min, double max, double sum, int count) CalcStat(
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
int count)
|
||||
{
|
||||
var sum = 0d;
|
||||
@ -210,6 +210,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
max = itemValue;
|
||||
sum += itemValue;
|
||||
}
|
||||
|
||||
return (min, max, sum, end - begin);
|
||||
}
|
||||
|
||||
@ -256,7 +257,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
var end = begin + count;
|
||||
end = end < telemetry.Length ? end : telemetry.Length;
|
||||
|
||||
for (var i = begin; i < end; i ++)
|
||||
for (var i = begin; i < end; i++)
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
@ -264,9 +265,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
min = itemValue;
|
||||
if (max < itemValue)
|
||||
max = itemValue;
|
||||
if(max - min > deviation)
|
||||
if (max - min > deviation)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -290,8 +292,8 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
var max = double.MinValue;
|
||||
var end = begin + count;
|
||||
end = end < telemetry.Length ? end : telemetry.Length;
|
||||
var step = count > 15 ? count / 5 : count > 3 ? 3: 1;
|
||||
for (var i = begin; i < end; i+= step)
|
||||
var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
|
||||
for (var i = begin; i < end; i += step)
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
@ -302,6 +304,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
if (max - min > deviation)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -323,6 +326,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
if (Math.Abs(beginPointValue - itemValue) > deviation)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -341,13 +345,12 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
if ( itemValue - beginPointValue > deviation)
|
||||
if (itemValue - beginPointValue > deviation)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,68 +1,66 @@
|
||||
using System;
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Проработка перед наращиванием
|
||||
/// </summary>
|
||||
internal class DetectorDevelopment : DetectorAbstract
|
||||
{
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcDeltaMinutes(telemetry, begin, end);
|
||||
|
||||
public override Func<DetectableTelemetry[], int, int, int> GetIdOperation => (_, _, _)
|
||||
=> WellOperationCategory.IdDevelopment;
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
if (previousOperation?.IdCategory == WellOperationCategory.IdSlipsTime)
|
||||
return false;
|
||||
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta < 0.03d || delta > 30)
|
||||
return false;
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return false;
|
||||
|
||||
if (point0.BlockPosition > 2.5)
|
||||
return false;
|
||||
|
||||
if (point0.RotorSpeed < 10)
|
||||
return false;
|
||||
|
||||
if (!ContainsDeviationApprox(telemetry, d => d.BlockPosition, position, 60, 0.03))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta < 0.03d || delta > 30)
|
||||
return IdReasonOfEnd_DeltaDepthOutOfRange;
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return IdReasonOfEnd_PressureIsLo;
|
||||
|
||||
if (point0.BlockPosition > 31)
|
||||
return IdReasonOfEnd_BlockPositionIsHi;
|
||||
|
||||
if (point0.RotorSpeed < 10)
|
||||
return IdReasonOfEnd_RotorSpeedIsLo;
|
||||
|
||||
return IdReasonOfEnd_NotDetected;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// using System;
|
||||
// using AsbCloudDb.Model;
|
||||
//
|
||||
// namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
// {
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Проработка перед наращиванием
|
||||
// /// </summary>
|
||||
// internal class DetectorDevelopment : DetectorAbstract
|
||||
// {
|
||||
// protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
// => CalcDeltaMinutes(telemetry, begin, end);
|
||||
//
|
||||
// public override Func<DetectableTelemetry[], int, int, int> GetIdOperation => (_, _, _)
|
||||
// => WellOperationCategory.IdDevelopment;
|
||||
//
|
||||
// protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
// {
|
||||
// if (previousOperation?.IdCategory == WellOperationCategory.IdSlipsTime)
|
||||
// return false;
|
||||
//
|
||||
// var point0 = telemetry[position];
|
||||
// var delta = point0.WellDepth - point0.BitDepth;
|
||||
// if (delta < 0.03d || delta > 30)
|
||||
// return false;
|
||||
//
|
||||
// if (point0.Pressure < 15)
|
||||
// return false;
|
||||
//
|
||||
// if (point0.BlockPosition > 2.5)
|
||||
// return false;
|
||||
//
|
||||
// if (point0.RotorSpeed < 10)
|
||||
// return false;
|
||||
//
|
||||
// if (!ContainsDeviationApprox(telemetry, d => d.BlockPosition, position, 60, 0.03))
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// protected override int DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
// {
|
||||
// var point0 = telemetry[position];
|
||||
// var delta = point0.WellDepth - point0.BitDepth;
|
||||
// if (delta < 0.03d || delta > 30)
|
||||
// return IdReasonOfEnd_DeltaDepthOutOfRange;
|
||||
//
|
||||
// if (point0.Pressure < 15)
|
||||
// return IdReasonOfEnd_PressureIsLo;
|
||||
//
|
||||
// if (point0.BlockPosition > 31)
|
||||
// return IdReasonOfEnd_BlockPositionIsHi;
|
||||
//
|
||||
// if (point0.RotorSpeed < 10)
|
||||
// return IdReasonOfEnd_RotorSpeedIsLo;
|
||||
//
|
||||
// return IdReasonOfEnd_NotDetected;
|
||||
// }
|
||||
//
|
||||
// protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
// => IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
@ -4,9 +4,9 @@ using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||
|
||||
internal class DetectorDrilling : DetectorAbstract
|
||||
public class DetectorDrilling : DetectorAbstract
|
||||
{
|
||||
public override Func<DetectableTelemetry[], int, int, int> GetIdOperation => DefineDrillingOperation;
|
||||
protected override Func<DetectableTelemetry[], int, int, int> GetIdOperation => DefineDrillingOperation;
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
@ -18,9 +18,6 @@ internal class DetectorDrilling : DetectorAbstract
|
||||
if (point0.Pressure < 25)
|
||||
return false;
|
||||
|
||||
if (point0.RotorSpeed < 5)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -37,26 +34,38 @@ internal class DetectorDrilling : DetectorAbstract
|
||||
|
||||
return IdReasonOfEnd_NotDetected;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthIncreasing(telemetry, begin, end);
|
||||
|
||||
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcRop(telemetry, begin, end);
|
||||
|
||||
protected override bool IsValidOperationDetectorResult(OperationDetectorResult operationDetectorResult) =>
|
||||
operationDetectorResult.Operation.IdReasonOfEnd is IdReasonOfEnd_DeltaDepthIsHi or IdReasonOfEnd_PressureIsLo &&
|
||||
Math.Abs(operationDetectorResult.Operation.DepthStart - operationDetectorResult.Operation.DepthEnd) > 0.01;
|
||||
|
||||
private static int DefineDrillingOperation(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
{
|
||||
const int idSlideWithOscillation = 12000;
|
||||
|
||||
var telemetryRange = telemetry[begin.. end];
|
||||
|
||||
var telemetryRange = telemetry[begin.. end]
|
||||
.OrderBy(x => x.DateTime).ToList();
|
||||
|
||||
for (var i = telemetryRange.Count - 1; i >= 0 && telemetryRange.Count > 1; i--)
|
||||
{
|
||||
if (Math.Abs(telemetryRange[i].WellDepth - telemetryRange[i - 1].WellDepth) < 0.001d)
|
||||
{
|
||||
telemetryRange.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
var avgRotorSpeed = telemetryRange.Average(t => t.RotorSpeed);
|
||||
|
||||
|
||||
if (avgRotorSpeed < 10)
|
||||
return WellOperationCategory.IdSlide;
|
||||
|
||||
var despersion = telemetryRange
|
||||
.Average(t => Math.Pow((t.RotorSpeed - avgRotorSpeed) / avgRotorSpeed, 2));
|
||||
|
||||
var despersion = telemetryRange.Average(t => Math.Pow(t.RotorSpeed/avgRotorSpeed - 1, 2));
|
||||
|
||||
return despersion < 0.2d ? WellOperationCategory.IdRotor : idSlideWithOscillation;
|
||||
}
|
||||
|
@ -1,39 +1,39 @@
|
||||
using System;
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
|
||||
internal class DetectorSlipsTime : DetectorAbstract
|
||||
{
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcDeltaMinutes(telemetry, begin, end);
|
||||
|
||||
public override Func<DetectableTelemetry[], int, int, int> GetIdOperation => (_, _, _) => WellOperationCategory.IdSlipsTime;
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 2.5d)
|
||||
return false;
|
||||
|
||||
if (point0.Pressure > 15)
|
||||
return false;
|
||||
|
||||
if (point0.BlockPosition > 8)
|
||||
return false;
|
||||
|
||||
if (point0.HookWeight > 20)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// using System;
|
||||
// using AsbCloudDb.Model;
|
||||
//
|
||||
// namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
// {
|
||||
//
|
||||
// internal class DetectorSlipsTime : DetectorAbstract
|
||||
// {
|
||||
// protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
// => CalcDeltaMinutes(telemetry, begin, end);
|
||||
//
|
||||
// public override Func<DetectableTelemetry[], int, int, int> GetIdOperation => (_, _, _) => WellOperationCategory.IdSlipsTime;
|
||||
//
|
||||
// protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
// {
|
||||
// var point0 = telemetry[position];
|
||||
// var delta = point0.WellDepth - point0.BitDepth;
|
||||
// if (delta > 2.5d)
|
||||
// return false;
|
||||
//
|
||||
// if (point0.Pressure > 15)
|
||||
// return false;
|
||||
//
|
||||
// if (point0.BlockPosition > 8)
|
||||
// return false;
|
||||
//
|
||||
// if (point0.HookWeight > 20)
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
// => IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// }
|
||||
//
|
||||
|
@ -1,29 +1,27 @@
|
||||
Метод определения бурения
|
||||
# Алгоритм определения бурения в роторе, слайде, слайде с осцилляцией
|
||||
|
||||
Признак начала операции =
|
||||
## Метод определения операции бурения
|
||||
|
||||
расстояние от долота до забоя < 0.03м И
|
||||
Признак начала операции =
|
||||
(расстояние от долота до забоя < 0.03м) И
|
||||
(давление > 25атм)
|
||||
|
||||
Признак окончания операции =
|
||||
(расстояние от долота до забоя > 0.03м) ИЛИ
|
||||
(давление < 25атм)
|
||||
|
||||
давление > 25атм
|
||||
## Валидация
|
||||
Для точного определения операции бурения, необходимо убрать диапазон в которых сработал признак окончания операции и не менялась глубина:
|
||||
Определили точку окончания операции исходя из Признак окончания операции.
|
||||
Определяем временной интервал, когда не менялась глубина (т.е. время шло, а глубина была неизменна)
|
||||
Определив начальную точку и точку окончания операции
|
||||
Исключаем этот интервал из операции.
|
||||
|
||||
Признак окончания операции =
|
||||
## Метод определения бурения в слайде
|
||||
Необходимо рассчитать средние обороты ротора за всю операцию бурения.
|
||||
Если среднее арифметическое больше константы (10 об/мин), то это бурение в роторе, если меньше, то это бурение в слайде.
|
||||
|
||||
расстояние от долота до забоя > 0.03м ИЛИ
|
||||
|
||||
давление < 25атм
|
||||
|
||||
Находим границы
|
||||
|
||||
После того когда мы нашли границы, мы должны определить операцию, тогда мы смотрим на забой точки окончания операций сравниваем с забоем точками начала операций:
|
||||
|
||||
Если они равны друг другу, то мы эту операцию дальше не обрабатываем, а выбрасываем.
|
||||
|
||||
Если они не равны, то у нас произошло увеличение забоя, значит эта операция бурения.
|
||||
|
||||
Дальше мы определяем как мы бурили в роторе или слайде, для этого нам необходимо рассчитать среднюю скорость(среднее арифметическое) за всю операцию бурения . Если среднее арифметическое больше константы (10 об/мин), то это бурение в роторе, если меньше, то это бурение в слайде.
|
||||
|
||||
Если бурение в роторе, то мы считаем только дисперсию нормированных оборотов ротора(по среднему значению). (Так как это может быть бурение в слайде с осцилляцией и выглядеть как бурение в роторе):
|
||||
|
||||
Если полученное значение меньше константы(0,2), то мы подтвердили что бурение в роторе.
|
||||
|
||||
Если полученное значение больше константы, то это бурение в слайде с осцилляцией.
|
||||
## Метод определения бурения в роторе, слайде с осцилляцией
|
||||
Необходимо рассчитать десперсию нормированных оборотов ротора по(по среднему значению)
|
||||
1. Если полученное значение больше константы(0,2), то мы подтвердили что бурение в роторе.
|
||||
2. Если полученное значение меньше константы, то это бурение в слайде с осцилляцией.
|
@ -16,11 +16,11 @@ public class WorkOperationDetection: Work
|
||||
{
|
||||
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
|
||||
{
|
||||
new DetectorDrilling()
|
||||
// new DetectorRotor(),
|
||||
// new DetectorSlide(),
|
||||
//new DetectorDevelopment(),
|
||||
//new DetectorTemplating(),
|
||||
new DetectorSlipsTime(),
|
||||
//new DetectorStaticSurveying(),
|
||||
//new DetectorFlashingBeforeConnection(),
|
||||
//new DetectorFlashing(),
|
||||
@ -116,7 +116,6 @@ public class WorkOperationDetection: Work
|
||||
{
|
||||
var data = await query
|
||||
.Where(d => d.DateTime > startDate)
|
||||
.Take(take)
|
||||
.ToArrayAsync(token);
|
||||
|
||||
if (data.Length < gap)
|
||||
@ -125,25 +124,21 @@ public class WorkOperationDetection: Work
|
||||
var isDetected = false;
|
||||
var positionBegin = 0;
|
||||
var positionEnd = data.Length - gap;
|
||||
var step = 10;
|
||||
while (positionEnd > positionBegin)
|
||||
{
|
||||
step ++;
|
||||
for (int i = 0; i < detectors.Length; i++)
|
||||
foreach (var detector in detectors)
|
||||
{
|
||||
if (detectors[i].TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out OperationDetectorResult? result))
|
||||
{
|
||||
detectedOperations.Add(result!.Operation);
|
||||
lastDetectedOperation = result.Operation;
|
||||
isDetected = true;
|
||||
step = 1;
|
||||
positionBegin = result.TelemetryEnd;
|
||||
break;
|
||||
}
|
||||
if (!detector.TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out var result))
|
||||
continue;
|
||||
|
||||
detectedOperations.Add(result!.Operation);
|
||||
lastDetectedOperation = result.Operation;
|
||||
isDetected = true;
|
||||
positionBegin = result.TelemetryEnd;
|
||||
break;
|
||||
}
|
||||
if (step > 20)
|
||||
step = 10;
|
||||
positionBegin += step;
|
||||
|
||||
positionBegin += 1;
|
||||
}
|
||||
|
||||
if (isDetected)
|
||||
|
@ -0,0 +1,290 @@
|
||||
using System.Collections.Generic;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||
using Xunit;
|
||||
|
||||
namespace AsbCloudWebApi.Tests.Services.DetectedOperations.Detectors;
|
||||
|
||||
public class DetectorDrillingTests : DetectorDrilling
|
||||
{
|
||||
private const int idSlide = 5002;
|
||||
private const int idRotor = 5003;
|
||||
private const int idSlideWithOscillation = 12000;
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TelemetryRangeDrillingRotor))]
|
||||
public void DefineDrillingOperation_ShouldReturn_DrillingRotor(DetectableTelemetry[] telemetryRange)
|
||||
{
|
||||
//act
|
||||
var result = GetIdOperation.Invoke(telemetryRange, 0, telemetryRange.Length);
|
||||
|
||||
//assert
|
||||
Assert.Equal(idRotor, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TelemetryRangeDrillingSlide))]
|
||||
public void DefineDrillingOperation_ShouldReturn_DrillingSlide(DetectableTelemetry[] telemetryRange)
|
||||
{
|
||||
//act
|
||||
var result = GetIdOperation.Invoke(telemetryRange, 0, telemetryRange.Length);
|
||||
|
||||
//assert
|
||||
Assert.Equal(idSlide, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TelemetryRangeDrillingSlideWithOscillation))]
|
||||
public void DefineDrillingOperation_ShouldReturn_DrillingSlideWithOscillation(DetectableTelemetry[] telemetryRange)
|
||||
{
|
||||
//act
|
||||
var result = GetIdOperation.Invoke(telemetryRange, 0, telemetryRange.Length);
|
||||
|
||||
//assert
|
||||
Assert.Equal(idSlideWithOscillation, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidOperationDetectorResult_ShouldReturn_True()
|
||||
{
|
||||
//arrange
|
||||
var operationDetectorResult = new OperationDetectorResult
|
||||
{
|
||||
Operation = new DetectedOperation
|
||||
{
|
||||
IdReasonOfEnd = IdReasonOfEnd_PressureIsLo,
|
||||
DepthStart = 5000,
|
||||
DepthEnd = 6000
|
||||
}
|
||||
};
|
||||
|
||||
//act
|
||||
var result = IsValidOperationDetectorResult(operationDetectorResult);
|
||||
|
||||
//assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidOperationDetectorResult_ShouldReturn_False()
|
||||
{
|
||||
//arrange
|
||||
var operationDetectorResult = new OperationDetectorResult
|
||||
{
|
||||
Operation = new DetectedOperation
|
||||
{
|
||||
IdReasonOfEnd = IdReasonOfEnd_PressureIsLo,
|
||||
DepthStart = 5000,
|
||||
DepthEnd = 5000
|
||||
}
|
||||
};
|
||||
|
||||
//act
|
||||
var result = IsValidOperationDetectorResult(operationDetectorResult);
|
||||
|
||||
//assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TelemetryRangeDrillingRotor()
|
||||
{
|
||||
yield return new object[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 4.187f,
|
||||
Pressure = 27.815952f,
|
||||
HookWeight = 34.221367f,
|
||||
BlockPosition = 24.388f,
|
||||
BitDepth = 4.187f,
|
||||
RotorSpeed = 40.3f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 4.232f,
|
||||
Pressure = 28.080372f,
|
||||
HookWeight = 34.162174f,
|
||||
BlockPosition = 24.343f,
|
||||
BitDepth = 4.232f,
|
||||
RotorSpeed = 40.3f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 4.277f,
|
||||
Pressure = 29.047901f,
|
||||
HookWeight = 33.688717f,
|
||||
BlockPosition = 24.298f,
|
||||
BitDepth = 24.298f,
|
||||
RotorSpeed = 40.3f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 4.309f,
|
||||
Pressure = 29.574032f,
|
||||
HookWeight = 33.692104f,
|
||||
BlockPosition = 24.266f,
|
||||
BitDepth = 4.309f,
|
||||
RotorSpeed = 40.4f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 4.324f,
|
||||
Pressure = 24.007977f,
|
||||
HookWeight = 34.838448f,
|
||||
BlockPosition = 24.251f,
|
||||
BitDepth = 4.324f,
|
||||
RotorSpeed = 40.5f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 4.324f,
|
||||
Pressure = 24.04114f,
|
||||
HookWeight = 34.423424f,
|
||||
BlockPosition = 24.252f,
|
||||
BitDepth = 4.323f,
|
||||
RotorSpeed = 40.3f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TelemetryRangeDrillingSlide()
|
||||
{
|
||||
yield return new object[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 447.276001f,
|
||||
Pressure = 26.619421f,
|
||||
HookWeight = 40.9143829f,
|
||||
BlockPosition = 4.559f,
|
||||
BitDepth = 477.265991f,
|
||||
RotorSpeed = 0
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 477.289f,
|
||||
Pressure = 28.716f,
|
||||
HookWeight = 38.27f,
|
||||
BlockPosition = 4.5f,
|
||||
BitDepth = 477.289f,
|
||||
RotorSpeed = 0.1f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
WellDepth = 477.30899f,
|
||||
Pressure = 33.953495f,
|
||||
HookWeight = 38.27f,
|
||||
BlockPosition = 4.5359997f,
|
||||
BitDepth = 477.289001f,
|
||||
RotorSpeed = 0.1f
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TelemetryRangeDrillingSlideWithOscillation()
|
||||
{
|
||||
yield return new object[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.306f,
|
||||
Pressure = 53.731934f,
|
||||
HookWeight = 41.049942f,
|
||||
BlockPosition = 28.666f,
|
||||
BitDepth = 415.293f,
|
||||
RotorSpeed = 0.3f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.311f,
|
||||
Pressure = 57.660595f,
|
||||
HookWeight = 40.898712f,
|
||||
BlockPosition = 28.648f,
|
||||
BitDepth = 415.311f,
|
||||
RotorSpeed = 0.2f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.326f,
|
||||
Pressure = 59.211086f,
|
||||
HookWeight = 40.882797f,
|
||||
BlockPosition = 28.633f,
|
||||
BitDepth = 415.326f,
|
||||
RotorSpeed = 0.1f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.344f,
|
||||
Pressure = 59.484406f,
|
||||
HookWeight = 40.91972f,
|
||||
BlockPosition = 28.615f,
|
||||
BitDepth = 415.344f,
|
||||
RotorSpeed = 0.2f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.364f,
|
||||
Pressure = 60.739918f,
|
||||
HookWeight = 40.795666f,
|
||||
BlockPosition = 28.595f,
|
||||
BitDepth = 415.364f,
|
||||
RotorSpeed = 4.5f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.378f,
|
||||
Pressure = 62.528984f,
|
||||
HookWeight = 40.52114f,
|
||||
BlockPosition = 28.581f,
|
||||
BitDepth = 415.378f,
|
||||
RotorSpeed = 22.6f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.392f,
|
||||
Pressure = 67.0039f,
|
||||
HookWeight = 38.878895f,
|
||||
BlockPosition = 28.569f,
|
||||
BitDepth = 415.39f,
|
||||
RotorSpeed = 50f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.392f,
|
||||
Pressure = 65.72418f,
|
||||
HookWeight = 42.53173f,
|
||||
BlockPosition = 28.622f,
|
||||
BitDepth = 415.337f,
|
||||
RotorSpeed = 93f
|
||||
},
|
||||
new DetectableTelemetry
|
||||
{
|
||||
IdUser = 1,
|
||||
WellDepth = 415.392f,
|
||||
Pressure = 56.82195f,
|
||||
HookWeight = 43.15844f,
|
||||
BlockPosition = 28.704f,
|
||||
BitDepth = 415.255f,
|
||||
RotorSpeed = 71.5f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user