Procházet zdrojové kódy

延时计算常规心率

master
H Vs před 2 měsíci
rodič
revize
63379d96ec
2 změnil soubory, kde provedl 479 přidání a 144 odebrání
  1. +42
    -17
      HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs
  2. +437
    -127
      HealthMonitor.WebApi/Worker.cs

+ 42
- 17
HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs Zobrazit soubor

@@ -52,6 +52,8 @@ namespace HealthMonitor.Service.Resolver
private readonly MqProcessLogic _serviceMqProcess; private readonly MqProcessLogic _serviceMqProcess;


private static int[] SCHEDULE_HOUR = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 }; private static int[] SCHEDULE_HOUR = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 };
// 延时胎心计算间隔周期
private static int INTERVAL_FHR=15;






@@ -102,8 +104,6 @@ namespace HealthMonitor.Service.Resolver
var messageId = _messageId.Value; var messageId = _messageId.Value;
var heartRate = _msgData.Value!; var heartRate = _msgData.Value!;




try try
{ {


@@ -379,9 +379,9 @@ namespace HealthMonitor.Service.Resolver


// 删除高频状态的首条记录 // 删除高频状态的首条记录
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
// 计算本次常规心率的胎心数据(高频结束后,实时处理)
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
// (逐条计算)计算本次常规心率的胎心数据(高频结束后,实时处理)
// await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
await CalculateNormalFetalHeartRateScheduleAsync(heartRate);


} }
///不满足持续10分钟highFreqSampleTimes或出现时间倒叙 ///不满足持续10分钟highFreqSampleTimes或出现时间倒叙
@@ -440,9 +440,9 @@ namespace HealthMonitor.Service.Resolver
} }
// 删除高频状态的首条记录 // 删除高频状态的首条记录
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
// 计算本次常规心率的胎心数据(高频结束后,实时处理)
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
// (逐条计算)计算本次常规心率的胎心数据(高频结束后,实时处理)
//await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
await CalculateNormalFetalHeartRateScheduleAsync(heartRate);
} }


// 删除高频状态的首条记录 // 删除高频状态的首条记录
@@ -450,8 +450,7 @@ namespace HealthMonitor.Service.Resolver


_logger.LogInformation($"{heartRate.Serialno} 超时结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{(firstTwoPhr[1] - phrFreqstatus!.LastUpdate).TotalSeconds} 秒"); _logger.LogInformation($"{heartRate.Serialno} 超时结束高频心率状态 timeDiffInSeconds {timeDiffInSeconds},highFreqSampleInterval:{highFreqSampleInterval},高频状态持续{(firstTwoPhr[1] - phrFreqstatus!.LastUpdate).TotalSeconds} 秒");


