240 lines
7.0 KiB
C#
240 lines
7.0 KiB
C#
using Modbus.Device;
|
||
using Microsoft.Win32;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Net.Sockets;
|
||
using System.Text;
|
||
using System.Windows;
|
||
using 头罩视野.Services.Data;
|
||
|
||
public static class ModbusHelper
|
||
{
|
||
// 全局唯一连接,所有页面共用
|
||
public static TcpClient TcpClient => ModbusResourceManager.Instance.TcpClient;
|
||
|
||
|
||
// 统一连接方法(全项目只调用一次)
|
||
public static bool Connect(string ip, int port = 502)
|
||
{
|
||
return ModbusResourceManager.Instance.Init(ip, port);
|
||
}
|
||
|
||
// 判断是否连接成功
|
||
public static bool IsConnected => TcpClient != null && TcpClient.Connected;
|
||
|
||
|
||
// <summary>
|
||
/// 公共保存方法(用户自选文件夹)
|
||
/// </summary>
|
||
/// <param name="dataList">你的数据集合</param>
|
||
/// <param name="defaultFileName">默认文件名</param>
|
||
public static void SaveToCsv(List<dynamic> dataList, string defaultFileName)
|
||
{
|
||
if (dataList == null || dataList.Count == 0)
|
||
{
|
||
MessageBox.Show("无数据可保存!");
|
||
return;
|
||
}
|
||
|
||
// 选择文件夹
|
||
var folderDialog = new OpenFolderDialog
|
||
{
|
||
Title = "请选择保存路径"
|
||
};
|
||
|
||
if (folderDialog.ShowDialog() != true)
|
||
return;
|
||
|
||
string folderPath = folderDialog.FolderName;
|
||
string filePath = Path.Combine(folderPath, defaultFileName);
|
||
|
||
// 写入 CSV
|
||
using (var sw = new StreamWriter(filePath, false, Encoding.UTF8))
|
||
{
|
||
var firstRow = (IDictionary<string, object>)dataList[0];
|
||
sw.WriteLine(string.Join(",", firstRow.Keys));
|
||
|
||
foreach (var item in dataList)
|
||
{
|
||
var dict = (IDictionary<string, object>)item;
|
||
sw.WriteLine(string.Join(",", dict.Values));
|
||
}
|
||
}
|
||
|
||
MessageBox.Show("保存成功!\n" + filePath);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 计算单眼视野面积
|
||
/// </summary>
|
||
/// <param name="groupData">20组数据,每组72个通道</param>
|
||
/// <param name="threshold">有效亮度阈值(如80)</param>
|
||
/// <param name="standardTotalArea">标准视野面积(如120)</param>
|
||
/// <returns>计算好的面积</returns>
|
||
///
|
||
public static double CalculateEyeArea(List<double[]> groupData, double threshold, double standardArea)
|
||
{
|
||
double[] avg = new double[72];
|
||
for (int c = 0; c < 72; c++)
|
||
{
|
||
double sum = 0;
|
||
foreach (var g in groupData) sum += g[c];
|
||
avg[c] = sum / groupData.Count;
|
||
}
|
||
|
||
int valid = avg.Count(v => v >= threshold);
|
||
return (valid / 72.0) * standardArea;
|
||
}
|
||
//计算单眼面积调用的方法
|
||
|
||
//double leftArea = CalculateEyeArea(
|
||
// leftEye20Groups, // 左眼20组数据
|
||
// 80, // 阈值
|
||
// 120 // 标准面积
|
||
//);
|
||
//double rightArea = .CalculateEyeArea(
|
||
// rightEye20Groups, // 右眼20组数据
|
||
// 80, // 阈值
|
||
// 120 // 标准面积
|
||
//);
|
||
|
||
|
||
|
||
//计算双目视野面积
|
||
/// <summary>
|
||
/// 计算双目视野面积(左右眼同时可见)
|
||
/// </summary>
|
||
public static double CalcBinocularArea(
|
||
List<double[]> leftGroups,
|
||
List<double[]> rightGroups,
|
||
double threshold,
|
||
double standardArea)
|
||
{
|
||
// 1. 左眼平均数据
|
||
double[] leftAvg = new double[72];
|
||
for (int i = 0; i < 72; i++)
|
||
{
|
||
double sum = 0;
|
||
foreach (var g in leftGroups) sum += g[i];
|
||
leftAvg[i] = sum / leftGroups.Count;
|
||
}
|
||
|
||
// 2. 右眼平均数据
|
||
double[] rightAvg = new double[72];
|
||
for (int i = 0; i < 72; i++)
|
||
{
|
||
double sum = 0;
|
||
foreach (var g in rightGroups) sum += g[i];
|
||
rightAvg[i] = sum / rightGroups.Count;
|
||
}
|
||
|
||
// 3. 双目同时有效点数(左右都亮才算)
|
||
int biValid = 0;
|
||
for (int i = 0; i < 72; i++)
|
||
{
|
||
if (leftAvg[i] >= threshold && rightAvg[i] >= threshold)
|
||
biValid++;
|
||
}
|
||
|
||
// 4. 双目视野面积
|
||
return (biValid / 72.0) * standardArea;
|
||
}
|
||
|
||
//调用公式
|
||
|
||
// 你从Modbus拿到的20组数据
|
||
//List<double[]> left20Groups = ...;
|
||
//List<double[]> right20Groups = ...;
|
||
|
||
//double threshold = 80;
|
||
//double standardArea = 120;
|
||
|
||
//// 左眼
|
||
//double left = VisionCalculator.CalcEyeArea(left20Groups, threshold, standardArea);
|
||
|
||
//// 右眼
|
||
//double right = VisionCalculator.CalcEyeArea(right20Groups, threshold, standardArea);
|
||
|
||
//// 双目视野面积
|
||
//double binocular = VisionCalculator.CalcBinocularArea(left20Groups, right20Groups, threshold, standardArea);
|
||
|
||
//// 总视野面积
|
||
//double total = left + right - binocular;
|
||
|
||
|
||
//下方视野面积
|
||
|
||
public static double CalcLowerEyeArea(
|
||
List<double[]> eyeGroups,
|
||
double threshold,
|
||
double standardLowerArea)
|
||
{
|
||
// 1. 每个通道求20组平均
|
||
double[] avg = new double[72];
|
||
for (int i = 0; i < 72; i++)
|
||
{
|
||
double sum = 0;
|
||
foreach (var g in eyeGroups) sum += g[i];
|
||
avg[i] = sum / eyeGroups.Count;
|
||
}
|
||
|
||
// 2. 只统计下半 36 个通道(下方视野)
|
||
int validCount = 0;
|
||
for (int i = 36; i < 72; i++) // 36~71 是下半区
|
||
{
|
||
if (avg[i] >= threshold)
|
||
validCount++;
|
||
}
|
||
|
||
// 3. 计算下方视野面积
|
||
return (validCount / 36.0) * standardLowerArea;
|
||
}
|
||
|
||
// 总下方视野面积调用
|
||
//double totalLower = leftLower + rightLower - binocularLower;
|
||
|
||
|
||
//空白视野面积计算
|
||
|
||
//空白视野面积 = 标准视野总面积 − 实测总视野面积
|
||
//总视野面积 = 左眼面积 + 右眼面积 − 双目重叠面积
|
||
// 前面已经算出来的
|
||
//double leftArea = ...;
|
||
//double rightArea = ...;
|
||
//double binocularArea = ...;
|
||
|
||
//// 总视野
|
||
//double totalVisionArea = leftArea + rightArea - binocularArea;
|
||
|
||
//// 标准总面积(设备固定值,比如 120)
|
||
//double standardTotalArea = 120;
|
||
|
||
//// 空白视野面积
|
||
//double blankArea = standardTotalArea - totalVisionArea;
|
||
|
||
|
||
|
||
|
||
//视野保存率
|
||
//double totalSaveRate = (总视野面积 / 标准总视野面积) * 100;
|
||
public static class VisionCalculator
|
||
{
|
||
/// <summary>
|
||
/// 计算视野保存率
|
||
/// </summary>
|
||
/// <param name="actualArea">实测面积</param>
|
||
/// <param name="standardArea">标准面积</param>
|
||
/// <returns>保存率 %</returns>
|
||
public static double CalculateVisionSaveRate(double actualArea, double standardArea)
|
||
{
|
||
if (standardArea == 0) return 0;
|
||
return (actualArea / standardArea) * 100;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//double totalSaveRate = VisionCalculator.CalculateVisionSaveRate(totalVisionArea, standardTotalArea);
|
||
} |