This commit is contained in:
xyy
2026-01-22 19:18:16 +08:00
parent e88d0aed75
commit 028728b816
5 changed files with 227 additions and 89 deletions

View File

@@ -10,6 +10,7 @@ namespace 口罩泄露定制款
public class ExperData : INotifyPropertyChanged public class ExperData : INotifyPropertyChanged
{ {
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
#region #region
static string experName = ""; static string experName = "";
/// <summary> /// <summary>
@@ -34,31 +35,34 @@ namespace 口罩泄露定制款
/// 实验种类 /// 实验种类
/// </summary> /// </summary>
public string ExperType { get { return experType; } set { experType = value; } } public string ExperType { get { return experType; } set { experType = value; } }
static float experMaskType = 2.0f; static float experMaskType = 2.0f;
/// <summary> /// <summary>
/// 口罩类型 /// 口罩类型泄漏率标准
/// </summary> /// </summary>
public float ExperMaskType { get { return experMaskType; } set { experMaskType = value; } } public float ExperMaskType { get { return experMaskType; } set { experMaskType = value; } }
/// <summary> /// <summary>
/// 面罩类型 /// 面罩类型
/// </summary> /// </summary>
static string maskType; static string maskType;
public string MaskType { get { return maskType; } set { maskType = value; } } public string MaskType { get { return maskType; } set { maskType = value; } }
static float _yangPinXiShu = 1.0f;
static float _testDuration = 120f; // 测试时间改为120秒
/// <summary> /// <summary>
/// 样品系数 /// 测试时长(秒)
/// </summary> /// </summary>
public float YangPinXiShu { get { return _yangPinXiShu; } set { _yangPinXiShu = value; } } public float TestDuration { get { return _testDuration; } set { _testDuration = value; } }
static string _testStatus = ""; static string _testStatus = "";
/// <summary> /// <summary>
/// 实验状态 /// 实验状态
/// </summary> /// </summary>
public string TestStatus { get { return _testStatus; } set { _testStatus = value; } } public string TestStatus { get { return _testStatus; } set { _testStatus = value; } }
static float benDiNongDu = 0.00f; static float benDiNongDu = 0.00f;
/// <summary> /// <summary>
/// 本底浓度 /// 本底浓度(mg/m³)
/// </summary> /// </summary>
public float BenDiNongDu { get { return benDiNongDu; } set { benDiNongDu = value; } } public float BenDiNongDu { get { return benDiNongDu; } set { benDiNongDu = value; } }
@@ -68,7 +72,6 @@ namespace 口罩泄露定制款
/// </summary> /// </summary>
public float HuanJingWenDu { get { return huanJingWenDu; } set { huanJingWenDu = value; } } public float HuanJingWenDu { get { return huanJingWenDu; } set { huanJingWenDu = value; } }
static float huanJingShiDu = 0.00f; static float huanJingShiDu = 0.00f;
/// <summary> /// <summary>
/// 环境湿度 /// 环境湿度
@@ -83,13 +86,13 @@ namespace 口罩泄露定制款
static float cO2NongDu = 0.00f; static float cO2NongDu = 0.00f;
/// <summary> /// <summary>
/// 环境C02浓度 /// 环境CO2浓度
/// </summary> /// </summary>
public float CO2NongDu_Indoor { get { return cO2NongDu; } set { cO2NongDu = value; } } public float CO2NongDu_Indoor { get { return cO2NongDu; } set { cO2NongDu = value; } }
static float inDoor_TSINongDu = 0.00f; static float inDoor_TSINongDu = 0.00f;
/// <summary> /// <summary>
/// 环境气溶胶浓度 /// 环境气溶胶浓度(mg/m³)
/// </summary> /// </summary>
public float InDoor_TSINongDu { get { return inDoor_TSINongDu; } set { inDoor_TSINongDu = value; } } public float InDoor_TSINongDu { get { return inDoor_TSINongDu; } set { inDoor_TSINongDu = value; } }
@@ -101,51 +104,115 @@ namespace 口罩泄露定制款
static float mask_TSINongDu = 0.00f; static float mask_TSINongDu = 0.00f;
/// <summary> /// <summary>
/// 口罩内气溶胶浓度 /// 口罩内气溶胶浓度(mg/m³)
/// </summary> /// </summary>
public float Mask_TSINongDu { get { return mask_TSINongDu; } set { mask_TSINongDu = value; } } public float Mask_TSINongDu { get { return mask_TSINongDu; } set { mask_TSINongDu = value; } }
static float _liuLiang = 0.00f; static float _liuLiang = 0.00f;
/// <summary> /// <summary>
/// 流量 /// 流量(L/min)
/// </summary> /// </summary>
public float LiuLiang { get { return _liuLiang; } set { _liuLiang = value; } } public float LiuLiang { get { return _liuLiang; } set { _liuLiang = value; } }
static float _xieloulv = 0.00f; static float _xieloulv = 0.00f;
/// <summary> /// <summary>
/// 泄露率 /// 泄露率(%)
/// </summary> /// </summary>
public float XieLouLv { get { return _xieloulv; } set { _xieloulv = value; } } public float XieLouLv { get { return _xieloulv; } set { _xieloulv = value; } }
// 新增采样流量和干燥气流流量根据YY/T 0866-2024标准
static float _samplingFlowRate = 2.0f; // 默认采样流量2L/min
public float SamplingFlowRate { get { return _samplingFlowRate; } set { _samplingFlowRate = value; } }
static float _dryingFlowRate = 1.0f; // 默认干燥气流1L/min
public float DryingFlowRate { get { return _dryingFlowRate; } set { _dryingFlowRate = value; } }
#endregion #endregion
#region #region YY/T 0866-2024
//单独动作泄露率
public float CumulativeLeakageRate(List<float> inDoor_Tsi,List<float> out_Door_Tsi,float benDiNongdu,float xiShu) /// <summary>
/// 连续采样法泄漏率计算公式2
/// P = 1.25 * ((C2 - C0) / C1) * ((S + D) / S) * 100
/// </summary>
public float ContinuousSamplingLeakageRate(List<float> indoorData, List<float> outdoorData,
float backgroundConcentration,
float samplingFlow, float dryingFlow)
{ {
if (inDoor_Tsi.Count != 0 && out_Door_Tsi.Count != 0) if (indoorData.Count == 0 || outdoorData.Count == 0)
return 0.0f;
// 使用最后100秒的数据标准要求
int dataCount = Math.Min(indoorData.Count, outdoorData.Count);
int startIndex = Math.Max(0, dataCount - 100); // 取最后100个数据点
// 计算最后100秒的平均值
float C1 = 0, C2 = 0;
int validCount = 0;
for (int i = startIndex; i < dataCount; i++)
{ {
//计算室内Tsi浓度平均值 C1 += indoorData[i];
float inDoor_Tsi_Avg = inDoor_Tsi.Average(); C2 += outdoorData[i];
//计算室外Tsi浓度平均值 validCount++;
float out_Door_Tsi_Avg = out_Door_Tsi.Average();
//计算泄露率
float leakageRate = ((out_Door_Tsi_Avg - benDiNongdu ) * xiShu)*100 / inDoor_Tsi_Avg;
return leakageRate;
}
else
{
return 0.00f;
} }
} if (validCount == 0)
//全部动作泄露率 return 0.0f;
public float CumulativeLeakageRate_All(List<float> All_Cv_List)
{ C1 /= validCount;
return All_Cv_List.Average(); C2 /= validCount;
// 应用连续采样法公式
if (C1 <= 0)
return 0.0f;
// P = 1.25 * ((C2 - C0) / C1) * ((S + D) / S) * 100
float leakageRate = 1.25f * ((C2 - backgroundConcentration) / C1) *
((samplingFlow + dryingFlow) / samplingFlow) * 100;
return Math.Max(0, leakageRate); // 确保非负
} }
/// <summary>
/// 脉冲式采样法泄漏率计算公式1 - 备用
/// </summary>
public float PulsedSamplingLeakageRate(List<float> indoorData, List<float> outdoorData,
float backgroundConcentration,
float samplingFlow, float dryingFlow,
float totalInhaleTime, float totalExhaleTime)
{
if (indoorData.Count == 0 || outdoorData.Count == 0 || totalInhaleTime <= 0)
return 0.0f;
// 使用最后100秒的数据
int dataCount = Math.Min(indoorData.Count, outdoorData.Count);
int startIndex = Math.Max(0, dataCount - 100);
float C1 = 0, C2 = 0;
int validCount = 0;
for (int i = startIndex; i < dataCount; i++)
{
C1 += indoorData[i];
C2 += outdoorData[i];
validCount++;
}
if (validCount == 0 || C1 <= 0)
return 0.0f;
C1 /= validCount;
C2 /= validCount;
// P = ((C2 - C0) / C1) * ((t_w + t_cm) / t_w) * ((S + D) / S) * 100
float leakageRate = ((C2 - backgroundConcentration) / C1) *
((totalInhaleTime + totalExhaleTime) / totalInhaleTime) *
((samplingFlow + dryingFlow) / samplingFlow) * 100;
return Math.Max(0, leakageRate);
}
#endregion #endregion
} }
} }