// 计算本次常规心率的胎心数据(高频结束后,实时处理)
//await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
//// 使用延后计算 //// 使用延后计算
//var fhrScheduleKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}"; //var fhrScheduleKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
//var fhrScheduleTTL = 60; //var fhrScheduleTTL = 60;
@@ -460,8 +459,6 @@ namespace HealthMonitor.Service.Resolver
// 常规心率(本次心率可能是高频心率的首条,所以要使用延后计算胎心率) // 常规心率(本次心率可能是高频心率的首条,所以要使用延后计算胎心率)
else else
{ {
// 计算本次常规心率的胎心数据
//await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);


// 本次心率可能是高频心率的首条,所以要使用本次常规心率延后计算胎心率 // 本次心率可能是高频心率的首条,所以要使用本次常规心率延后计算胎心率
//var fhrScheduleKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}"; //var fhrScheduleKey = $"health_monitor/schedule_push/cal_fetal_heart_rate/imei/{heartRate.Serialno}";
@@ -474,7 +471,7 @@ namespace HealthMonitor.Service.Resolver
{ {
try try
{ {
#region 休眠2秒
#region 休眠highFreqSampleInterval2秒
var startTime = DateTime.Now; var startTime = DateTime.Now;
//var highFreqSampleInterval2 = (int)watchConfig!["highFreqSampleInterval"]!+5; //var highFreqSampleInterval2 = (int)watchConfig!["highFreqSampleInterval"]!+5;
var highFreqSampleInterval2 = highFreqSampleInterval; var highFreqSampleInterval2 = highFreqSampleInterval;
@@ -493,8 +490,12 @@ namespace HealthMonitor.Service.Resolver
_logger.LogInformation($"phrFreqstatus.LastUpdate < heartRate.LastUpdate:{phrFreqstatus?.LastUpdate < heartRate.LastUpdate}"); _logger.LogInformation($"phrFreqstatus.LastUpdate < heartRate.LastUpdate:{phrFreqstatus?.LastUpdate < heartRate.LastUpdate}");
if (phrFreqstatus == null || phrFreqstatus.LastUpdate < heartRate.LastUpdate) if (phrFreqstatus == null || phrFreqstatus.LastUpdate < heartRate.LastUpdate)
{ {
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
_logger.LogInformation($"{heartRate.Serialno} 计算常规心率");
// (逐条计算)常规心率
//await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
//_logger.LogInformation($"{heartRate.Serialno} 计算常规心率");

// 延时计算常规心率
await CalculateNormalFetalHeartRateScheduleAsync(heartRate);
} }


} }
@@ -527,7 +528,7 @@ namespace HealthMonitor.Service.Resolver


} }
/// <summary> /// <summary>
/// 常规心率计算胎心数据
/// (逐条计算)常规心率计算胎心数据
/// </summary> /// </summary>
/// <param name="heartRate"></param> /// <param name="heartRate"></param>
/// <param name="upperAlarmThreshold"></param> /// <param name="upperAlarmThreshold"></param>
@@ -590,6 +591,30 @@ namespace HealthMonitor.Service.Resolver
await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR!, upperAlarmThreshold, lowerAlarmThreshold, phrValue, sampleTimeFHR, normalPhrStatStartTime, normalPhrStatEndTime); await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR!, upperAlarmThreshold, lowerAlarmThreshold, phrValue, sampleTimeFHR, normalPhrStatStartTime, normalPhrStatEndTime);
} }


/// <summary>
/// 延时计算
/// </summary>
/// <param name="heartRate"></param>
/// <returns></returns>
public async Task CalculateNormalFetalHeartRateScheduleAsync(HisGpsHeartRate heartRate)
{
var fhrScheduleKey = $"health_monitor/schedule_push/cal_normalphr_fetal_heart_rate/imei/{heartRate.Serialno}";

DateTime nowInterval = DateTime.Now;
if (nowInterval.Second > 0)
{
nowInterval = nowInterval.AddMinutes(1);
}
// 需要减去的分钟
int minutesToSubtract = nowInterval.Minute % INTERVAL_FHR;
var nextRunTime=nowInterval
.AddMinutes(-minutesToSubtract)
.AddMinutes(INTERVAL_FHR);
TimeSpan timeUntilNextRun = nextRunTime - nowInterval;
var ttl = (long)timeUntilNextRun.TotalSeconds;
await SetIntervalTriggerAsync(fhrScheduleKey, heartRate.Serialno, ttl, heartRate);
}

/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -859,6 +884,7 @@ namespace HealthMonitor.Service.Resolver
} }


} }
/// <summary> /// <summary>
/// 去除高频数据 /// 去除高频数据
/// </summary> /// </summary>
@@ -893,7 +919,6 @@ namespace HealthMonitor.Service.Resolver
return result; return result;
} }



/// <summary> /// <summary>
/// 获取高频数据 /// 获取高频数据
/// </summary> /// </summary>


+ 437
- 127
HealthMonitor.WebApi/Worker.cs Zobrazit soubor

@@ -59,6 +59,8 @@ namespace HealthMonitor.WebApi


private CancellationTokenSource _tokenSource = default!; private CancellationTokenSource _tokenSource = default!;


private static int INTERVAL_FHR = 15;

