实现温度数据处理功能:添加温度数据模型类、温度接收功能和相关集成

This commit is contained in:
zqm
2025-10-30 16:46:57 +08:00
parent 4ab2ddf1f3
commit 3501e9c952
5 changed files with 1112 additions and 0 deletions

View File

@@ -205,6 +205,7 @@ namespace JoyD.Windows.CS.Toprie
if (_isReceivingImage)
{
_deviceManager.StopImageReceiving();
_deviceManager.StopTemperatureDataReceiving();
_isReceivingImage = false;
}
}
@@ -224,7 +225,9 @@ namespace JoyD.Windows.CS.Toprie
if (_deviceManager.ConnectionStatus == ConnectionStatus.Connected)
{
_deviceManager.StopImageReceiving();
_deviceManager.StopTemperatureDataReceiving();
_deviceManager.StartImageReceiving();
_deviceManager.StartTemperatureDataReceiving();
_isReceivingImage = true;
// 恢复检测后,启动连接检查以确保连接正常
@@ -503,6 +506,7 @@ namespace JoyD.Windows.CS.Toprie
Console.WriteLine("Camera开始使用HTTP方式接收图像");
// 直接调用HTTP方式的图像接收
_deviceManager.StartImageReceiving();
_deviceManager.StartTemperatureDataReceiving();
_isReceivingImage = true;
}
}

View File

