瀏覽代碼

调整胎心系数选择的算法

datasub12_fetal_heart_rate_1
H Vs 4 天之前
父節點
當前提交
6d6a14ddd3
共有 1 個文件被更改,包括 140 次插入216 次删除
  1. +140
    -216
      HealthMonitor.WebApi/Worker.cs

+ 140
- 216
HealthMonitor.WebApi/Worker.cs 查看文件

@@ -1763,246 +1763,117 @@ namespace HealthMonitor.WebApi
}


private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)

/// <summary>
/// 高频胎心处理
/// 1. 高频数据触发连续12个值都是正常的的高频心率处理
/// 2. 高频结束后的highFreqSampleTimes=0的高频心率处理
/// 3. 高频结束后的在highFreqSampleTimes>0 正常心率触发的高频心率处理(常态)
/// 4. 高频结束后的时间倒序的正常心率触发的高频心率处理
/// 5. 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长,定时器时长highFreqSampleInterval触发的高频心率处理
/// 高频结束后超过9分钟且不在阈值内才告警
/// </summary>
/// <param name="heartRate"></param>
/// <param name="commonPHR"></param>
/// <param name="highFreqSampleTimes"></param>
/// <param name="upperAlarmThreshold"></param>
/// <param name="lowerAlarmThreshold"></param>
/// <param name="sampleTime"></param>
/// <param name="statStartTime"></param>
/// <param name="statEndTime"></param>
/// <returns></returns>
private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
{
// 计算胎心=孕妇心率*系数
/**
var fetalHeartRate = SafeType.SafeInt(phrValue * commonPHR?.StatModeAvgFprCoefficient!);
fetalHeartRate = fetalHeartRate > 220 ? 220 : fetalHeartRate; // 胎心的最大值调整为220,超过都按该值220输出
if (fetalHeartRate >= 220)
{
// 先使用最小系数计算
var statMaxValueFprCoefficient = commonPHR?.StatMaxValueFprCoefficient!;
var statMinValueFprCoefficient = commonPHR?.StatMinValueFprCoefficient!;
var coefficient = statMaxValueFprCoefficient < statMinValueFprCoefficient ? statMaxValueFprCoefficient : statMinValueFprCoefficient;
fetalHeartRate = SafeType.SafeInt(phrValue * coefficient);
if (fetalHeartRate < 220)
{
_logger.LogWarning($"{heartRate.Serialno} 使用极值系数 {coefficient} ,建模数据可能出现异常,请检查");
}
else
{
fetalHeartRate = 220;
_logger.LogWarning($"{heartRate.Serialno} 使用所有系数都不能放映实际,建模数据可能出现异常,请检查");
}
}
*/

#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}");
}
#endregion
*/

var fetalHeartRate = SafeType.SafeInt(heartRate.HeartRate! * 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) ? "常规" : "高频";
_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;
//
//}
// 保存到 数据服务 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);
///1、高频最小值>心率,取高频最小值系数
///2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
///3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
///4、心率 > 高频最大值,取高频最大值系数

// 推送到api/v1/open/OpenIot/SetFetalHeartRateConfig
// 推送最后一条常规心率计算的胎心数据到iot设备
#region 推送最后一条常规心率计算的胎心数据到iot设备

// 高频(<=12)-常规
var lastPhr = await _serviceTDengine.GetLastAsync<PregnancyHeartRateModel>(heartRate.Serialno);
if (lastPhr.MessageId == heartRate.MessageId && phrFreqstatus == null)
{
await _serviceIotApi.SetFetalHeartRateConfig(heartRate.Serialno, fetalHeartRate, sampleTime, isAbnormal);
_logger.LogInformation($"{heartRate.Serialno} 推送最后一条常规心率计算的胎心数据到iot设备,高频(<=12)-常规");
}
// 高频(13)-常规-高频(13)
if (phrFreqstatus != null)
// 1、高频最小值>心率,取高频最小值系数
if (commonPHR.MinValue > heartRate.HeartRate)
{
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)");
}
coefficient = commonPHR.StatMinValueFprCoefficient!;
_logger.LogInformation($"{heartRate.Serialno} 高频最小值>心率,取高频最小值系数 {coefficient}");
}

#endregion