View File

@@ -0,0 +1,36 @@
{
"High": "191",
"Weight": "59",
"FaceWidth": "4",
"FaceLength": "2",
"EyesDistance": "5",
"Customer": "7",
"IsNeedRun": false,
"MaskType": "KN95",
"Category": "NaCl浓度",
"Threshold": "10.0",
"Concentration": "5",
"ParticleSize": "1.7",
"ContentString": "篇三",
"ScreenValue": "[1选型决策树]\"问1环境有缺氧风险吗是→选正压式呼吸器否→下一步问2危害物是粉尘/烟雾是→选KN100/KP100口罩否→下一步问3危害物是毒气/蒸气?是→选对应滤毒罐全面罩!——科学选型是防护第一步!\"[2佩戴全流程]\"步骤1预检查•滤棉无破损头带弹性足步骤2规范佩戴•双手托口罩→下巴先入→拉紧下头带→再拉紧上头带步骤3密合检测•正压检测手掌堵呼气阀口罩应鼓起•负压检测捂住滤棉吸气口罩应塌陷\"[3致命误区解析]\"误区1'纱布口罩也能防尘'真相PM2.5穿透率高达90%误区2'滤棉变黑才需换'真相呼吸阻力增大就要换误区3'胡须长不影响密封'真相:胡须者必须用电动送风面罩!\"[4法规与创新]\"GB2626-2019规定KN95口罩盐性粉尘过滤率≥95%!新技术:智能口罩可监测呼吸阻力,报警提醒更换!——合规是底线,科技向未来!\"",
"CustomScreenValue": "1`2`3`4`5`6`7`8`9",
"Name": "qw",
"Sex": "男",
"Age": "30",
"IdNumber": "25",
"Company": "南京",
"CompanyAge": "3",
"No": "CSI-665B",
"FullMaskType": "随弃式面罩TIL-KN95",
"BenDiNongdu": 0.374,
"SamplingFlowRate": 2.0,
"DryingFlowRate": 1.0,
"MaskStandards": {
"KN90": 13.0,
"KP90": 13.0,
"KN95": 11.0,
"KP95": 11.0,
"KN100": 5.0,
"KP100": 5.0
}
}