@@ -69,6 +69,25 @@ namespace JoyD.Windows.CS.Toprie
Fusion5 // 融合5对应SDK参数6
}
/// <summary>
/// 温度模式枚举
/// </summary>
public enum TemperatureMode
{
/// <summary>
/// 摄氏度
/// </summary>
Celsius,
/// <summary>
/// 华氏度
/// </summary>
Fahrenheit,
/// <summary>
/// 开尔文
/// </summary>
Kelvin
}
/// <summary>
/// 连接状态改变事件参数
/// </summary>
@@ -242,6 +261,14 @@ namespace JoyD.Windows.CS.Toprie
private Thread _imageReconnectThread;
private Stream _imageStream;
// 温度数据接收相关字段
private Thread _temperatureReceiveThread;
private TcpClient _temperatureTcpClient;
private NetworkStream _temperatureStream;
private bool _isReceivingTemperatureData = false;
private ManualResetEvent _stopTemperatureEvent;
private const int TEMPERATURE_TCP_PORT = 7682; // 温度数据TCP端口
/// <summary>
/// 项目路径属性
/// 用于设置控件存取数据文件的目录
@@ -610,6 +637,10 @@ namespace JoyD.Windows.CS.Toprie
// 启动图像接收
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 连接成功,启动图像接收");
StartImageReceiving();
// 启动温度数据接收
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] Initialize() - 启动温度数据接收");
StartTemperatureDataReceiving();
return true;
}
@@ -645,6 +676,8 @@ namespace JoyD.Windows.CS.Toprie
StopAutoReconnect();
StopHeartbeat();
StopConnectionCheck();
// 停止温度数据接收
StopTemperatureDataReceiving();
// 安全释放SDK实例
A8SDK oldSdk = Interlocked.Exchange(ref _a8Sdk, null);
@@ -802,6 +835,377 @@ namespace JoyD.Windows.CS.Toprie
#endregion
#region
/// <summary>
/// 获取温度补偿值
/// </summary>
/// <returns>温度补偿值</returns>
private float GetTemperatureCompensationValue()
{
try
{
if (_connectionStatus == ConnectionStatus.Connected && _a8Sdk != null)
{
float compensationValue = _a8Sdk.Comp_temp;
Log($"获取温度补偿值: {compensationValue}");
return compensationValue;
}
}
catch (Exception ex)
{
Log($"获取温度补偿值异常: {ex.Message}");
}
return 0.0f;
}
/// <summary>
/// 开始接收温度数据
/// </summary>
public void StartTemperatureDataReceiving()
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 开始执行");
// 在设计模式下,跳过实际的温度数据接收
if (IsDesignMode)
{
Log("设计模式下跳过实际的温度数据接收");
return;
}
lock (_lockObject)
{
// 检查对象是否已被释放
if (_isDisposed)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 对象已释放,忽略操作");
return;
}
// 检查连接状态
if (_connectionStatus != ConnectionStatus.Connected)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 连接未建立,无法开始温度数据接收");
return;
}
}
Log("开始使用TCP方式接收温度数据");
try
{
// 确保之前的连接已关闭
StopTemperatureDataReceiving();
// 重置停止事件
_stopTemperatureEvent = new ManualResetEvent(false);
lock (_lockObject)
{
_isReceivingTemperatureData = true;
}
// 创建并启动温度数据接收线程
_temperatureReceiveThread = new Thread(ReceiveTemperatureDataWithTcp)
{
IsBackground = true,
Name = "TemperatureReceiveThread"
};
_temperatureReceiveThread.Start();
}
catch (Exception ex)
{
// 记录异常
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 异常: {ex.Message}");
lock (_lockObject)
{
_isReceivingTemperatureData = false;
}
// 如果连接状态异常,触发异常事件
OnConnectionException(new ConnectionExceptionEventArgs(ex, "启动温度数据接收失败"));
}
finally
{
// 确保方法执行完成时记录日志
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StartTemperatureDataReceiving() - 执行完成");
}
}
/// <summary>
/// 停止接收温度数据
/// </summary>
public void StopTemperatureDataReceiving()
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 开始执行");
if (_isDisposed)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 对象已释放,跳过操作");
return;
}
try
{
// 线程安全地更新状态
lock (_lockObject)
{
_isReceivingTemperatureData = false;
}
// 通知线程停止
ManualResetEvent stopEvent = null;
lock (_lockObject)
{
stopEvent = _stopTemperatureEvent;
}
if (stopEvent != null)
{
try
{
stopEvent.Set();
}
catch (ObjectDisposedException)
{
// 忽略已释放的事件
}
}
// 等待线程结束
Thread temperatureThread = null;
lock (_lockObject)
{
temperatureThread = _temperatureReceiveThread;
}
if (temperatureThread != null && temperatureThread.IsAlive)
{
temperatureThread.Join(1000); // 等待最多1秒
Log("温度接收线程已停止");
}
// 关闭TCP客户端和流
NetworkStream stream = null;
TcpClient client = null;
lock (_lockObject)
{
stream = _temperatureStream;
client = _temperatureTcpClient;
_temperatureStream = null;
_temperatureTcpClient = null;
}
if (stream != null)
{
try
{
stream.Close();
}
catch (Exception)
{}
}
if (client != null)
{
try
{
client.Close();
}
catch (Exception)
{}
}
}
catch (Exception ex)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 异常: {ex.Message}");
}
finally
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] StopTemperatureDataReceiving() - 执行完成");
}
}
/// <summary>
/// 使用TCP接收温度数据
/// </summary>
private void ReceiveTemperatureDataWithTcp()
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 开始执行");
try
{
// 创建TCP客户端并连接到设备的温度数据端口
_temperatureTcpClient = new TcpClient();
_temperatureTcpClient.ReceiveTimeout = 5000;
_temperatureTcpClient.SendTimeout = 5000;
IAsyncResult result = _temperatureTcpClient.BeginConnect(_deviceIp, TEMPERATURE_TCP_PORT, null, null);
bool connected = result.AsyncWaitHandle.WaitOne(3000, true);
if (!connected || !_temperatureTcpClient.Connected)
{
Log("温度数据TCP连接失败超时");
return;
}
_temperatureTcpClient.EndConnect(result);
Log("温度数据TCP连接成功");
// 获取网络流
_temperatureStream = _temperatureTcpClient.GetStream();
_temperatureStream.ReadTimeout = 5000;
byte[] buffer = new byte[8192]; // 温度数据缓冲区
List<byte> temperatureDataAccumulator = new List<byte>();
// 发送开始温度数据传输的命令
byte[] startCommand = Encoding.ASCII.GetBytes("start_temp_transfer\r\n");
_temperatureStream.Write(startCommand, 0, startCommand.Length);
_temperatureStream.Flush();
Log("已发送开始温度数据传输命令,开始接收温度数据");
while (!_stopTemperatureEvent.WaitOne(0))
{
try
{
// 检查连接状态
if (!_temperatureTcpClient.Connected)
{
Log("温度数据TCP连接已断开");
break;
}
// 读取数据
int bytesRead = _temperatureStream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
// 将读取的数据添加到累积器
byte[] receivedBytes = new byte[bytesRead];
Array.Copy(buffer, receivedBytes, bytesRead);
temperatureDataAccumulator.AddRange(receivedBytes);
// 处理累积的数据
ProcessReceivedTemperatureData(temperatureDataAccumulator);
}
}
catch (TimeoutException)
{
// 超时异常,继续尝试读取
Log("温度数据接收超时,继续尝试");
}
catch (IOException ex)
{
Log($"温度数据接收IO异常: {ex.Message}");
break;
}
catch (Exception ex)
{
Log($"温度数据接收异常: {ex.Message}");
// 非致命异常,继续尝试
}
}
}
catch (Exception ex)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 严重异常: {ex.Message}");
}
finally
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ReceiveTemperatureDataWithTcp() - 执行完成");
// 确保状态正确更新
lock (_lockObject)
{
_isReceivingTemperatureData = false;
}
// 清理资源
StopTemperatureDataReceiving();
}
}
/// <summary>
/// 处理接收到的温度数据
/// </summary>
/// <param name="dataAccumulator">累积的温度数据</param>
private void ProcessReceivedTemperatureData(List<byte> dataAccumulator)
{
const int TEMPERATURE_DATA_FRAME_SIZE = 256 * 192 * 2; // 假设分辨率为256x192每个温度值2字节
try
{
// 检查是否有足够的数据构成完整的温度数据帧
while (dataAccumulator.Count >= TEMPERATURE_DATA_FRAME_SIZE)
{
// 提取一帧温度数据
byte[] temperatureFrame = dataAccumulator.GetRange(0, TEMPERATURE_DATA_FRAME_SIZE).ToArray();
dataAccumulator.RemoveRange(0, TEMPERATURE_DATA_FRAME_SIZE);
// 获取温度补偿值
float compensationValue = GetTemperatureCompensationValue();
// 创建温度数据对象
TemperatureData temperatureData = new TemperatureData(temperatureFrame, compensationValue);
// 触发温度数据接收事件
OnTemperatureReceived(new TemperatureReceivedEventArgs(temperatureData, temperatureFrame, compensationValue));
}
}
catch (Exception ex)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] ProcessReceivedTemperatureData() - 异常: {ex.Message}");
// 清空累积器,重新开始
dataAccumulator.Clear();
}
}
/// <summary>
/// 触发温度数据接收事件
/// </summary>
/// <param name="e">事件参数</param>
protected virtual void OnTemperatureReceived(TemperatureReceivedEventArgs e)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 开始执行");
// 检查参数有效性
if (e == null)
{
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 参数为空,跳过事件触发");
return;
}
// 获取事件处理程序的快照,避免在多线程环境中出现竞态条件
EventHandler<TemperatureReceivedEventArgs> handler = TemperatureReceived;
// 检查是否有订阅者
if (handler != null)
{
// 获取所有订阅的委托,单独处理每个处理器
Delegate[] invocationList = handler.GetInvocationList();
foreach (Delegate d in invocationList)
{
try
{
// 安全地转换并调用每个处理器
EventHandler<TemperatureReceivedEventArgs> invoker = (EventHandler<TemperatureReceivedEventArgs>)d;
invoker(this, e);
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 成功触发一个事件处理器: {d.Method.Name}");
}
catch (Exception ex)
{
// 捕获单个事件处理器的异常,确保其他处理器仍能被调用
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 事件处理器异常: {ex.Message}");
}
}
}
Log($"[{DateTime.Now:HH:mm:ss.fff}] [线程:{Thread.CurrentThread.ManagedThreadId}] OnTemperatureReceived() - 执行完成");
}
#endregion
#region
/// <summary>
@@ -818,6 +1222,11 @@ namespace JoyD.Windows.CS.Toprie
/// 图像数据接收事件
/// </summary>
public event EventHandler<ImageReceivedEventArgs> ImageReceived;
/// <summary>
/// 温度数据接收事件
/// </summary>
public event EventHandler<TemperatureReceivedEventArgs> TemperatureReceived;
#endregion
@@ -1669,6 +2078,9 @@ namespace JoyD.Windows.CS.Toprie
{
_isReceivingImages = false;
}
// 同步停止温度数据接收
StopTemperatureDataReceiving();
// 通知线程停止
ManualResetEvent stopEvent = null;
@@ -2405,6 +2817,25 @@ namespace JoyD.Windows.CS.Toprie
set { _currentPaletteType = value; }
}
/// <summary>
/// 当前温度模式
/// </summary>
public TemperatureMode CurrentTemperatureMode { get; set; } = TemperatureMode.Celsius;
/// <summary>
/// 是否正在接收温度数据
/// </summary>
public bool IsReceivingTemperatureData
{
get
{
lock (_lockObject)
{
return _isReceivingTemperatureData;
}
}
}
/// <summary>
/// 获取或设置当前视频模式
/// </summary>
@@ -4663,5 +5094,295 @@ namespace JoyD.Windows.CS.Toprie
}
#endregion IDisposable
#region
/// <summary>
/// 温度数据事件参数类
/// </summary>
public class TemperatureReceivedEventArgs : EventArgs
{
/// <summary>
/// 温度数据对象
/// </summary>
public TemperatureData TemperatureData { get; private set; }
/// <summary>
/// 原始温度数据字节数组
/// </summary>
public byte[] RawData { get; private set; }
/// <summary>
/// 温度补偿值
/// </summary>
public float CompensationValue { get; private set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="temperatureData">温度数据对象</param>
/// <param name="rawData">原始温度数据</param>
/// <param name="compensationValue">温度补偿值</param>
public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue)
{
TemperatureData = temperatureData;
RawData = rawData;
CompensationValue = compensationValue;
}
}
/// <summary>
/// 温度数据类,用于存储和处理温度数据
/// </summary>
public class TemperatureData
{
/// <summary>
/// 温度数据数组
/// </summary>
public float[,] Data { get; private set; }
/// <summary>
/// 温度数据的宽度(像素)
/// </summary>
public int Width { get; private set; }
/// <summary>
/// 温度数据的高度(像素)
/// </summary>
public int Height { get; private set; }
/// <summary>
/// 温度补偿值
/// </summary>
public float CompensationValue { get; private set; }
/// <summary>
/// 最大温度值
/// </summary>
public float MaxTemperature { get; private set; }
/// <summary>
/// 最小温度值
/// </summary>
public float MinTemperature { get; private set; }
/// <summary>
/// 平均温度值
/// </summary>
public float AverageTemperature { get; private set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="rawData">原始温度数据字节数组</param>
/// <param name="compensationValue">温度补偿值</param>
public TemperatureData(byte[] rawData, float compensationValue)
{
// 假设分辨率为256x192
Width = 256;
Height = 192;
CompensationValue = compensationValue;
// 初始化温度数据数组
Data = new float[Height, Width];
// 解析原始数据
ParseRawData(rawData);
// 计算温度统计信息
CalculateStatistics();
}
/// <summary>
/// 解析原始温度数据
/// </summary>
/// <param name="rawData">原始温度数据字节数组</param>
private void ParseRawData(byte[] rawData)
{
try
{
// 假设每个温度值由2字节表示
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
int index = (i * Width + j) * 2;
if (index + 1 < rawData.Length)
{
// 读取2字节数据并转换为温度值
short rawTempValue = (short)((rawData[index + 1] << 8) | rawData[index]);
// 转换为实际温度值(假设温度值为原始值除以某个系数)
// 这里使用一个示例转换公式,实际转换方式需要根据设备的数据格式确定
float temperature = rawTempValue / 100.0f + CompensationValue;
Data[i, j] = temperature;
}
}
}
}
catch (Exception ex)
{
// 记录异常但不抛出,确保即使解析出错也能继续执行
Console.WriteLine($"解析温度数据异常: {ex.Message}");
}
}
/// <summary>
/// 计算温度统计信息
/// </summary>
private void CalculateStatistics()
{
if (Data == null || Data.Length == 0)
{
MaxTemperature = MinTemperature = AverageTemperature = 0.0f;
return;
}
float sum = 0.0f;
MaxTemperature = float.MinValue;
MinTemperature = float.MaxValue;
int validCount = 0;
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
float temp = Data[i, j];
// 跳过无效温度值
if (!float.IsNaN(temp) && !float.IsInfinity(temp))
{
sum += temp;
MaxTemperature = Math.Max(MaxTemperature, temp);
MinTemperature = Math.Min(MinTemperature, temp);
validCount++;
}
}
}
// 计算平均温度
AverageTemperature = validCount > 0 ? sum / validCount : 0.0f;
}
/// <summary>
/// 获取指定区域的温度数据
/// </summary>
/// <param name="x">区域左上角X坐标</param>
/// <param name="y">区域左上角Y坐标</param>
/// <param name="width">区域宽度</param>
/// <param name="height">区域高度</param>
/// <returns>区域温度数据如果参数无效则返回null</returns>
public TemperatureData GetRegionData(int x, int y, int width, int height)
{
// 验证参数
if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
x + width > Width || y + height > Height)
{
return null;
}
// 创建区域温度数据数组
float[,] regionData = new float[height, width];
// 复制区域数据
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
regionData[i, j] = Data[y + i, x + j];
}
}
// 创建新的温度数据对象
TemperatureData result = new TemperatureData();
result.Width = width;
result.Height = height;
result.CompensationValue = CompensationValue;
result.Data = regionData;
result.CalculateStatistics();
return result;
}
/// <summary>
/// 获取指定坐标的温度值(摄氏度)
/// </summary>
/// <param name="x">X坐标</param>
/// <param name="y">Y坐标</param>
/// <returns>温度值如果坐标无效则返回NaN</returns>
public float GetTemperatureAt(int x, int y)
{
if (x < 0 || x >= Width || y < 0 || y >= Height)
{
return float.NaN;
}
return Data[y, x];
}
/// <summary>
/// 将温度数据转换为指定的温度模式
/// </summary>
/// <param name="mode">目标温度模式</param>
/// <returns>转换后的温度数据副本</returns>
public TemperatureData ConvertTo(TemperatureMode mode)
{
// 创建新的温度数据对象
TemperatureData result = new TemperatureData();
result.Width = Width;
result.Height = Height;
result.CompensationValue = CompensationValue;
result.Data = new float[Height, Width];
// 根据目标模式进行转换
switch (mode)
{
case TemperatureMode.Celsius:
// 如果当前已经是摄氏度,直接复制数据
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
result.Data[i, j] = Data[i, j];
}
}
break;
case TemperatureMode.Fahrenheit:
// 摄氏度转华氏度: F = C * 9/5 + 32
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
result.Data[i, j] = Data[i, j] * 9.0f / 5.0f + 32.0f;
}
}
break;
case TemperatureMode.Kelvin:
// 摄氏度转开尔文: K = C + 273.15
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
result.Data[i, j] = Data[i, j] + 273.15f;
}
}
break;
}
// 重新计算统计信息
result.CalculateStatistics();
return result;
}
/// <summary>
/// 私有构造函数,用于内部创建
/// </summary>
private TemperatureData()
{}
}
#endregion
}
}

