|
|
@@ -274,6 +274,87 @@ namespace HealthMonitor.WebApi |
|
|
|
} |
|
|
|
} |
|
|
|
// health_monitor/schedule_push/cal_fetal_heart_rate/imei/ |
|
|
|
if (key.Contains("health_monitor/schedule_push/cal_freqhr_fetal_heart_rate/imei/")) |
|
|
|
{ |
|
|
|
/// 延时计算高频状态的胎心数据,防止高频结束后与触发数据时间相隔过长。 |
|
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(imeiDel); |
|
|
|
// 高频不停,15分钟内只下发一条 |
|
|
|
var push =await _deviceCacheMgr.GetBizIntervalAsync(imeiDel, "SaveAndPushFetalHeartRate"); |
|
|
|
var triggerValue = (JObject)JsonConvert.DeserializeObject(e.PrevKv.Value.ToStringUtf8())!; |
|
|
|
var trigger = triggerValue["trigger"]?.ToString(); |
|
|
|
// 验证高频首条是否还存在 |
|
|
|
if (phrFreqstatus!=null && string.IsNullOrEmpty(push)) |
|
|
|
{ |
|
|
|
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($"{imeiDel}高频结束后,延迟计算高频数据产生的胎心数据"); |
|
|
|
var isFetalHeartEnable = watchConfig != null && (int)watchConfig["enabled"]! == 1; |
|
|
|
if (isFetalHeartEnable) |
|
|
|
{ |
|
|
|
// 防止超过12条连续正常,高频不停止 |
|
|
|
if (phrFreqstatus.MessageId == triggerHeartRate?.MessageId) |
|
|
|
{ |
|
|
|
// 告警上限阀值 |
|
|
|
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 stopHighFreqSampleCount = (int)watchConfig["stopHighFreqSampleCount"]!; |
|
|
|
|
|
|
|
var commonPHR = await _serviceTDengine.GetLastAsync<PregnancyCommonHeartRateModel>(imeiDel); |
|
|
|
|
|
|
|
|
|
|
|
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(imeiDel, 7); |
|
|
|
var phrFromFreqstatus = phr.Where(i => i.LastUpdate >= phrFreqstatus.LastUpdate).ToList(); |
|
|
|
// 高频数据 |
|
|
|
var phrInFreqstatus = GetFreqPregnancyHeartRate(phrFromFreqstatus, highFreqSampleInterval) |
|
|
|
.OrderByDescending(i=>i.LastUpdate).ToList(); |
|
|
|
|
|
|
|
if (phrInFreqstatus.Count > stopHighFreqSampleCount) |
|
|
|
{ |
|
|
|
// 取最后 stopHighFreqSampleCount 条高频数据 |
|
|
|
phrInFreqstatus = phrInFreqstatus |
|
|
|
.OrderByDescending(i => i.LastUpdate) |
|
|
|
.Take(stopHighFreqSampleCount).ToList(); // 计算最后12条 |
|
|
|
|
|
|
|
var avgPhr = phrInFreqstatus |
|
|
|
.Select(i => i.PregnancyHeartRate).Average(); |
|
|
|
|
|
|
|
var FreqStatsEnd = phrInFreqstatus.First().LastUpdate; |
|
|
|
|
|
|
|
_logger.LogInformation($"延时计算,{imeiDel} 高频状态持续{(FreqStatsEnd - phrFreqstatus!.LastUpdate).TotalSeconds} 秒,统计周期:{phrFreqstatus!.LastUpdate.ToString("yyyy-MM-dd HH:mm:ss")}----{FreqStatsEnd.ToString("yyyy-MM-dd HH:mm:ss")},将下发指令"); |
|
|
|
|
|
|
|
await SaveAndPushFetalHeartRateAsync(triggerHeartRate, commonPHR, upperAlarmThreshold, lowerAlarmThreshold, avgPhr, DateTimeUtil.ConvertToTimeStamp(phrFreqstatus!.LastUpdate).ToString(), phrFreqstatus!.LastUpdate, FreqStatsEnd); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogWarning($"{imeiDel} 高频心率的数据不大于{stopHighFreqSampleCount}条,不进行高频数据的胎心计算"); |
|
|
|
|
|
|
|
} |
|
|
|
// 删除高频状态的首条记录 |
|
|
|
await _deviceCacheMgr.DelPregnancyHeartRateFreqStatusAsync(imeiDel); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogWarning($"{imeiDel} 超过12条连续正常,高频不停止,暂不处理"); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_logger.LogWarning($"{imeiDel} 胎心监测功能没有启动"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else if (key.Contains("health_monitor/schedule_push/cal_fetal_heart_rate/imei/")) |
|
|
|
{ |
|
|
|
/** |
|
|
@@ -1191,67 +1272,13 @@ namespace HealthMonitor.WebApi |
|
|
|
return timeRanges.Any(range => now >= range.Start && now <= range.End); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task CalculateNormalFetalHeartRateAsync(HisGpsHeartRate heartRate, int upperAlarmThreshold, int lowerAlarmThreshold, int intervalFHR, PregnancyCommonHeartRateModel? commonPHR) |
|
|
|
{ |
|
|
|
// 上15分钟的数据 |
|
|
|
// 获取当前时间 |
|
|
|
DateTime nowInterval = (DateTime)heartRate.LastUpdate!; |
|
|
|
|
|
|
|
if (nowInterval.Second > 0) |
|
|
|
{ |
|
|
|
nowInterval = nowInterval.AddMinutes(1); |
|
|
|
} |
|
|
|
// 计算last_update到上一间隔的分钟数 |
|
|
|
int minutesToSubtract = nowInterval.Minute % intervalFHR; |
|
|
|
|
|
|
|
// 计算上一间隔的时间 |
|
|
|
DateTime previousInterval = nowInterval.AddMinutes(-minutesToSubtract).AddSeconds(-nowInterval.Second).AddMilliseconds(-nowInterval.Millisecond); |
|
|
|
|
|
|
|
// 使用 last_update 上一刻 |
|
|
|
var sampleTimeFHR = DateTimeUtil.ConvertToTimeStamp(previousInterval).ToString(); |
|
|
|
|
|
|
|
// 计算last_update到下一间隔的分钟数 |
|
|
|
int minutesToAdd = intervalFHR - (nowInterval.Minute % intervalFHR); |
|
|
|
if (minutesToAdd == intervalFHR) |
|
|
|
{ |
|
|
|
minutesToAdd = 0; // 如果已经是间隔,则不需要增加分钟 |
|
|
|
} |
|
|
|
|
|
|
|
// 计算下一间隔的时间 |
|
|
|
DateTime nextInterval = nowInterval.AddMinutes(minutesToAdd) |
|
|
|
.AddSeconds(-nowInterval.Second) |
|
|
|
.AddMilliseconds(-nowInterval.Millisecond); |
|
|
|
|
|
|
|
|
|
|
|
var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7); |
|
|
|
|
|
|
|
var normalPhrStatStartTime = nextInterval.AddMinutes(-intervalFHR); |
|
|
|
|
|
|
|
var normalPhrStatEndTime = nextInterval; |
|
|
|
|
|
|
|
_logger.LogInformation($" {heartRate.MessageId} -- {heartRate.Serialno} 计算胎心数据, 周期:{normalPhrStatStartTime}-{normalPhrStatEndTime} "); |
|
|
|
var filteredPhr = daysPhr |
|
|
|
// 使用 last_update 下一刻 |
|
|
|
.Where(i => i.LastUpdate <= normalPhrStatEndTime && i.LastUpdate >= normalPhrStatStartTime) |
|
|
|
.ToList(); |
|
|
|
if (filteredPhr.Count == 0) |
|
|
|
{ |
|
|
|
_logger.LogWarning($"{heartRate.MessageId} -- {heartRate.Serialno} 周期:{normalPhrStatStartTime}-{normalPhrStatEndTime} 孕妇心率数据不足,{filteredPhr.Count}条记录"); |
|
|
|
return; |
|
|
|
} |
|
|
|
var phrValue = filteredPhr.Count == 1 |
|
|
|
? filteredPhr.First().PregnancyHeartRate |
|
|
|
: filteredPhr.Average(i => i.PregnancyHeartRate); |
|
|
|
|
|
|
|
//await SaveAndPushFreqFetalHeartRateAsync(heartRate, commonPHR!, upperAlarmThreshold, lowerAlarmThreshold, phrValue, sampleTimeFHR); |
|
|
|
await SaveAndPushFetalHeartRateAsync(heartRate, commonPHR!, upperAlarmThreshold, lowerAlarmThreshold, phrValue, sampleTimeFHR, normalPhrStatStartTime, normalPhrStatEndTime); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task SaveAndPushFetalHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int upperAlarmThreshold, int lowerAlarmThreshold, double phrValue, string sampleTime, DateTime statStartTime, DateTime statEndTime) |
|
|
|
{ |
|
|
|
// 计算胎心=孕妇心率*系数 |
|
|
|
/** |
|
|
|
var fetalHeartRate = SafeType.SafeInt(phrValue * commonPHR?.StatModeAvgFprCoefficient!); |
|
|
|
//fetalHeartRate = fetalHeartRate > 220 ? 220 : fetalHeartRate; // 胎心的最大值调整为220,超过都按该值220输出 |
|
|
|
fetalHeartRate = fetalHeartRate > 220 ? 220 : fetalHeartRate; // 胎心的最大值调整为220,超过都按该值220输出 |
|
|
|
if (fetalHeartRate >= 220) |
|
|
|
{ |
|
|
|
// 先使用最小系数计算 |
|
|
@@ -1269,12 +1296,46 @@ namespace HealthMonitor.WebApi |
|
|
|
_logger.LogWarning($"{heartRate.Serialno} 使用所有系数都不能放映实际,建模数据可能出现异常,请检查"); |
|
|
|
} |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
#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 |
|
|
|
|
|
|
|
var fetalHeartRate = SafeType.SafeInt(phrValue * coefficient); |
|
|
|
// 胎心的最大值调整为220,超过都按该值220输出 |
|
|
|
fetalHeartRate = fetalHeartRate >= 220 ? 220 : fetalHeartRate; |
|
|
|
|
|
|
|
var isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0); |
|
|
|
var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno); |
|
|
|
if (phrFreqstatus == null) isAbnormal = 0; |
|
|
|
var statsusDesc = (phrFreqstatus == null) ? $"MSG ID: {heartRate.MessageId} 常规" : "高频"; |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 在 {statsusDesc} 状态,心率值{heartRate.HeartRate},生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}"); |
|
|
|
var statsusDesc = (phrFreqstatus == null) ? "常规" : "高频"; |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 在 {statsusDesc} 状态,生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}"); |
|
|
|
//if (!isFreq) |
|
|
|
//{ |
|
|
|
// statStartTime = heartRate.LastUpdate; |
|
|
@@ -1300,13 +1361,63 @@ namespace HealthMonitor.WebApi |
|
|
|
|
|
|
|
// 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig |
|
|
|
// 推送最后一条常规心率计算的胎心数据到iot设备 |
|
|
|
#region 推送最后一条常规心率计算的胎心数据到iot设备 |
|
|
|
|
|
|
|
// 高频(<=12)-常规 |
|
|
|
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(heartRate.Serialno); |
|
|
|
if (lastPhr.MessageId== heartRate.MessageId) |
|
|
|
if (lastPhr.MessageId == heartRate.MessageId && phrFreqstatus == null) |
|
|
|
{ |
|
|
|
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal); |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备"); |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备,高频(<=12)-常规"); |
|
|
|
} |
|
|
|
// 高频(13)-常规-高频(13) |
|
|
|
if (phrFreqstatus != null) |
|
|
|
{ |
|
|
|
var phr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 1); |
|
|
|
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 <= 60) |
|
|
|
{ |
|
|
|
freqCollection.Add(item); |
|
|
|
} |
|
|
|
} |
|
|
|
// 高频最后一条 |
|
|
|
if (lastPhr.MessageId == item.MessageId) |
|
|
|
{ |
|
|
|
freqCollection.Add(item); |
|
|
|
} |
|
|
|
|
|
|
|
previousItem = item; |
|
|
|
} |
|
|
|
//去除高频 |
|
|
|
foreach (var item in freqCollection) |
|
|
|
{ |
|
|
|
phr.Remove(item); |
|
|
|
} |
|
|
|
lastPhr = phr.FirstOrDefault(); |
|
|
|
if (lastPhr?.MessageId == heartRate.MessageId) |
|
|
|
{ |
|
|
|
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal); |
|
|
|
_logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备,高频(13)-常规-高频(13)"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
#region 高频心率计算胎心数据到iot设备 |
|
|
|
// 高频(17) ,连续12个高频正常,也不停止且数据偏高和偏低也推送到iot |
|
|
|
if (phrFreqstatus != null && isAbnormal != 0) |
|
|
|
{ |
|
|
|
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal); |
|
|
|
} |
|
|
|
#endregion |
|
|
|
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"); |
|
|
@@ -1353,5 +1464,73 @@ namespace HealthMonitor.WebApi |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 去除高频数据 |
|
|
|
/// </summary> |
|
|
|
/// <param name="phr"></param> |
|
|
|
/// <param name="highFreqSampleInterva"></param> |
|
|
|
/// <returns></returns> |
|
|
|
private static List<PregnancyHeartRateModel> GetNonFreqPregnancyHeartRate(List<PregnancyHeartRateModel> phr, int highFreqSampleInterval) |
|
|
|
{ |
|
|
|
phr = phr.OrderByDescending(i => i.LastUpdate).ToList(); |
|
|
|
var result = new List<PregnancyHeartRateModel>(); |
|
|
|
PregnancyHeartRateModel? previousItem = null; |
|
|
|
|
|
|
|
foreach (var item in phr) |
|
|
|
{ |
|
|
|
if (previousItem != null) |
|
|
|
{ |
|
|
|
var timeNextDiff = (previousItem!.LastUpdate - item.LastUpdate).TotalSeconds; |
|
|
|
if (timeNextDiff > highFreqSampleInterval) |
|
|
|
{ |
|
|
|
result.Add(previousItem); |
|
|
|
} |
|
|
|
} |
|
|
|
previousItem = item; |
|
|
|
} |
|
|
|
|
|
|
|
// 添加上一个 |
|
|
|
if (previousItem != null) |
|
|
|
{ |
|
|
|
result.Add(previousItem); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// 获取高频数据 |
|
|
|
/// </summary> |
|
|
|
/// <param name="phr"></param> |
|
|
|
/// <param name="highFreqSampleInterval"></param> |
|
|
|
/// <returns></returns> |
|
|
|
private static List<PregnancyHeartRateModel> GetFreqPregnancyHeartRate(List<PregnancyHeartRateModel> phr, int highFreqSampleInterval) |
|
|
|
{ |
|
|
|
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(previousItem); |
|
|
|
} |
|
|
|
} |
|
|
|
previousItem = item; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查最后一条是否高频 |
|
|
|
if (previousItem != null && (phr.Last().LastUpdate - previousItem.LastUpdate).TotalSeconds <= highFreqSampleInterval) |
|
|
|
{ |
|
|
|
freqCollection.Add(previousItem); |
|
|
|
} |
|
|
|
|
|
|
|
return freqCollection; |
|
|
|
} |
|
|
|
} |
|
|
|
} |