public Worker(ILogger<Worker> logger, IServiceProvider services, PersonCacheManager personCacheMgr, public Worker(ILogger<Worker> logger, IServiceProvider services, PersonCacheManager personCacheMgr,
BloodPressReferenceValueCacheManager bpRefValCacheManager, IotApiService IotApiService, BloodPressReferenceValueCacheManager bpRefValCacheManager, IotApiService IotApiService,
IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor, IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor,
@@ -274,16 +276,17 @@ namespace HealthMonitor.WebApi
} }
} }
// health_monitor/schedule_push/cal_fetal_heart_rate/imei/ // health_monitor/schedule_push/cal_fetal_heart_rate/imei/
// 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长
if (key.Contains("health_monitor/schedule_push/cal_freqhr_fetal_heart_rate/imei/")) if (key.Contains("health_monitor/schedule_push/cal_freqhr_fetal_heart_rate/imei/"))
{ {
/// 延时计算高频状态的胎心数据,防止高频结束后与触发数据时间相隔过长。 /// 延时计算高频状态的胎心数据,防止高频结束后与触发数据时间相隔过长。
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel); var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel);
// 高频不停,15分钟内只下发一条 // 高频不停,15分钟内只下发一条
var push =await _deviceCacheMgr.GetBizIntervalAsync(imeiDel, "SaveAndPushFetalHeartRate");
var push = await _deviceCacheMgr.GetBizIntervalAsync(imeiDel, "SaveAndPushFetalHeartRate");
var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!; var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!;
var trigger = triggerValue["trigger"]?.ToString(); var trigger = triggerValue["trigger"]?.ToString();
// 验证高频首条是否还存在 // 验证高频首条是否还存在
if (phrFreqstatus!=null && string.IsNullOrEmpty(push))
if (phrFreqstatus != null && string.IsNullOrEmpty(push))
{ {
if (!string.IsNullOrEmpty(trigger)) if (!string.IsNullOrEmpty(trigger))
{ {
@@ -316,7 +319,7 @@ namespace HealthMonitor.WebApi
var phrFromFreqstatus = phr.Where(i => i.LastUpdate >= phrFreqstatus.LastUpdate).ToList(); var phrFromFreqstatus = phr.Where(i => i.LastUpdate >= phrFreqstatus.LastUpdate).ToList();
// 高频数据 // 高频数据
var phrInFreqstatus = GetFreqPregnancyHeartRate(phrFromFreqstatus, highFreqSampleInterval) var phrInFreqstatus = GetFreqPregnancyHeartRate(phrFromFreqstatus, highFreqSampleInterval)
.OrderByDescending(i=>i.LastUpdate).ToList();
.OrderByDescending(i => i.LastUpdate).ToList();


if (phrInFreqstatus.Count > stopHighFreqSampleCount) if (phrInFreqstatus.Count > stopHighFreqSampleCount)
{ {
@@ -355,154 +358,187 @@ namespace HealthMonitor.WebApi
} }
} }
} }
else if (key.Contains("health_monitor/schedule_push/cal_fetal_heart_rate/imei/"))

