diff --git a/HealthMonitor.Service/Biz/db/TDengineService.cs b/HealthMonitor.Service/Biz/db/TDengineService.cs
index e3038a4..042958e 100644
--- a/HealthMonitor.Service/Biz/db/TDengineService.cs
+++ b/HealthMonitor.Service/Biz/db/TDengineService.cs
@@ -28,6 +28,8 @@ using HealthMonitor.Service.Cache;
using System.Text.RegularExpressions;
using Etcdserverpb;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
+using HealthMonitor.Core.Pipeline;
+using static Dm.net.buffer.ByteArrayBuffer;
namespace HealthMonitor.Service.Biz.db
{
@@ -1007,7 +1009,14 @@ namespace HealthMonitor.Service.Biz.db
//}
-
+ ///
+ /// 建模
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
public async Task InitPregnancyCommonHeartRateModeAsync(string serialNo, int days = 7, int percentage = 90, int highFreqSampleInterval=0)
{
var tableName = typeof(PregnancyHeartRateModel)
@@ -1144,7 +1153,7 @@ namespace HealthMonitor.Service.Biz.db
maxValue= maxValue < 100 ? 100 : maxValue;
- // 20-45周之间
+ // 12-45周之间
if (pregnancyWeek >= 12 && pregnancyWeek <= 45)
{
var map = fhrMap
@@ -1314,82 +1323,60 @@ namespace HealthMonitor.Service.Biz.db
}
+
+
///
- /// 获取孕妇心率众数
+ /// 胎心算法
+ /// 1、增量系数 = (正常胎心最大值 - 正常胎心最小值) / (阀值最大值 - 阀值最小值)
+ /// 2、胎心值 = 正常胎心最小值 + 增量系数 * (心率值 - 阀值最小值)
///
///
- ///
+ ///
///
- //public async Task GetPregnancyHeartRateModeAsync(string serialNo,int days=7)
- //{
- // var tableName = typeof(PregnancyHeartRateModel)
- // .GetCustomAttribute()?
- // .STableName;
- // var daysAgo = DateTime.Now.AddDays(-days);
- // var res = await _clientSqlSugar
- // .Queryable()
- // .AS(tableName)
- // .Where(i=>i.SerialNumber.Equals(serialNo))
- // .Where(i => i.Timestamp > daysAgo)
- // //.OrderByDescending(i => i.PregnancyHeartRate)
- // .Select(i =>i.PregnancyHeartRate)
- // .ToListAsync();
- // // 心率数据量必须30个以上才进行计算
- // if (res.Count < 30) return 0;
-
- // // 计算众数
- // var mode = res.GroupBy(n => n)
- // .OrderByDescending(g => g.Count())
- // .First()
- // .Key;
+ public async Task GetFetalHeartRateAsync(string serialNo,int heartrateValue)
+ {
+ var fhrMap = _mgrFhrPhrMapCache.GetHeartRatesMap();
+ var watchConfig = await _deviceCacheMgr.GetGpsDeviceWatchConfigCacheObjectBySerialNoAsync(serialNo, "0067");
+ if (watchConfig == null)
+ {
+ return 0;
+ }
- // Console.WriteLine("众数是: " + mode);
+ var edoc = DateTimeUtil.ToDateTime(watchConfig["EDOC"]!.ToString());
+ int pregnancyWeek = (DateTime.Now - edoc.AddDays(-280)).Days / 7;
- // // 如果有多个众数的情况
- // var maxCount = res.GroupBy(n => n)
- // .Max(g => g.Count());
+ // 12-45周之间
+ if (pregnancyWeek >= 12 && pregnancyWeek <= 45)
+ {
+ var map = fhrMap
+ .Where(i =>
+ i.PregnancyPeriod![0] <= pregnancyWeek &&
+ i.PregnancyPeriod[1] >= pregnancyWeek
+ //&&i.PregnancyHeartRateRange![0] <= mode && i.PregnancyHeartRateRange[1] >= mode
+ )
+ .FirstOrDefault();
- // var modes = res.GroupBy(n => n)
- // .Where(g => g.Count() == maxCount)
- // .Select(g => g.Key)
- // .ToList();
- // // 多个众数,选择最接近平均数或中位数的众数
- // if (modes.Count>1)
- // {
- // // 计算平均值
- // double average = res.Average();
- // Console.WriteLine("平均值是: " + average);
+ var NormaletalHeartRateMin = map?.FetalHeartRateRange![0];
+ var NormaletalHeartRateMax = map?.FetalHeartRateRange![1];
- // // 计算中位数
- // double median;
- // int count = res.Count;
- // var sortedRes = res.OrderBy(n => n).ToList();
- // if (count % 2 == 0)
- // {
- // // 偶数个元素,取中间两个数的平均值
- // median = (sortedRes[count / 2 - 1] + sortedRes[count / 2]) / 2.0;
- // }
- // else
- // {
- // // 奇数个元素,取中间的数
- // median = sortedRes[count / 2];
- // }
- // Console.WriteLine("中位数是: " + median);
- // // 找出最接近平均值的众数
- // //var closestToAverage = modes.OrderBy(m => Math.Abs(m - average)).First();
- // //Console.WriteLine("最接近平均值的众数是: " + closestToAverage);
+ // 触发高频监测的心率上限值
+ var triggerHighFreqHigh = (int)watchConfig["triggerHighFreqHigh"]!;
+ // 触发高频监测的心率下限值
+ var triggerHighFreqLow = (int)watchConfig["triggerHighFreqLow"]!;
+ //增量系数 = (正常胎心最大值 - 正常胎心最小值) / (阀值最大值 - 阀值最小值)
+ var coefficient = (NormaletalHeartRateMax - NormaletalHeartRateMin) / (triggerHighFreqHigh - triggerHighFreqLow);
- // // 找出最接近中位数的众数
- // var closestToMedian = modes.OrderBy(m => Math.Abs(m - median)).First();
- // Console.WriteLine("最接近中位数的众数是: " + closestToMedian);
- // mode = closestToMedian;
- // }
+ //胎心值 = 正常胎心最小值 + 增量系数 * (心率值 - 阀值最小值)
+ var fetalHeartRate = NormaletalHeartRateMin + coefficient * (heartrateValue - triggerHighFreqLow);
- // return mode;
- //}
+ _logger.LogInformation($"{serialNo} 孕周:{pregnancyWeek}, 正常胎心最大值:{NormaletalHeartRateMax},正常胎心最小值:{NormaletalHeartRateMin},阀值最大值:{triggerHighFreqHigh} ,阀值最小值:{triggerHighFreqLow}, 增量系数:{coefficient}");
+ return SafeType.SafeInt(fetalHeartRate!);
+ }
+ return 0;
+ }
#endregion
}
diff --git a/HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs b/HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs
index 8517f90..bf6ef01 100644
--- a/HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs
+++ b/HealthMonitor.Service/Resolver/PregnancyHeartRateResolver.cs
@@ -829,7 +829,6 @@ namespace HealthMonitor.Service.Resolver
return selectedHrValue;
}
-
///
/// 高频胎心处理
/// 1. 高频数据触发连续12个值都是正常的的高频心率处理
@@ -848,37 +847,98 @@ namespace HealthMonitor.Service.Resolver
///
///
///
- private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
+ private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsyncOld(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
{
// 计算胎心=孕妇心率*系数
- #region 胎心系数使用基于心率与中位数对比
+ #region 胎心系数使用基于心率与众数对比
var coefficient = 0f;
- // 孕妇心率少于中位数,取StatMinValueFprCoefficient
+ /**
+ // 孕妇心率少于众数,取StatMinValueFprCoefficient
if (heartRate.HeartRate < commonPHR!.Mode)
{
coefficient = commonPHR.StatMinValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 孕妇心率少于中位数,使用最小值系数 {coefficient}");
+ _logger.LogInformation($"{heartRate.Serialno} 孕妇心率少于众数,使用最小值系数 {coefficient}");
}
- // 孕妇心率大于中位数,取StatMaxValueFprCoefficient与StatModeAvgFprCoefficient中少的那个
+ // 孕妇心率大于众数,取StatMaxValueFprCoefficient与StatModeAvgFprCoefficient中少的那个
else if (heartRate.HeartRate > commonPHR.Mode)
{
if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMaxValueFprCoefficient)
{
coefficient = commonPHR.StatMaxValueFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于中位数,使用最大值系数 {coefficient}");
+ _logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于众数,使用最大值系数 {coefficient}");
}
else
{
coefficient = commonPHR.StatModeAvgFprCoefficient!;
- _logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于中位数,使用均值系数 {coefficient}");
+ _logger.LogInformation($"{heartRate.Serialno} 孕妇心率大于众数,使用均值系数 {coefficient}");
}
}
else
{
coefficient = commonPHR.StatModeAvgFprCoefficient;
- _logger.LogInformation($"{heartRate.Serialno} 孕妇心率等于中位数,使用均值系数 {coefficient}");
+ _logger.LogInformation($"{heartRate.Serialno} 孕妇心率等于众数,使用均值系数 {coefficient}");
+ }
+ */
+
+
+ ///1、高频最小值>心率,取高频最小值系数
+ ///2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
+ ///3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
+ ///4、心率 > 高频最大值,取高频最大值系数
+
+ // 1、高频最小值>心率,取高频最小值系数
+ if (commonPHR.MinValue > heartRate.HeartRate)
+ {
+ coefficient = commonPHR.StatMinValueFprCoefficient!;
+ _logger.LogInformation($"{heartRate.Serialno} 高频最小值>心率,取高频最小值系数 {coefficient}");
}
+
+ // 2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
+ if (commonPHR.MinValue < heartRate.HeartRate && heartRate.HeartRate < commonPHR.Mode)
+ {
+ if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMinValueFprCoefficient)
+ {
+ coefficient = commonPHR.StatMinValueFprCoefficient!;
+ _logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数大于最小值系数,使用最小值系数 {coefficient}");
+ }
+ else
+ {
+ coefficient = commonPHR.StatModeAvgFprCoefficient!;
+ _logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数小于最小值系数,使用均值系数 {coefficient}");
+ }
+ }
+
+ // 3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
+ if (commonPHR.Mode < heartRate.HeartRate && heartRate.HeartRate < commonPHR.MaxValue)
+ {
+ if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMaxValueFprCoefficient)
+ {
+ coefficient = commonPHR.StatMaxValueFprCoefficient!;
+ _logger.LogInformation($"{heartRate.Serialno} 众数 < 心率 < 高频最大值,平均值系数大于最最大值系数,使用最大值系数 {coefficient}");
+ }
+ else
+ {
+ coefficient = commonPHR.StatModeAvgFprCoefficient!;
+ _logger.LogInformation($"{heartRate.Serialno} 众数 < 心率 < 高频最大值,平均值系数小于最小值系数,使用均值系数 {coefficient}");
+ }
+ }
+
+ // 4、心率 > 高频最大值,取高频最大值系数
+
+ if (heartRate.HeartRate > commonPHR.MaxValue)
+ {
+ coefficient = commonPHR.StatMaxValueFprCoefficient!;
+ _logger.LogInformation($"{heartRate.Serialno} 心率 > 高频最大值,取高频最大值系数 {coefficient}");
+ }
+
+ if (heartRate.HeartRate == commonPHR.Mode)
+ {
+ coefficient = commonPHR.StatModeAvgFprCoefficient!;
+
+ _logger.LogInformation($"{heartRate.Serialno} 心率 == 众数,取均值系数 {coefficient}");
+ }
+
#endregion
var fetalHeartRate = SafeType.SafeInt(heartRate.HeartRate! * coefficient);
@@ -1012,6 +1072,153 @@ namespace HealthMonitor.Service.Resolver
}
}
+ ///
+ /// 高频胎心处理
+ /// 1. 高频数据触发连续12个值都是正常的的高频心率处理
+ /// 2. 高频结束后的highFreqSampleTimes=0的高频心率处理
+ /// 3. 高频结束后的在highFreqSampleTimes>0 正常心率触发的高频心率处理(常态)
+ /// 4. 高频结束后的时间倒序的正常心率触发的高频心率处理
+ /// 5. 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长,定时器时长highFreqSampleInterval触发的高频心率处理
+ /// 高频结束后超过9分钟且不在阈值内才告警
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
+ {
+
+ var fetalHeartRate = await _serviceTDengine.GetFetalHeartRateAsync(heartRate.Serialno, (int)heartRate.HeartRate!);
+
+ var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
+ var isAbnormal = 0;
+ #region 判断是否够highFreqSampleTimes,540s
+ var ts = DateTimeUtil.GetTimeDifferenceInSeconds((DateTime)heartRate.LastUpdate!, phrFreqstatus!.LastUpdate);
+ // 判断是否够highFreqSampleTimes,540s
+ ///高频时长不足10分钟停止高频的胎心值生成说明:最近12个数据的最小值生成胎心值,
+ ///对于小于高频下限阀值取高频下限阀值进行转换;
+ ///对于高于高频上限阀值取高频上限阀值进行转换。并输出相关日志后续进行数据分析。
+ if (ts < highFreqSampleTimes)
+ {
+ if (fetalHeartRate > upperAlarmThreshold)
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,计算胎心值 {fetalHeartRate} 高于高频警告上限阀值{upperAlarmThreshold},最后胎心值{upperAlarmThreshold},并且不告警");
+ fetalHeartRate = upperAlarmThreshold;
+
+
+ }
+ else if (fetalHeartRate < lowerAlarmThreshold)
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,计算胎心值 {fetalHeartRate} 低于高频警告下限阀值 {lowerAlarmThreshold},最后胎心值{lowerAlarmThreshold},并且不告警");
+ fetalHeartRate = lowerAlarmThreshold;
+ }
+ else
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,在高频警告下限阀值 {lowerAlarmThreshold} 和 高频警告上限阀值:{upperAlarmThreshold}之间,最后胎心值{fetalHeartRate},并且不告警");
+ }
+
+ }
+ // 超过highFreqSampleTimes,540s
+ else
+ {
+ if (fetalHeartRate > 220)
+ {
+ fetalHeartRate = 220;
+ _logger.LogWarning($"{heartRate.Serialno} 大于220,按220输出,计算因子:孕妇心率 {heartRate.HeartRate},周期:{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}, 周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
+ }
+ isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
+ }
+ #endregion
+
+
+
+ _logger.LogInformation($"{heartRate.Serialno} 在 高频 状态,生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
+ // 保存到 数据服务 MySQL 数据库
+ HisGpsFetalHeartRate gpsFetalHeartRate = new()
+ {
+ FetalHeartRateId = Guid.NewGuid().ToString("D"),
+ PersonId = commonPHR!.PersonId,
+ Serialno = heartRate.Serialno,
+ HeartRate = fetalHeartRate,
+ SampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : 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);
+
+ #region 高频心率计算胎心数据到iot设备
+
+ //if (phrFreqstatus != null && isAbnormal != 0)
+ //{
+ // await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
+ //}
+ // 高频有数据都推送到iot
+
+ 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");
+ // 胎心数据推送到第三方
+ 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);
+
+ // 胎心数据推送到微信
+ 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);
+
+ }
+ }
+
private async Task SetIntervalTriggerAsync(string key, string imei, long interval, HisGpsHeartRate heartRate)
{
// var key = $"health_monitor/schedule_push/{type}/imei/{imei}";
diff --git a/HealthMonitor.WebApi/Worker.cs b/HealthMonitor.WebApi/Worker.cs
index 4e9145e..2bc41a2 100644
--- a/HealthMonitor.WebApi/Worker.cs
+++ b/HealthMonitor.WebApi/Worker.cs
@@ -1824,7 +1824,7 @@ namespace HealthMonitor.WebApi
///
///
///
- private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
+ private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsyncOld(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
{
// 计算胎心=孕妇心率*系数
@@ -2049,6 +2049,153 @@ namespace HealthMonitor.WebApi
}
}
+ ///
+ /// 高频胎心处理
+ /// 1. 高频数据触发连续12个值都是正常的的高频心率处理
+ /// 2. 高频结束后的highFreqSampleTimes=0的高频心率处理
+ /// 3. 高频结束后的在highFreqSampleTimes>0 正常心率触发的高频心率处理(常态)
+ /// 4. 高频结束后的时间倒序的正常心率触发的高频心率处理
+ /// 5. 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长,定时器时长highFreqSampleInterval触发的高频心率处理
+ /// 高频结束后超过9分钟且不在阈值内才告警
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
+ {
+
+ var fetalHeartRate = await _serviceTDengine.GetFetalHeartRateAsync(heartRate.Serialno, (int)heartRate.HeartRate!);
+
+ var phrFreqstatus = await _deviceCacheMgr.GetPregnancyHeartRateFreqStatusAsync(heartRate.Serialno);
+ var isAbnormal = 0;
+ #region 判断是否够highFreqSampleTimes,540s
+ var ts = DateTimeUtil.GetTimeDifferenceInSeconds((DateTime)heartRate.LastUpdate!, phrFreqstatus!.LastUpdate);
+ // 判断是否够highFreqSampleTimes,540s
+ ///高频时长不足10分钟停止高频的胎心值生成说明:最近12个数据的最小值生成胎心值,
+ ///对于小于高频下限阀值取高频下限阀值进行转换;
+ ///对于高于高频上限阀值取高频上限阀值进行转换。并输出相关日志后续进行数据分析。
+ if (ts < highFreqSampleTimes)
+ {
+ if (fetalHeartRate > upperAlarmThreshold)
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,计算胎心值 {fetalHeartRate} 高于高频警告上限阀值{upperAlarmThreshold},最后胎心值{upperAlarmThreshold},并且不告警");
+ fetalHeartRate = upperAlarmThreshold;
+
+
+ }
+ else if (fetalHeartRate < lowerAlarmThreshold)
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,计算胎心值 {fetalHeartRate} 低于高频警告下限阀值 {lowerAlarmThreshold},最后胎心值{lowerAlarmThreshold},并且不告警");
+ fetalHeartRate = lowerAlarmThreshold;
+ }
+ else
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 高频持续不足10分钟,在高频警告下限阀值 {lowerAlarmThreshold} 和 高频警告上限阀值:{upperAlarmThreshold}之间,最后胎心值{fetalHeartRate},并且不告警");
+ }
+
+ }
+ // 超过highFreqSampleTimes,540s
+ else
+ {
+ if (fetalHeartRate > 220)
+ {
+ fetalHeartRate = 220;
+ _logger.LogWarning($"{heartRate.Serialno} 大于220,按220输出,计算因子:孕妇心率 {heartRate.HeartRate},周期:{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}, 周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
+ }
+ isAbnormal = fetalHeartRate > upperAlarmThreshold ? 1 : (fetalHeartRate < lowerAlarmThreshold ? 2 : 0);
+ }
+ #endregion
+
+
+
+ _logger.LogInformation($"{heartRate.Serialno} 在 高频 状态,生成胎心值:{fetalHeartRate},统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}----{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
+ // 保存到 数据服务 MySQL 数据库
+ HisGpsFetalHeartRate gpsFetalHeartRate = new()
+ {
+ FetalHeartRateId = Guid.NewGuid().ToString("D"),
+ PersonId = commonPHR!.PersonId,
+ Serialno = heartRate.Serialno,
+ HeartRate = fetalHeartRate,
+ SampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : 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);
+
+ #region 高频心率计算胎心数据到iot设备
+
+ //if (phrFreqstatus != null && isAbnormal != 0)
+ //{
+ // await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
+ //}
+ // 高频有数据都推送到iot
+
+ 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");
+ // 胎心数据推送到第三方
+ 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);
+
+ // 胎心数据推送到微信
+ 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);
+
+ }
+ }
+
///
/// 去除高频数据
@@ -2178,7 +2325,7 @@ namespace HealthMonitor.WebApi
///
///
///
- public async Task CalculateNormalFetalHeartRateIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,int highFreqSampleInterval)
+ public async Task CalculateNormalFetalHeartRateIntervalAsyncOld(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,int highFreqSampleInterval)
{
var daysPhr = await _serviceTDengine.GetBySerialNoAsync(heartRate.Serialno, 7);
var now = DateTime.Now;
@@ -2535,6 +2682,264 @@ namespace HealthMonitor.WebApi
}
+ ///
+ /// 周期性常规心率计算胎心值
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task CalculateNormalFetalHeartRateIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleInterval)
+ {
+ var daysPhr = await _serviceTDengine.GetBySerialNoAsync(heartRate.Serialno, 7);
+ var now = DateTime.Now;
+ var filteredPhr = daysPhr.Where(i => i.LastUpdate >= heartRate.LastUpdate && i.LastUpdate <= now).ToList();
+ // 去除高频
+ var normalPhr = GetNonFreqPregnancyHeartRate(filteredPhr, highFreqSampleInterval).OrderBy(i => i.LastUpdate);
+
+ if (normalPhr.ToList().Count == 0)
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 时间段{heartRate.LastUpdate}-{now},去除高频心率数据后,没有常规数据,不计算常规胎心数据");
+ return;
+ }
+
+ 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
+ {
+ //var CalNow = DateTime.Now;
+ //var during = TimeSpan.FromSeconds(300); //5分钟
+
+ var c = 0;
+ while (true)
+ {
+
+ //if (DateTime.Now - CalNow > during)
+ //{
+ // _logger.LogInformation($"{heartRate.Serialno} 超过1分钟,迭代完成跳出循环 ");
+ // break;
+ //}
+
+ await Task.Delay(TimeSpan.FromSeconds(1));
+
+ 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.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")}");
+
+ if (statEndTime > boundaryStatEndTime)
+ {
+ _logger.LogInformation($"{heartRate.Serialno} 常规胎心统计超过时间边界,迭代完成跳出循环 ");
+ break;
+ }
+
+ var segmentPhr = normalPhr
+ .Where(i => i.LastUpdate <= statEndTime && i.LastUpdate >= statStartTime)
+ .ToList();
+
+ if (segmentPhr.Count == 0)
+ {
+ // 跳出当次迭代,进入下次迭代
+ _logger.LogWarning($"{heartRate.Serialno} 统计周期:{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")} 孕妇心率数据不足,{segmentPhr.Count}条记录,不处理");
+ continue;
+ }
+
+ _logger.LogInformation($"{heartRate.Serialno} 当前统计周期{statStartTime.ToString("yyyy-MM-dd HH:mm:ss")}-{statEndTime.ToString("yyyy-MM-dd HH:mm:ss")},对应的常规心率ID{string.Join(",", segmentPhr.Select(i => i.MessageId))}");
+
+
+
+ var sampleTime = DateTimeUtil.ConvertToTimeStamp(segmentStatStartTime).ToString();
+ sampleTime = sampleTime.Length > 10 ? sampleTime.Substring(0, 10) : sampleTime;
+
+ //检测 是否存在,不存在则处理
+ GeneralParam param = new()
+ {
+ Filters = new List
+ {
+ 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
+ {
+ 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 fetalHeartRateFromAlgorithm = await _serviceTDengine.GetFetalHeartRateAsync(heartRate.Serialno, (int)heartRate.HeartRate);
+ // 计算胎心率并进行边界检查
+ var fetalHeartRate = Math.Clamp(fetalHeartRateFromAlgorithm, 90, 220);
+ if (fetalHeartRate != fetalHeartRateFromAlgorithm)
+ {
+ _logger.LogWarning($"{heartRate.Serialno} 胎心率超出范围, 按修正值 {fetalHeartRate} 输出, 孕妇心率 {heartRate.HeartRate}, 周期 {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(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")} ,常规胎心已处理");
+ }
+ //await Task.Delay(TimeSpan.FromSeconds(1));
+ // 跳出循环
+ if (statEndTime.ToString("yyyyMMddHHmm") == boundaryStatEndTime.ToString("yyyyMMddHHmm"))
+ {
+ _logger.LogInformation($"{heartRate.Serialno} 迭代完成跳出循环 ");
+ break;
+ }
+
+ //if (statEndTime>= boundaryStatEndTime)
+ //{
+ // _logger.LogInformation($"{heartRate.Serialno} 时间边界,迭代完成跳出循环 ");
+ // 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;
+ // }
+ //}
+ }
+
+
public async Task CalculateFetalMovementIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,DateTime edoc)
{