#region 高频心率计算胎心数据到iot设备
// 高频(17) ,连续12个高频正常,也不停止且数据偏高和偏低也推送到iot
if (phrFreqstatus != null && isAbnormal != 0)
// 2、高频最小值 < 心率 < 众数,取众数系数与高频最小值系数较小值
if (commonPHR.MinValue < heartRate.HeartRate && heartRate.HeartRate < commonPHR.Mode)
{
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
if (commonPHR.StatModeAvgFprCoefficient > commonPHR.StatMinValueFprCoefficient)
{
imei = heartRate.Serialno,
value = fetalHeartRate,
isAbnormal,
type = "fetalHeart"
coefficient = commonPHR.StatMinValueFprCoefficient!;
_logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数大于最小值系数,使用最小值系数 {coefficient}");
}
};
await _serviceMqProcess.ProcessIMEIEventMessageAsync(fhrMsgId, topic, 31, fhrThridMsg).ConfigureAwait(false);

// 胎心数据推送到微信
if (isAbnormal != 0)
{

topic = "topic.push.wx";
var fhrMsg = new
else
{
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);

coefficient = commonPHR.StatModeAvgFprCoefficient!;
_logger.LogInformation($"{heartRate.Serialno} 高频最小值 < 心率 < 众数,平均值系数小于最小值系数,使用均值系数 {coefficient}");
}
}
}

/// <summary>
/// 高频胎心处理
/// 1. 高频数据触发连续12个值都是正常的的高频心率处理
/// 2. 高频结束后的highFreqSampleTimes=0的高频心率处理
/// 3. 高频结束后的在highFreqSampleTimes>0 正常心率触发的高频心率处理(常态)
/// 4. 高频结束后的时间倒序的正常心率触发的高频心率处理
/// 5. 高频结束后计算胎心数据,防止结束后与常规心理的胎心处理过长,定时器时长highFreqSampleInterval触发的高频心率处理
/// 高频结束后超过9分钟且不在阈值内才告警
/// </summary>
/// <param name="heartRate"></param>
/// <param name="commonPHR"></param>
/// <param name="highFreqSampleTimes"></param>
/// <param name="upperAlarmThreshold"></param>
/// <param name="lowerAlarmThreshold"></param>
/// <param name="sampleTime"></param>
/// <param name="statStartTime"></param>
/// <param name="statEndTime"></param>
/// <returns></returns>
private async Task SaveAndPushFetalHeartRateEndFreqHeartRateAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR, int highFreqSampleTimes, int upperAlarmThreshold, int lowerAlarmThreshold, string sampleTime, DateTime statStartTime, DateTime statEndTime)
{
// 计算胎心=孕妇心率*系数

#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)
// 3、众数 < 心率 < 高频最大值,取众数系数与高频最大值系数较小值
if (commonPHR.Mode < heartRate.HeartRate && heartRate.HeartRate < commonPHR.MaxValue)
{
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

// 4、心率 > 高频最大值,取高频最大值系数

if (heartRate.HeartRate > commonPHR.MaxValue)
{
coefficient = commonPHR.StatModeAvgFprCoefficient;
_logger.LogInformation($"{heartRate.Serialno} 孕妇心率等于中位数,使用均值系数 {coefficient}");
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);
@@ -2258,6 +2129,13 @@ namespace HealthMonitor.WebApi
return freqCollection;
}

/// <summary>
/// 周期性常规心率计算胎心值
/// </summary>
/// <param name="heartRate"></param>
/// <param name="commonPHR"></param>
/// <param name="highFreqSampleInterval"></param>
/// <returns></returns>
public async Task CalculateNormalFetalHeartRateIntervalAsync(HisGpsHeartRate heartRate, PregnancyCommonHeartRateModel commonPHR,int highFreqSampleInterval)
{
var daysPhr = await _serviceTDengine.GetBySerialNoAsync<PregnancyHeartRateModel>(heartRate.Serialno, 7);
@@ -2371,33 +2249,94 @@ namespace HealthMonitor.WebApi

heartRate.HeartRate = (int)avgPhr;

#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

#region 胎心阈值判断
@@ -3034,22 +2973,7 @@ namespace HealthMonitor.WebApi
}

}
//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;
//}

public static DateTime GetSampleTimeFromLastUpdate(DateTime lastUpdate, int interval)
{
// 获取当前的分钟


Loading…
取消
儲存