From 028728b816d825959467ab1fc57dd0fced4337f3 Mon Sep 17 00:00:00 2001
From: xyy <544939200@qq.com>
Date: Thu, 22 Jan 2026 19:18:16 +0800
Subject: [PATCH]
---
口罩泄露定制款/Data/ExperData.cs | 161 +++++++++++++-----
口罩泄露定制款/Data/UserData.json | 36 ++++
口罩泄露定制款/DatabaseHelper/SQLiteHelper.cs | 6 +
口罩泄露定制款/Form/frm_Main.cs | 112 +++++++-----
口罩泄露定制款/口罩泄露定制款山东.csproj | 1 +
5 files changed, 227 insertions(+), 89 deletions(-)
create mode 100644 口罩泄露定制款/Data/UserData.json
diff --git a/口罩泄露定制款/Data/ExperData.cs b/口罩泄露定制款/Data/ExperData.cs
index 7cb1cc7..458368a 100644
--- a/口罩泄露定制款/Data/ExperData.cs
+++ b/口罩泄露定制款/Data/ExperData.cs
@@ -7,145 +7,212 @@ using System.Threading.Tasks;
namespace 口罩泄露定制款
{
- public class ExperData: INotifyPropertyChanged
+ public class ExperData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
+
#region 实验属性
static string experName = "";
///
/// 实验人员
///
public string ExperName { get { return experName; } set { experName = value; } }
-
+
static string experDate = "";
///
/// 实验日期
///
public string ExperDate { get { return experDate; } set { experDate = value; } }
-
+
static string experNum = "";
///
/// 实验编号
///
public string ExperNum { get { return experNum; } set { experNum = value; } }
-
+
static string experType = " ";
///
/// 实验种类
///
public string ExperType { get { return experType; } set { experType = value; } }
+
static float experMaskType = 2.0f;
///
- /// 口罩类型
+ /// 口罩类型泄漏率标准
///
public float ExperMaskType { get { return experMaskType; } set { experMaskType = value; } }
+
///
/// 面罩类型
///
static string maskType;
public string MaskType { get { return maskType; } set { maskType = value; } }
- static float _yangPinXiShu = 1.0f;
+
+ static float _testDuration = 120f; // 测试时间改为120秒
///
- /// 样品系数
+ /// 测试时长(秒)
///
- public float YangPinXiShu { get { return _yangPinXiShu; } set { _yangPinXiShu = value; } }
+ public float TestDuration { get { return _testDuration; } set { _testDuration = value; } }
+
static string _testStatus = "";
-
-
///
/// 实验状态
///
public string TestStatus { get { return _testStatus; } set { _testStatus = value; } }
+
static float benDiNongDu = 0.00f;
///
- /// 本底浓度
+ /// 本底浓度(mg/m³)
///
public float BenDiNongDu { get { return benDiNongDu; } set { benDiNongDu = value; } }
-
+
static float huanJingWenDu = 0.00f;
///
/// 环境温度
///
public float HuanJingWenDu { get { return huanJingWenDu; } set { huanJingWenDu = value; } }
-
-
+
static float huanJingShiDu = 0.00f;
///
/// 环境湿度
///
public float HuanJingShiDu { get { return huanJingShiDu; } set { huanJingShiDu = value; } }
-
+
static float o2NongDu = 0.00f;
///
/// 环境氧浓度
///
public float O2NongDu { get { return o2NongDu; } set { o2NongDu = value; } }
-
+
static float cO2NongDu = 0.00f;
///
- /// 环境C02浓度
+ /// 环境CO2浓度
///
public float CO2NongDu_Indoor { get { return cO2NongDu; } set { cO2NongDu = value; } }
-
+
static float inDoor_TSINongDu = 0.00f;
///
- /// 环境气溶胶浓度
+ /// 环境气溶胶浓度(mg/m³)
///
public float InDoor_TSINongDu { get { return inDoor_TSINongDu; } set { inDoor_TSINongDu = value; } }
-
+
static float mask_CO2NongDu = 0.00f;
///
/// 口罩内CO2浓度
///
public float Mask_CO2NongDu { get { return mask_CO2NongDu; } set { mask_CO2NongDu = value; } }
-
+
static float mask_TSINongDu = 0.00f;
///
- /// 口罩内气溶胶浓度
+ /// 口罩内气溶胶浓度(mg/m³)
///
public float Mask_TSINongDu { get { return mask_TSINongDu; } set { mask_TSINongDu = value; } }
static float _liuLiang = 0.00f;
///
- /// 流量
+ /// 流量(L/min)
///
public float LiuLiang { get { return _liuLiang; } set { _liuLiang = value; } }
+
static float _xieloulv = 0.00f;
///
- /// 泄露率
+ /// 泄露率(%)
///
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
- #region 泄露率计算
- //单独动作泄露率
- public float CumulativeLeakageRate(List inDoor_Tsi,List out_Door_Tsi,float benDiNongdu,float xiShu)
+ #region 泄漏率计算方法(根据YY/T 0866-2024标准)
+
+ ///
+ /// 连续采样法泄漏率计算(公式2)
+ /// P = 1.25 * ((C2 - C0) / C1) * ((S + D) / S) * 100
+ ///
+ public float ContinuousSamplingLeakageRate(List indoorData, List outdoorData,
+ float backgroundConcentration,
+ float samplingFlow, float dryingFlow)
{
- if (inDoor_Tsi.Count != 0 && out_Door_Tsi.Count != 0)
- {
- //计算室内Tsi浓度平均值
- float inDoor_Tsi_Avg = inDoor_Tsi.Average();
- //计算室外Tsi浓度平均值
- float out_Door_Tsi_Avg = out_Door_Tsi.Average();
- //计算泄露率
- float leakageRate = ((out_Door_Tsi_Avg - benDiNongdu ) * xiShu)*100 / inDoor_Tsi_Avg;
- return leakageRate;
- }
- else
+ 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++)
{
- return 0.00f;
+ C1 += indoorData[i];
+ C2 += outdoorData[i];
+ validCount++;
}
-
- }
- //全部动作泄露率
- public float CumulativeLeakageRate_All(List All_Cv_List)
+ if (validCount == 0)
+ return 0.0f;
+
+ C1 /= validCount;
+ 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); // 确保非负
+ }
+
+ ///
+ /// 脉冲式采样法泄漏率计算(公式1) - 备用
+ ///
+ public float PulsedSamplingLeakageRate(List indoorData, List outdoorData,
+ float backgroundConcentration,
+ float samplingFlow, float dryingFlow,
+ float totalInhaleTime, float totalExhaleTime)
{
- return All_Cv_List.Average();
- }
- #endregion
+ 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
}
-}
+}
\ No newline at end of file
diff --git a/口罩泄露定制款/Data/UserData.json b/口罩泄露定制款/Data/UserData.json
new file mode 100644
index 0000000..2cfc260
--- /dev/null
+++ b/口罩泄露定制款/Data/UserData.json
@@ -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
+}
+}
\ No newline at end of file
diff --git a/口罩泄露定制款/DatabaseHelper/SQLiteHelper.cs b/口罩泄露定制款/DatabaseHelper/SQLiteHelper.cs
index 34d5ac8..5b0cb31 100644
--- a/口罩泄露定制款/DatabaseHelper/SQLiteHelper.cs
+++ b/口罩泄露定制款/DatabaseHelper/SQLiteHelper.cs
@@ -67,6 +67,12 @@ public class Experiment
public float TsiIndoorAgv { get; set; }
public float TsiOutdoorAgv { 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; } // 测试时长(秒)
}
diff --git a/口罩泄露定制款/Form/frm_Main.cs b/口罩泄露定制款/Form/frm_Main.cs
index c813b7b..b4cc5df 100644
--- a/口罩泄露定制款/Form/frm_Main.cs
+++ b/口罩泄露定制款/Form/frm_Main.cs
@@ -78,7 +78,7 @@ namespace 口罩泄露定制款
}
}
- // 3. 步骤初始化
+ // 步骤初始化 - 根据新标准调整
private void InitStepList()
{
stepList.Clear();
@@ -86,11 +86,11 @@ namespace 口罩泄露定制款
stepList.Add("请将采样管插头插入测量接口");
if (isNeedRun)
stepList.Add("请按下跑步机启动按钮");
- stepList.Add("头部静止、不说话,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("左右转动头部看检测仓左右墙壁(大约15次),2 min");
+ stepList.Add("抬头和低头看检测仓顶和地面(大约15次),2 min");
+ stepList.Add("大声阅读屏幕显示文字,2 min");
+ stepList.Add("头部静止、不说话,2 min");
stepList.Add("测试完成,拔下采样管插头,走出测量仓");
comboBox1.Items.Clear();
foreach (var step in stepList)
@@ -541,18 +541,31 @@ namespace 口罩泄露定制款
if (dt_Show.Columns.Count != 0)
{
- if (list_Tsi_Indoor_Data.Count != 0 && list_Tsi_Outdoor_Data.Count != 0)
- {
- _TsiIndoorAgv = list_Tsi_Indoor_Data.Average();
- _TsiOutdoorAgv = list_Tsi_Outdoor_Data.Average();
+ // 使用最后100秒数据计算(标准要求)
+ int dataCount = Math.Min(list_Tsi_Indoor_Data.Count, list_Tsi_Outdoor_Data.Count);
+ int startIndex = Math.Max(0, dataCount - 100);
- // 关键修改:使用与 timer_UpdataChart_Tick 中相同的计算方法
- // 而不是简单的 lsit_XieLoulv.Average()
- _Xieloulv = experData.CumulativeLeakageRate(
- list_Tsi_Indoor_Data,
- list_Tsi_Outdoor_Data,
+ List last100Indoor = new List();
+ List last100Outdoor = new List();
+
+ 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)
+ {
+ _TsiIndoorAgv = last100Indoor.Average();
+ _TsiOutdoorAgv = last100Outdoor.Average();
+
+ // 使用连续采样法计算公式
+ _Xieloulv = experData.ContinuousSamplingLeakageRate(
+ last100Indoor,
+ last100Outdoor,
experData.BenDiNongDu,
- experData.YangPinXiShu);
+ experData.SamplingFlowRate,
+ experData.DryingFlowRate);
}
else
{
@@ -581,12 +594,12 @@ namespace 口罩泄露定制款
experData.ExperNum,
experData.ExperType,
comboBox1.Text,
- experData.HuanJingWenDu,
- experData.HuanJingShiDu,
- experData.BenDiNongDu,
- _TsiIndoorAgv,
- _TsiOutdoorAgv,
- _Xieloulv); // 这里使用统一计算后的泄露率
+ experData.HuanJingWenDu.ToString("F1"),
+ experData.HuanJingShiDu.ToString("F1"),
+ experData.BenDiNongDu.ToString("F3"),
+ _TsiIndoorAgv.ToString("F3"),
+ _TsiOutdoorAgv.ToString("F3"),
+ _Xieloulv.ToString("F2"));
this.Invoke(new Action(() =>
{
@@ -599,11 +612,12 @@ namespace 口罩泄露定制款
private void InsertDataToDatabase()
{
float _Xieloulv = 0.0f;
- _Xieloulv = experData.CumulativeLeakageRate(
+ _Xieloulv = experData.ContinuousSamplingLeakageRate(
list_Tsi_Indoor_Data,
list_Tsi_Outdoor_Data,
experData.BenDiNongDu,
- experData.YangPinXiShu);
+ experData.SamplingFlowRate,
+ experData.DryingFlowRate);
// 读取用户数据
@@ -979,6 +993,7 @@ namespace 口罩泄露定制款
List list_O2_Data = new List();//氧气浓度
List list_HuanJingWenDu_Data = new List();//环境内温度
List list_HuanJingShiDu_Data = new List();//环境湿度
+ // 修改timer_UpdataChart_Tick - 实时泄漏率计算
private void timer_UpdataChart_Tick(object sender, EventArgs e)
{
int currindex = 0;
@@ -990,18 +1005,43 @@ namespace 口罩泄露定制款
{
currindex = 2;
}
+
if (data_M130_M135[1] && currentStepIndex >= currindex)
{
list_Time.Add(DateTime.Now.ToString("HH:mm:ss"));
list_Tsi_Indoor_Data.Add(experData.InDoor_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 last100Indoor = new List();
+ List last100Outdoor = new List();
+
+ 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);
list_CO2_Indoor_Data.Add(experData.CO2NongDu_Indoor);
list_CO2_Outdoor_Data.Add(experData.Mask_CO2NongDu);
list_O2_Data.Add(experData.O2NongDu);
list_HuanJingWenDu_Data.Add(experData.HuanJingWenDu);
list_HuanJingShiDu_Data.Add(experData.HuanJingShiDu);
+
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[2].Points.DataBindXY(list_Time, lsit_XieLoulv);
@@ -1010,9 +1050,7 @@ namespace 口罩泄露定制款
chart2.Series[2].Points.DataBindXY(list_Time, list_O2_Data);
chart2.Series[3].Points.DataBindXY(list_Time, list_HuanJingWenDu_Data);
chart2.Series[4].Points.DataBindXY(list_Time, list_HuanJingShiDu_Data);
-
}
-
}
//结束时写入Excel
public static int comindex;
@@ -1091,6 +1129,7 @@ namespace 口罩泄露定制款
#endregion
#region 按钮事件
+ // 修改btn_Start_Click - 加载配置参数
private void btn_Start_Click(object sender, EventArgs e)
{
string configPath = Path.Combine(Application.StartupPath, "UserData.json");
@@ -1099,23 +1138,15 @@ namespace 口罩泄露定制款
var json = File.ReadAllText(configPath);
dynamic config = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
experData.BenDiNongDu = config.BenDiNongdu;
- experData.YangPinXiShu = config.ParticleSize;
+ experData.SamplingFlowRate = config.SamplingFlowRate ?? 2.0f;
+ experData.DryingFlowRate = config.DryingFlowRate ?? 1.0f;
experData.ExperName = config.Category;
}
+
isPaused = false;
Pause1.Text = "暂停测试";
Pause1.Style = UIStyle.Red;
-
-
- //if (experData.BenDiNongDu == 0.0f)//add by xyy
- ////if (false)
- //{
- // MessageBox.Show("未校准本底浓度!");
- // return;
- //}
- //else
- //{
// 清空数据
list_Time.Clear();
list_Tsi_Indoor_Data.Clear();
@@ -1130,7 +1161,6 @@ namespace 口罩泄露定制款
fc?.BtnClickFunction(Function.ButtonType.复归型, 130);
-
LoadIsNeedRunConfig();
InitStepList();
@@ -1139,10 +1169,8 @@ namespace 口罩泄露定制款
StartProcess();
_logger.Log(loginData.UserName, "点击了【测试开始】按钮", loginData.UserPower.ToString());
- //}
}
-
private void btn_Stop_Click(object sender, EventArgs e)
{
isPaused = false;
@@ -2169,7 +2197,7 @@ namespace 口罩泄露定制款
list_Tsi_Outdoor_Data.Clear();
//experData.XieLouLv = experData.CumulativeLeakageRate(list_Tsi_Indoor_Data, list_Tsi_Outdoor_Data, experData.BenDiNongDu, 1.0f);
lsit_XieLoulv.Clear();
- list_CO2_Indoor_Data.Clear();
+ list_CO2_Indoor_Data.Clear();
list_CO2_Outdoor_Data.Clear();
list_O2_Data.Clear();
list_HuanJingWenDu_Data.Clear();
diff --git a/口罩泄露定制款/口罩泄露定制款山东.csproj b/口罩泄露定制款/口罩泄露定制款山东.csproj
index c8fc81e..387a136 100644
--- a/口罩泄露定制款/口罩泄露定制款山东.csproj
+++ b/口罩泄露定制款/口罩泄露定制款山东.csproj
@@ -281,6 +281,7 @@
TreeComboBox.cs
+