// 延时计算常规胎心数据
else if (key.Contains("health_monitor/schedule_push/cal_normalphr_fetal_heart_rate/imei/"))
{ {
/**
var triggerValue= (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!;
var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!;
var trigger = triggerValue["trigger"]?.ToString(); var trigger = triggerValue["trigger"]?.ToString();
if (!string.IsNullOrEmpty(trigger)) if (!string.IsNullOrEmpty(trigger))
{ {
var triggerHeartRate= JsonConvert.DeserializeObject<HisGpsHeartRate>(trigger);
var triggerHeartRate = JsonConvert.DeserializeObject<HisGpsHeartRate>(trigger);
using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = triggerHeartRate?.MessageId! })) using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = triggerHeartRate?.MessageId! }))
{ {
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067"); var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067");
_logger.LogInformation($"触发常规心率计算胎心");
_logger.LogInformation($"{imeiDel}延迟常规胎心数据产生的胎心数据");
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;

if (isFetalHeartEnable) if (isFetalHeartEnable)
{ {
// 告警上限阀值
var upperAlarmThreshold = (int)watchConfig!["upperAlarmThreshold"]!;
// 告警下限阀值
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!;

// 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容(最小highFreqSampleInterval=60)
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! + 5 : 60;

var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel); var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel);

// 最后一条孕妇心率
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(imeiDel);
var isNormalHeartRate = triggerHeartRate?.MessageId == lastPhr.MessageId;
// 判断最后一条孕妇心率与解析器的触发心率是否一致
if (isNormalHeartRate)
if (commonPHR!=null)
{ {
//最后一条孕妇心率与解析器的触发心率一致
HisGpsHeartRate heartRate = new()
{
CreateTime = lastPhr.CreateTime,
DeviceKey = lastPhr.DeviceKey,
HeartRate = lastPhr.PregnancyHeartRate,
HeartRateId = lastPhr.PregnancyHeartRateId,
IsDisplay = lastPhr.IsDisplay ? 1 : 0,
MessageId = lastPhr.MessageId,
LastUpdate = lastPhr.LastUpdate,
Method = lastPhr.Method,
PersonId = lastPhr.PersonId,
Serialno = lastPhr.SerialNumber
};
var intervalFHR = 15;
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! : 60;
await CalculateNormalFetalHeartRateIntervalAsync(triggerHeartRate!, commonPHR, highFreqSampleInterval);
} }
// 最后一条孕妇心率与解析器的触发心率不一致,触发心率是高频心率的首条
else else
{ {
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 7);
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel);
if (phrFreqstatus != null)
{

#region 高频缓存
// 高频首条是触发心率,30秒后,高频第二条已经写入首条高频缓存
var diffCount = phr.Where(i => i.CreateTime >= phrFreqstatus.CreateTime && i.CreateTime <= lastPhr.CreateTime)
.OrderByDescending(i => i.CreateTime);
_logger.LogInformation($"{imeiDel} 存在高频缓存,高频心率首条记录${phrFreqstatus.MessageId},高频首条到当前的MSG ID{string.Join(",",diffCount.Select(i=>i.MessageId))}");
#endregion
}
// 不在高频状态状态,但触发孕妇心率与最后一条孕妇心率不一致,
// 常规心率数据是批量上报,需要计算每条心率对应的胎心数据
else
{
_logger.LogInformation($"{imeiDel} 常规心率数据是批量上报,需要计算每条心率对应的胎心数据");

#region 计算每条心率对应的胎心数据
phr = phr.OrderByDescending(i => i.LastUpdate).ToList();
// 获取高频数据
var freqCollection = new List<PregnancyHeartRateModel>();
PregnancyHeartRateModel? previousItem = null;
foreach (var item in phr)
{
if (previousItem != null)
{
var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
if (timeNextDiff <= highFreqSampleInterval)
{
freqCollection.Add(item);
}
}
previousItem = item;
}
//去除高频
foreach (var item in freqCollection)
{
phr.Remove(item);
}


// 排序并过滤高频数据
//var previousItem = phr.OrderByDescending(i => i.LastUpdate).ToList().First();
//phr = phr.Skip(1)
// .Where(item =>
// {
// var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
// previousItem = item;
// return timeNextDiff > highFreqSampleInterval;
// })
// .Prepend(previousItem)
// .OrderByDescending(i => i.LastUpdate)
// .ToList();

var calFhrTasks = phr.Where(p => p.LastUpdate >= triggerHeartRate!.LastUpdate)
.Select( async p =>
{
HisGpsHeartRate heartRate = new()
{
CreateTime = p.CreateTime,
DeviceKey = p.DeviceKey,
HeartRate = p.PregnancyHeartRate,
HeartRateId = p.PregnancyHeartRateId,
IsDisplay = p.IsDisplay ? 1 : 0,
MessageId = p.MessageId,
LastUpdate = p.LastUpdate,
Method = p.Method,
PersonId = p.PersonId,
Serialno = p.SerialNumber
};
var intervalFHR = 15;
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
});
await Task.WhenAll(calFhrTasks);
#endregion
}
_logger.LogWarning($"{imeiDel} 胎心数据建模中...");
} }
} }
else else
{ {
_logger.LogWarning($"{imeiDel} 胎心监测功能没有启");
_logger.LogWarning($"{imeiDel} 胎心监测功能没有启动");
} }
} }
} }
else
{
_logger.LogWarning($"{imeiDel} trigger is not set");
}
}
else if (key.Contains("health_monitor/schedule_push/cal_fetal_heart_rate/imei/"))
{


*/


/**
var triggerValue= (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!;
var trigger = triggerValue["trigger"]?.ToString();
if (!string.IsNullOrEmpty(trigger))
{
var triggerHeartRate= JsonConvert.DeserializeObject<HisGpsHeartRate>(trigger);
using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = triggerHeartRate?.MessageId! }))
{
var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(imeiDel, "0067");
_logger.LogInformation($"触发常规心率计算胎心");
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1;

if (isFetalHeartEnable)
{
// 告警上限阀值
var upperAlarmThreshold = (int)watchConfig!["upperAlarmThreshold"]!;
// 告警下限阀值
var lowerAlarmThreshold = (int)watchConfig["lowerAlarmThreshold"]!;

// 高频心率采样间隔 highFreqSampleInterval = highFreqSampleInterval+5,增加5秒兼容(最小highFreqSampleInterval=60)
var highFreqSampleInterval = (int)watchConfig!["highFreqSampleInterval"]! >= 60 ? (int)watchConfig!["highFreqSampleInterval"]! + 5 : 60;

var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel);

// 最后一条孕妇心率
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(imeiDel);
var isNormalHeartRate = triggerHeartRate?.MessageId == lastPhr.MessageId;
// 判断最后一条孕妇心率与解析器的触发心率是否一致
if (isNormalHeartRate)
{
//最后一条孕妇心率与解析器的触发心率一致
HisGpsHeartRate heartRate = new()
{
CreateTime = lastPhr.CreateTime,
DeviceKey = lastPhr.DeviceKey,
HeartRate = lastPhr.PregnancyHeartRate,
HeartRateId = lastPhr.PregnancyHeartRateId,
IsDisplay = lastPhr.IsDisplay ? 1 : 0,
MessageId = lastPhr.MessageId,
LastUpdate = lastPhr.LastUpdate,
Method = lastPhr.Method,
PersonId = lastPhr.PersonId,
Serialno = lastPhr.SerialNumber
};
var intervalFHR = 15;
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
}
// 最后一条孕妇心率与解析器的触发心率不一致,触发心率是高频心率的首条
else
{
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 7);
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel);
if (phrFreqstatus != null)
{

#region 高频缓存
// 高频首条是触发心率,30秒后,高频第二条已经写入首条高频缓存
var diffCount = phr.Where(i => i.CreateTime >= phrFreqstatus.CreateTime && i.CreateTime <= lastPhr.CreateTime)
.OrderByDescending(i => i.CreateTime);
_logger.LogInformation($"{imeiDel} 存在高频缓存,高频心率首条记录${phrFreqstatus.MessageId},高频首条到当前的MSG ID{string.Join(",",diffCount.Select(i=>i.MessageId))}");
#endregion
}
// 不在高频状态状态,但触发孕妇心率与最后一条孕妇心率不一致,
// 常规心率数据是批量上报,需要计算每条心率对应的胎心数据
else
{
_logger.LogInformation($"{imeiDel} 常规心率数据是批量上报,需要计算每条心率对应的胎心数据");

#region 计算每条心率对应的胎心数据
phr = phr.OrderByDescending(i => i.LastUpdate).ToList();
// 获取高频数据
var freqCollection = new List<PregnancyHeartRateModel>();
PregnancyHeartRateModel? previousItem = null;
foreach (var item in phr)
{
if (previousItem != null)
{
var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
if (timeNextDiff <= highFreqSampleInterval)
{
freqCollection.Add(item);
}
}
previousItem = item;
}
//去除高频
foreach (var item in freqCollection)
{
phr.Remove(item);
}


// 排序并过滤高频数据
//var previousItem = phr.OrderByDescending(i => i.LastUpdate).ToList().First();
//phr = phr.Skip(1)
// .Where(item =>
// {
// var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds;
// previousItem = item;
// return timeNextDiff > highFreqSampleInterval;
// })
// .Prepend(previousItem)
// .OrderByDescending(i => i.LastUpdate)
// .ToList();

var calFhrTasks = phr.Where(p => p.LastUpdate >= triggerHeartRate!.LastUpdate)
.Select( async p =>
{
HisGpsHeartRate heartRate = new()
{
CreateTime = p.CreateTime,
DeviceKey = p.DeviceKey,
HeartRate = p.PregnancyHeartRate,
HeartRateId = p.PregnancyHeartRateId,
IsDisplay = p.IsDisplay ? 1 : 0,
MessageId = p.MessageId,
LastUpdate = p.LastUpdate,
Method = p.Method,
PersonId = p.PersonId,
Serialno = p.SerialNumber
};
var intervalFHR = 15;
await CalculateNormalFetalHeartRateAsync(heartRate, upperAlarmThreshold, lowerAlarmThreshold, intervalFHR, commonPHR);
});
await Task.WhenAll(calFhrTasks);
#endregion
}
}
}
else
{
_logger.LogWarning($"{imeiDel} 胎心监测功能没有开启");
}
}
}
else
{
_logger.LogWarning($"{imeiDel} trigger is not set");
}

*/


} }
// 胎动计算 // 胎动计算
//health_monitor/schedule_push/cal_fetal_movement/imei/ //health_monitor/schedule_push/cal_fetal_movement/imei/
@@ -1026,7 +1062,7 @@ namespace HealthMonitor.WebApi
statStartTime = firstHmBp!.Timestamp; statStartTime = firstHmBp!.Timestamp;
} }