View File

@@ -67,6 +67,12 @@ public class Experiment
public float TsiIndoorAgv { get; set; } public float TsiIndoorAgv { get; set; }
public float TsiOutdoorAgv { get; set; } public float TsiOutdoorAgv { get; set; }
public float Xieloulv { get; set; } public float Xieloulv { get; set; }
public float SamplingFlowRate { get; set; } // 采样流量(L/min)
public float DryingFlowRate { get; set; } // 干燥气流(L/min)
// 测试时长
public int TestDuration { get; set; } // 测试时长(秒)
} }

View File

@@ -78,7 +78,7 @@ namespace 口罩泄露定制款
} }
} }
// 3. 步骤初始化 // 步骤初始化 - 根据新标准调整
private void InitStepList() private void InitStepList()
{ {
stepList.Clear(); stepList.Clear();
@@ -86,11 +86,11 @@ namespace 口罩泄露定制款
stepList.Add("请将采样管插头插入测量接口"); stepList.Add("请将采样管插头插入测量接口");
if (isNeedRun) if (isNeedRun)
stepList.Add("请按下跑步机启动按钮"); stepList.Add("请按下跑步机启动按钮");
stepList.Add("头部静止、不说话,2 min"); stepList.Add("头部静止、不说话2 min");
stepList.Add("左右转动头部看检测仓左右墙壁(大约15次),2 min"); stepList.Add("左右转动头部看检测仓左右墙壁(大约15次)2 min");
stepList.Add("抬头和低头看检测仓顶和地面(大约15次),2 min"); stepList.Add("抬头和低头看检测仓顶和地面(大约15次)2 min");
stepList.Add("大声阅读屏幕显示文字,2 min"); stepList.Add("大声阅读屏幕显示文字2 min");
stepList.Add("头部静止、不说话,2 min"); stepList.Add("头部静止、不说话2 min");
stepList.Add("测试完成,拔下采样管插头,走出测量仓"); stepList.Add("测试完成,拔下采样管插头,走出测量仓");
comboBox1.Items.Clear(); comboBox1.Items.Clear();
foreach (var step in stepList) foreach (var step in stepList)
@@ -541,18 +541,31 @@ namespace 口罩泄露定制款
if (dt_Show.Columns.Count != 0) if (dt_Show.Columns.Count != 0)
{ {
if (list_Tsi_Indoor_Data.Count != 0 && list_Tsi_Outdoor_Data.Count != 0) // 使用最后100秒数据计算标准要求
{ int dataCount = Math.Min(list_Tsi_Indoor_Data.Count, list_Tsi_Outdoor_Data.Count);
_TsiIndoorAgv = list_Tsi_Indoor_Data.Average(); int startIndex = Math.Max(0, dataCount - 100);
_TsiOutdoorAgv = list_Tsi_Outdoor_Data.Average();
// 关键修改:使用与 timer_UpdataChart_Tick 中相同的计算方法 List<float> last100Indoor = new List<float>();
// 而不是简单的 lsit_XieLoulv.Average() List<float> last100Outdoor = new List<float>();
_Xieloulv = experData.CumulativeLeakageRate(
list_Tsi_Indoor_Data, for (int i = startIndex; i < dataCount; i++)
list_Tsi_Outdoor_Data, {
last100Indoor.Add(list_Tsi_Indoor_Data[i]);
last100Outdoor.Add(list_Tsi_Outdoor_Data[i]);
}
if (last100Indoor.Count > 0 && last100Outdoor.Count > 0)
{
_TsiIndoorAgv = last100Indoor.Average();
_TsiOutdoorAgv = last100Outdoor.Average();
// 使用连续采样法计算公式
_Xieloulv = experData.ContinuousSamplingLeakageRate(
last100Indoor,
last100Outdoor,
experData.BenDiNongDu, experData.BenDiNongDu,
experData.YangPinXiShu); experData.SamplingFlowRate,
experData.DryingFlowRate);
} }
else else
{ {
@@ -581,12 +594,12 @@ namespace 口罩泄露定制款
experData.ExperNum, experData.ExperNum,
experData.ExperType, experData.ExperType,
comboBox1.Text, comboBox1.Text,
experData.HuanJingWenDu, experData.HuanJingWenDu.ToString("F1"),
experData.HuanJingShiDu, experData.HuanJingShiDu.ToString("F1"),
experData.BenDiNongDu, experData.BenDiNongDu.ToString("F3"),
_TsiIndoorAgv, _TsiIndoorAgv.ToString("F3"),
_TsiOutdoorAgv, _TsiOutdoorAgv.ToString("F3"),
_Xieloulv); // 这里使用统一计算后的泄露率 _Xieloulv.ToString("F2"));
this.Invoke(new Action(() => this.Invoke(new Action(() =>
{ {
@@ -599,11 +612,12 @@ namespace 口罩泄露定制款
private void InsertDataToDatabase() private void InsertDataToDatabase()
{ {
float _Xieloulv = 0.0f; float _Xieloulv = 0.0f;
_Xieloulv = experData.CumulativeLeakageRate( _Xieloulv = experData.ContinuousSamplingLeakageRate(
list_Tsi_Indoor_Data, list_Tsi_Indoor_Data,
list_Tsi_Outdoor_Data, list_Tsi_Outdoor_Data,
experData.BenDiNongDu, experData.BenDiNongDu,
experData.YangPinXiShu); experData.SamplingFlowRate,
experData.DryingFlowRate);
// 读取用户数据 // 读取用户数据
@@ -979,6 +993,7 @@ namespace 口罩泄露定制款
List<float> list_O2_Data = new List<float>();//氧气浓度 List<float> list_O2_Data = new List<float>();//氧气浓度
List<float> list_HuanJingWenDu_Data = new List<float>();//环境内温度 List<float> list_HuanJingWenDu_Data = new List<float>();//环境内温度
List<float> list_HuanJingShiDu_Data = new List<float>();//环境湿度 List<float> list_HuanJingShiDu_Data = new List<float>();//环境湿度
// 修改timer_UpdataChart_Tick - 实时泄漏率计算
private void timer_UpdataChart_Tick(object sender, EventArgs e) private void timer_UpdataChart_Tick(object sender, EventArgs e)
{ {
int currindex = 0; int currindex = 0;
@@ -990,18 +1005,43 @@ namespace 口罩泄露定制款
{ {
currindex = 2; currindex = 2;
} }
if (data_M130_M135[1] && currentStepIndex >= currindex) if (data_M130_M135[1] && currentStepIndex >= currindex)
{ {
list_Time.Add(DateTime.Now.ToString("HH:mm:ss")); list_Time.Add(DateTime.Now.ToString("HH:mm:ss"));
list_Tsi_Indoor_Data.Add(experData.InDoor_TSINongDu); list_Tsi_Indoor_Data.Add(experData.InDoor_TSINongDu);
list_Tsi_Outdoor_Data.Add(experData.Mask_TSINongDu); list_Tsi_Outdoor_Data.Add(experData.Mask_TSINongDu);
experData.XieLouLv = experData.CumulativeLeakageRate(list_Tsi_Indoor_Data, list_Tsi_Outdoor_Data, experData.BenDiNongDu, experData.YangPinXiShu);
// 使用最后100秒数据计算实时泄漏率
int dataCount = Math.Min(list_Tsi_Indoor_Data.Count, list_Tsi_Outdoor_Data.Count);
int startIndex = Math.Max(0, dataCount - 100);
List<float> last100Indoor = new List<float>();
List<float> last100Outdoor = new List<float>();
for (int i = startIndex; i < dataCount; i++)
{
last100Indoor.Add(list_Tsi_Indoor_Data[i]);
last100Outdoor.Add(list_Tsi_Outdoor_Data[i]);
}
if (last100Indoor.Count > 0 && last100Outdoor.Count > 0)
{
experData.XieLouLv = experData.ContinuousSamplingLeakageRate(
last100Indoor,
last100Outdoor,
experData.BenDiNongDu,
experData.SamplingFlowRate,
experData.DryingFlowRate);
}
lsit_XieLoulv.Add(experData.XieLouLv); lsit_XieLoulv.Add(experData.XieLouLv);
list_CO2_Indoor_Data.Add(experData.CO2NongDu_Indoor); list_CO2_Indoor_Data.Add(experData.CO2NongDu_Indoor);
list_CO2_Outdoor_Data.Add(experData.Mask_CO2NongDu); list_CO2_Outdoor_Data.Add(experData.Mask_CO2NongDu);
list_O2_Data.Add(experData.O2NongDu); list_O2_Data.Add(experData.O2NongDu);
list_HuanJingWenDu_Data.Add(experData.HuanJingWenDu); list_HuanJingWenDu_Data.Add(experData.HuanJingWenDu);
list_HuanJingShiDu_Data.Add(experData.HuanJingShiDu); list_HuanJingShiDu_Data.Add(experData.HuanJingShiDu);
chart_TSI.Series[0].Points.DataBindXY(list_Time, list_Tsi_Indoor_Data); chart_TSI.Series[0].Points.DataBindXY(list_Time, list_Tsi_Indoor_Data);
chart_TSI.Series[1].Points.DataBindXY(list_Time, list_Tsi_Outdoor_Data); chart_TSI.Series[1].Points.DataBindXY(list_Time, list_Tsi_Outdoor_Data);
chart_TSI.Series[2].Points.DataBindXY(list_Time, lsit_XieLoulv); chart_TSI.Series[2].Points.DataBindXY(list_Time, lsit_XieLoulv);
@@ -1010,9 +1050,7 @@ namespace 口罩泄露定制款
chart2.Series[2].Points.DataBindXY(list_Time, list_O2_Data); chart2.Series[2].Points.DataBindXY(list_Time, list_O2_Data);
chart2.Series[3].Points.DataBindXY(list_Time, list_HuanJingWenDu_Data); chart2.Series[3].Points.DataBindXY(list_Time, list_HuanJingWenDu_Data);
chart2.Series[4].Points.DataBindXY(list_Time, list_HuanJingShiDu_Data); chart2.Series[4].Points.DataBindXY(list_Time, list_HuanJingShiDu_Data);
} }
} }
//结束时写入Excel //结束时写入Excel
public static int comindex; public static int comindex;
@@ -1091,6 +1129,7 @@ namespace 口罩泄露定制款
#endregion #endregion
#region #region
// 修改btn_Start_Click - 加载配置参数
private void btn_Start_Click(object sender, EventArgs e) private void btn_Start_Click(object sender, EventArgs e)
{ {
string configPath = Path.Combine(Application.StartupPath, "UserData.json"); string configPath = Path.Combine(Application.StartupPath, "UserData.json");
@@ -1099,23 +1138,15 @@ namespace 口罩泄露定制款
var json = File.ReadAllText(configPath); var json = File.ReadAllText(configPath);
dynamic config = Newtonsoft.Json.JsonConvert.DeserializeObject(json); dynamic config = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
experData.BenDiNongDu = config.BenDiNongdu; experData.BenDiNongDu = config.BenDiNongdu;
experData.YangPinXiShu = config.ParticleSize; experData.SamplingFlowRate = config.SamplingFlowRate ?? 2.0f;
experData.DryingFlowRate = config.DryingFlowRate ?? 1.0f;
experData.ExperName = config.Category; experData.ExperName = config.Category;
} }
isPaused = false; isPaused = false;
Pause1.Text = "暂停测试"; Pause1.Text = "暂停测试";
Pause1.Style = UIStyle.Red; Pause1.Style = UIStyle.Red;
//if (experData.BenDiNongDu == 0.0f)//add by xyy
////if (false)
//{
// MessageBox.Show("未校准本底浓度!");
// return;
//}
//else
//{
// 清空数据 // 清空数据
list_Time.Clear(); list_Time.Clear();
list_Tsi_Indoor_Data.Clear(); list_Tsi_Indoor_Data.Clear();
@@ -1130,7 +1161,6 @@ namespace 口罩泄露定制款
fc?.BtnClickFunction(Function.ButtonType., 130); fc?.BtnClickFunction(Function.ButtonType., 130);
LoadIsNeedRunConfig(); LoadIsNeedRunConfig();
InitStepList(); InitStepList();
@@ -1139,10 +1169,8 @@ namespace 口罩泄露定制款
StartProcess(); StartProcess();
_logger.Log(loginData.UserName, "点击了【测试开始】按钮", loginData.UserPower.ToString()); _logger.Log(loginData.UserName, "点击了【测试开始】按钮", loginData.UserPower.ToString());
//}
} }
private void btn_Stop_Click(object sender, EventArgs e) private void btn_Stop_Click(object sender, EventArgs e)
{ {
isPaused = false; isPaused = false;

View File

@@ -281,6 +281,7 @@
<EmbeddedResource Include="UserControl\TreeComboBox.resx"> <EmbeddedResource Include="UserControl\TreeComboBox.resx">
<DependentUpon>TreeComboBox.cs</DependentUpon> <DependentUpon>TreeComboBox.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<None Include="Data\UserData.json" />
<None Include="ParticleTypeConfig.json" /> <None Include="ParticleTypeConfig.json" />
<None Include="MaskTypeConfig.json" /> <None Include="MaskTypeConfig.json" />
<None Include="packages.config" /> <None Include="packages.config" />