View File

@@ -0,0 +1,319 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Toprie
{
/// <summary>
/// 温度数据模型类,用于存储和处理红外热像仪采集的温度数据
/// </summary>
public class TemperatureData
{
/// <summary>
/// 温度数据矩阵
/// 格式: [行][列]
/// </summary>
public float[,] TemperatureMatrix { get; private set; }
/// <summary>
/// 温度数据的宽度(列数)
/// </summary>
public int Width { get; private set; }
/// <summary>
/// 温度数据的高度(行数)
/// </summary>
public int Height { get; private set; }
/// <summary>
/// 温度采集时间戳
/// </summary>
public DateTime Timestamp { get; set; }
/// <summary>
/// 最低温度值
/// </summary>
public float MinTemperature { get; private set; }
/// <summary>
/// 最高温度值
/// </summary>
public float MaxTemperature { get; private set; }
/// <summary>
/// 平均温度值
/// </summary>
public float AverageTemperature { get; private set; }
/// <summary>
/// 根据原始数据创建温度数据实例
/// </summary>
/// <param name="rawData">原始温度数据每个温度点为2字节</param>
/// <param name="width">温度矩阵宽度</param>
/// <param name="height">温度矩阵高度</param>
/// <param name="compensationValue">温度补偿值从sdk_get_comp_temp获取</param>
public TemperatureData(byte[] rawData, int width, int height, float compensationValue = 0)
{
if (rawData == null)
throw new ArgumentNullException(nameof(rawData));
if (width <= 0 || height <= 0)
throw new ArgumentException("宽度和高度必须大于0");
Width = width;
Height = height;
TemperatureMatrix = new float[height, width];
Timestamp = DateTime.Now;
ParseRawData(rawData, compensationValue);
CalculateStatistics();
}
/// <summary>
/// 解析原始温度数据
/// </summary>
/// <param name="rawData">原始温度数据</param>
/// <param name="compensationValue">温度补偿值</param>
private void ParseRawData(byte[] rawData, float compensationValue)
{
// 按照SDK文档温度数据为每个点2字节摄氏温度=(H*256+L)/10
// 需要考虑数据分布逻辑:先发送第一行奇数列,再发送第一行偶数列,接着第二行奇数列,依此类推
int dataIndex = 0;
// 处理奇数列
for (int row = 0; row < Height; row++)
{
for (int col = 0; col < Width; col += 2)
{
if (dataIndex + 1 < rawData.Length)
{
// 按照SDK文档计算温度值摄氏温度=(H*256+L)/10
// 这里假设H是高位字节L是低位字节
int highByte = rawData[dataIndex];
int lowByte = rawData[dataIndex + 1];
float temperature = (highByte * 256 + lowByte) / 10.0f;
// 应用温度补偿值
temperature += compensationValue;
TemperatureMatrix[row, col] = temperature;
dataIndex += 2;
}
}
}
// 处理偶数列
dataIndex = 0; // 重置索引,重新遍历
for (int row = 0; row < Height; row++)
{
for (int col = 1; col < Width; col += 2)
{
if (dataIndex + 1 < rawData.Length)
{
int highByte = rawData[dataIndex];
int lowByte = rawData[dataIndex + 1];
float temperature = (highByte * 256 + lowByte) / 10.0f;
// 应用温度补偿值
temperature += compensationValue;
TemperatureMatrix[row, col] = temperature;
dataIndex += 2;
}
}
}
}
/// <summary>
/// 计算温度统计信息
/// </summary>
private void CalculateStatistics()
{
float sum = 0;
float min = float.MaxValue;
float max = float.MinValue;
int count = 0;
for (int row = 0; row < Height; row++)
{
for (int col = 0; col < Width; col++)
{
float temp = TemperatureMatrix[row, col];
sum += temp;
min = Math.Min(min, temp);
max = Math.Max(max, temp);
count++;
}
}
MinTemperature = min;
MaxTemperature = max;
AverageTemperature = count > 0 ? sum / count : 0;
}
/// <summary>
/// 获取指定区域内的温度统计信息
/// </summary>
/// <param name="startRow">起始行</param>
/// <param name="startCol">起始列</param>
/// <param name="endRow">结束行</param>
/// <param name="endCol">结束列</param>
/// <returns>区域温度统计信息</returns>
public RegionTemperatureStats GetRegionStatistics(int startRow, int startCol, int endRow, int endCol)
{
// 参数验证和边界检查
startRow = Math.Max(0, startRow);
startCol = Math.Max(0, startCol);
endRow = Math.Min(Height - 1, endRow);
endCol = Math.Min(Width - 1, endCol);
if (startRow > endRow || startCol > endCol)
return new RegionTemperatureStats(0, 0, 0, 0);
float sum = 0;
float min = float.MaxValue;
float max = float.MinValue;
int count = 0;
for (int row = startRow; row <= endRow; row++)
{
for (int col = startCol; col <= endCol; col++)
{
float temp = TemperatureMatrix[row, col];
sum += temp;
min = Math.Min(min, temp);
max = Math.Max(max, temp);
count++;
}
}
float avg = count > 0 ? sum / count : 0;
return new RegionTemperatureStats(min, max, avg, count);
}
/// <summary>
/// 将温度矩阵转换为字节数组(用于保存或传输)
/// </summary>
/// <returns>温度数据的字节数组表示</returns>
public byte[] ToByteArray()
{
// 创建一个包含所有必要信息的字节数组
// 包括宽度、高度、时间戳和温度数据
int headerSize = 4 + 4 + 8; // width(4) + height(4) + timestamp(8)
int dataSize = Width * Height * 4; // 每个温度值使用4字节float
byte[] result = new byte[headerSize + dataSize];
// 写入头信息
Buffer.BlockCopy(BitConverter.GetBytes(Width), 0, result, 0, 4);
Buffer.BlockCopy(BitConverter.GetBytes(Height), 0, result, 4, 4);
Buffer.BlockCopy(BitConverter.GetBytes(Timestamp.Ticks), 0, result, 8, 8);
// 写入温度数据
int dataIndex = headerSize;
for (int row = 0; row < Height; row++)
{
for (int col = 0; col < Width; col++)
{
byte[] tempBytes = BitConverter.GetBytes(TemperatureMatrix[row, col]);
Buffer.BlockCopy(tempBytes, 0, result, dataIndex, 4);
dataIndex += 4;
}
}
return result;
}
/// <summary>
/// 从字节数组创建TemperatureData实例
/// </summary>
/// <param name="data">包含温度数据的字节数组</param>
/// <returns>TemperatureData实例</returns>
public static TemperatureData FromByteArray(byte[] data)
{
if (data == null || data.Length < 16) // 至少需要头信息的长度
throw new ArgumentException("无效的数据格式");
int width = BitConverter.ToInt32(data, 0);
int height = BitConverter.ToInt32(data, 4);
long ticks = BitConverter.ToInt64(data, 8);
DateTime timestamp = new DateTime(ticks);
// 验证数据完整性
int expectedSize = 16 + width * height * 4;
if (data.Length != expectedSize)
throw new ArgumentException("数据长度不匹配");
// 创建温度矩阵
float[,] matrix = new float[height, width];
int dataIndex = 16;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
matrix[row, col] = BitConverter.ToSingle(data, dataIndex);
dataIndex += 4;
}
}
// 创建TemperatureData实例
TemperatureData tempData = new TemperatureData();
tempData.Width = width;
tempData.Height = height;
tempData.TemperatureMatrix = matrix;
tempData.Timestamp = timestamp;
tempData.CalculateStatistics();
return tempData;
}
/// <summary>
/// 私有构造函数用于FromByteArray方法
/// </summary>
private TemperatureData()
{ }
}
/// <summary>
/// 区域温度统计信息
/// </summary>
public struct RegionTemperatureStats
{
/// <summary>
/// 区域最低温度
/// </summary>
public float MinTemperature { get; }
/// <summary>
/// 区域最高温度
/// </summary>
public float MaxTemperature { get; }
/// <summary>
/// 区域平均温度
/// </summary>
public float AverageTemperature { get; }
/// <summary>
/// 统计的温度点数量
/// </summary>
public int PointCount { get; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="minTemp">最低温度</param>
/// <param name="maxTemp">最高温度</param>
/// <param name="avgTemp">平均温度</param>
/// <param name="count">温度点数量</param>
public RegionTemperatureStats(float minTemp, float maxTemp, float avgTemp, int count)
{
MinTemperature = minTemp;
MaxTemperature = maxTemp;
AverageTemperature = avgTemp;
PointCount = count;
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Toprie
{
/// <summary>
/// 温度数据接收事件参数类
/// 用于在接收到温度数据时传递相关信息
/// </summary>
public class TemperatureReceivedEventArgs : EventArgs
{
/// <summary>
/// 温度数据对象
/// </summary>
public TemperatureData TemperatureData { get; private set; }
/// <summary>
/// 原始温度数据(可选,用于调试或特殊处理)
/// </summary>
public byte[] RawData { get; private set; }
/// <summary>
/// 温度补偿值
/// </summary>
public float CompensationValue { get; private set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="temperatureData">解析后的温度数据对象</param>
public TemperatureReceivedEventArgs(TemperatureData temperatureData)
{
TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData));
RawData = null;
CompensationValue = 0;
}
/// <summary>
/// 构造函数(包含原始数据和补偿值)
/// </summary>
/// <param name="temperatureData">解析后的温度数据对象</param>
/// <param name="rawData">原始温度数据</param>
/// <param name="compensationValue">温度补偿值</param>
public TemperatureReceivedEventArgs(TemperatureData temperatureData, byte[] rawData, float compensationValue)
{
TemperatureData = temperatureData ?? throw new ArgumentNullException(nameof(temperatureData));
RawData = rawData;
CompensationValue = compensationValue;
}
/// <summary>
/// 获取温度统计摘要信息
/// </summary>
public string GetStatisticsSummary()
{
return $"温度统计 - 最低: {TemperatureData.MinTemperature:F2}°C, " +
$"最高: {TemperatureData.MaxTemperature:F2}°C, " +
$"平均: {TemperatureData.AverageTemperature:F2}°C, " +
$"数据点: {TemperatureData.Width}x{TemperatureData.Height} ({TemperatureData.Width * TemperatureData.Height}), " +
$"采集时间: {TemperatureData.Timestamp:yyyy-MM-dd HH:mm:ss.fff}";
}
}
}

View File

@@ -73,6 +73,8 @@
<Compile Include="DeviceManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SharedStructures.cs" />
<Compile Include="TemperatureData.cs" />
<Compile Include="TemperatureReceivedEventArgs.cs" />
<Compile Include="UdpCommunicationManager.cs" />
<Compile Include="V8.cs" />
</ItemGroup>