// NewMethod(systolicRefValue, hmBpParser);
// GetSampleTime(systolicRefValue, hmBpParser);


// 最大值 // 最大值
//systolicMax = (int)hmBpParser?.Select(i => i.SystolicValue).Max()!; //systolicMax = (int)hmBpParser?.Select(i => i.SystolicValue).Max()!;
@@ -1532,5 +1568,279 @@ namespace HealthMonitor.WebApi


return freqCollection; return freqCollection;
} }

public async Task CalculateNormalFetalHeartRateIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,int highFreqSampleInterval)
{
var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
var filteredPhr = daysPhr.Where(i => i.LastUpdate >= heartRate.LastUpdate && i.LastUpdate <= DateTime.Now).ToList();
// 去除高频
var normalPhr = GetNonFreqPregnancyHeartRate(filteredPhr, highFreqSampleInterval).OrderBy(i => i.LastUpdate);

var startPhr = normalPhr.First();
var endPhr = normalPhr.Last();

//var sampleTime = GetSampleTimeFromLastUpdate((DateTime)heartRate.LastUpdate!, INTERVAL_FHR);
// 数据统计边界
var boundaryStatStartTime = GetSampleTimeFromLastUpdate((DateTime)startPhr.LastUpdate!, INTERVAL_FHR);
var boundaryStatEndTime = GetSampleTimeFromLastUpdate((DateTime)endPhr.LastUpdate!, INTERVAL_FHR).AddMinutes(INTERVAL_FHR);

_logger.LogInformation($"{heartRate.Serialno} 统计边界{boundaryStatStartTime}-{boundaryStatEndTime}");

try
{
while (true)
{
var c = 0;
var segmentStatStartTime = boundaryStatStartTime.AddMinutes(c * INTERVAL_FHR);
var segmentStatEndTime = segmentStatStartTime.AddMinutes(INTERVAL_FHR);
c++;

var statStartTime = segmentStatStartTime;
var statEndTime = segmentStatEndTime;

_logger.LogInformation($"{heartRate.Serialno} 当前统计周期{statStartTime}-{statEndTime}");

var segmentPhr = daysPhr
.Where(i => i.LastUpdate <= statEndTime && i.LastUpdate >= statStartTime)
.ToList();

if (segmentPhr.Count == 0)
{
// 跳出当次迭代,进入下次迭代
_logger.LogWarning($"{heartRate.Serialno} 统计周期:{statStartTime}-{statEndTime} 孕妇心率数据不足,{segmentPhr.Count}条记录,不处理");
continue;
}

var sampleTime = DateTimeUtil.ConvertToTimeStamp(segmentStatStartTime).ToString();
sampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : sampleTime;

//检测 是否存在,不存在则处理
GeneralParam param = new()
{
Filters = new List<QueryFilterCondition>
{
new ()
{
Key=nameof(HisGpsFetalHeartRate.Serialno),
Value=heartRate.Serialno,
ValueType=QueryValueTypeEnum.String,
Operator=QueryOperatorEnum.Equal
},
new ()
{
Key=nameof(HisGpsFetalHeartRate.SampleTime),
Value=sampleTime,
ValueType=QueryValueTypeEnum.String,
Operator=QueryOperatorEnum.Equal
},

},
OrderBys = new List<OrderByCondition>
{
new (){
IsDesc=true,
Key=nameof(HisGpsFetalHeartRate.SampleTime)
}
}
};

var fhr = await _hisFetalHeartApiClient.GetFirstAsync(param, heartRate.Serialno[^2..], null, new RequestHeader { RequestId = Guid.NewGuid().ToString("D") });

if (fhr == null)
{
var avgPhr = segmentPhr.Count == 1
? segmentPhr.First().PregnancyHeartRate
: segmentPhr.Average(i => i.PregnancyHeartRate);

heartRate.HeartRate = (int)avgPhr;

#region 胎心系数使用基于心率与中位数对比
var coefficient = 0f;
// 孕妇心率少于中位数,取StatMinValueFprCoefficient
if (heartRate.HeartRate < commonPHR!.Mode)
{
coefficient = commonPHR.StatMinValueFprCoefficient!;
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率少于中位数,使用最小值系数 {coefficient}");
}
// 孕妇心率大于中位数,取StatMaxValueFprCoefficient与StatModeAvgFprCoefficient中少的那个
else if (heartRate.HeartRate > commonPHR.Mode)
{
if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMaxValueFprCoefficient)
{
coefficient = commonPHR.StatMaxValueFprCoefficient!;
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于中位数,使用最大值系数 {coefficient}");
}
else
{
coefficient = commonPHR.StatModeAvgFprCoefficient!;
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于中位数,使用均值系数 {coefficient}");
}
}
else
{
coefficient = commonPHR.StatModeAvgFprCoefficient;
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率等于中位数,使用均值系数 {coefficient}");
}
#endregion

#region 胎心阈值判断
//var fetalHeartRate = SafeType.SafeInt(heartRate.HeartRate * coefficient);
//// 胎心的最大值调整为220,超过都按该值220输出
//// fetalHeartRate = fetalHeartRate>= 220 ? 220 : fetalHeartRate;

//if (fetalHeartRate > 220)
//{
// fetalHeartRate = 220;
// _logger.LogWarning($"{heartRate.Serialno} 大于220,按220输出,计算因子:孕妇心率 {heartRate.HeartRate},系数 {coefficient},周期 周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
//}

//// 胎心的最小值调整为90,超过都按该值90
//if (fetalHeartRate < 90)
//{
// fetalHeartRate = 90;
// _logger.LogWarning($"{heartRate.Serialno} 小于90,按90输出,计算因子:孕妇心率 {heartRate.HeartRate},系数 {coefficient},周期 周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
//}


// 计算胎心率并进行边界检查
var fetalHeartRate = Math.Clamp((int)(heartRate.HeartRate * coefficient), 90, 220);
if (fetalHeartRate != (int)(heartRate.HeartRate * coefficient))
{
_logger.LogWarning($"{heartRate.Serialno} 胎心率超出范围, 按修正值 {fetalHeartRate} 输出, 计算因子:孕妇心率 {heartRate.HeartRate}, 系数 {coefficient}, 周期 {statStartTime} - {statEndTime}");
}

#endregion

_logger.LogInformation($"{heartRate.Serialno} 在 常规 状态,生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
var isAbnormal = 0;

#region 保存到Mysql数据库
// 保存到 数据服务 MySQL 数据库
HisGpsFetalHeartRate gpsFetalHeartRate = new()
{
FetalHeartRateId = Guid.NewGuid().ToString("D"),
PersonId = commonPHR!.PersonId,
Serialno = heartRate.Serialno,
HeartRate = fetalHeartRate,
SampleTime = sampleTime,
IsAbnormal = isAbnormal,
StatStartTime = statStartTime,
StatEndTime = statEndTime,//commonPHR.StatEndTime,
CreateTime = DateTime.Now,
Method = 1,
IsDisplay = 1,
DeviceKey = commonPHR!.DeviceKey
};
await _hisFetalHeartApiClient.AddAsync(gpsFetalHeartRate).ConfigureAwait(false);
#endregion

#region 推送最后一条常规心率计算的胎心数据到iot设备
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(heartRate.Serialno);
if (segmentStatEndTime == boundaryStatEndTime)
{
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
_logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备");
}
#endregion

#region 推送到第三方
var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(heartRate.Serialno).ConfigureAwait(false);
var fhrMsgId = $"{heartRate.Serialno}-{sampleTime}-{Guid.NewGuid().ToString("D")[^3..]}";
var fhrMsgTime = DateTimeUtil.GetDateTimeFromUnixTimeMilliseconds(long.Parse(sampleTime.Length < 13 ? sampleTime.PadRight(13, '0') : sampleTime)).ToString("yyyy-MM-dd HH:mm:ss");
var topic = "topic.push.third";
var fhrThridMsg = new
{
messageId = fhrMsgId,
topic = topic,
time = fhrMsgTime,
data = new
{
imei = heartRate.Serialno,
value = fetalHeartRate,
isAbnormal,
type = "fetalHeart"
}
};
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, 31, fhrThridMsg).ConfigureAwait(false);
#endregion

#region 推送到微信
if (isAbnormal != 0)
{

topic = "topic.push.wx";
var fhrMsg = new
{
messageId = fhrMsgId,
topic = topic,
time = fhrMsgTime,
data = new
{
deviceId = device?.DeviceId,
imei = heartRate.Serialno,
alarmTypeId = 12,
alarmDeviceName = heartRate.Serialno,
alarmRemarks = JsonConvert.SerializeObject(new { fetalHeartValue = fetalHeartRate, isAbnormal = isAbnormal }),
address = string.Empty,
deviceKey = device?.DeviceId
}
};
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, fhrMsg).ConfigureAwait(false);

}
#endregion

}
else
{
_logger.LogInformation($"{heartRate.Serialno},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")} ,胎心已处理");
}

// 跳出循环
if (statEndTime == boundaryStatEndTime)
{
break;
}
}
}
catch (Exception ex)
{
_logger.LogError($"处理心率数据时发生错误: {ex.Message}");
}


//for (var segmentStatStartTime = boundaryStatStartTime;
// segmentStatStartTime < boundaryStatEndTime;
// segmentStatStartTime = segmentStatStartTime.AddMinutes(INTERVAL_FHR))
//{
// var segmentStatEndTime = segmentStatStartTime.AddMinutes(INTERVAL_FHR);

// var segmentPhr = daysPhr
// .Where(i => i.LastUpdate <= segmentStatEndTime && i.LastUpdate >= segmentStatStartTime)
// .ToList();

// if (segmentStatEndTime == boundaryStatEndTime)
// {
// break;
// }
//}
}

private DateTime GetSampleTimeFromLastUpdate(DateTime lastUpdate,int interval)
{
DateTime nowInterval = lastUpdate;
if (nowInterval.Second > 0)
{
nowInterval = nowInterval.AddMinutes(1);
}
// 计算last_update到上一间隔的分钟数
int minutesToSubtract = nowInterval.Minute % interval;

// 计算上一间隔的时间
DateTime previousInterval = nowInterval.AddMinutes(-minutesToSubtract).AddSeconds(-nowInterval.Second).AddMilliseconds(-nowInterval.Millisecond);

return previousInterval;
}
} }
} }

Načítá se…
Zrušit
Uložit