Files
NoBuilding/建材不燃性试验炉/BalanceChartWindow.xaml.cs
2026-02-02 16:18:52 +08:00

380 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using OxyPlot;
using OxyPlot.Series;
using OxyPlot.Axes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
namespace jiancaiburanxing
{
public partial class BalanceChartWindow : Window
{
// 温度获取函数
private Func<double> _getFurnaceTemperature;
// 定时器
private DispatcherTimer _updateTimer;
private const int COLLECTION_DURATION = 600; // 10分钟
// 已运行时间
private int _elapsedSeconds = 0;
// 目标温度
private const double TARGET_TEMPERATURE = 750.0;
private const double TOLERANCE = 5.0;
// 数据存储
private List<DataPoint> temperatureData = new List<DataPoint>();
// PlotModel
private PlotModel plotModel;
public BalanceChartWindow(Func<double> getFurnaceTemperature)
{
InitializeComponent();
_getFurnaceTemperature = getFurnaceTemperature;
// 初始化图表
InitializePlot();
}
private void InitializePlot()
{
plotModel = new PlotModel
{
Title = "温度波动曲线",
TitleFontSize = 16,
TitleFontWeight = OxyPlot.FontWeights.Bold,
PlotAreaBorderColor = OxyColors.LightGray,
PlotAreaBorderThickness = new OxyThickness(1)
};
// 设置背景色
plotModel.Background = OxyColors.White;
plotModel.PlotAreaBackground = OxyColors.White;
// X轴时间轴- 更关注近期的波动
var timeAxis = new LinearAxis
{
Position = AxisPosition.Bottom,
Title = "时间 (秒)",
TitleFontSize = 12,
AxislineColor = OxyColors.Black,
MinorGridlineColor = OxyColor.FromArgb(40, 200, 200, 200),
MajorGridlineColor = OxyColor.FromArgb(80, 150, 150, 150),
//Minimum = 0,
//Maximum = 300, // 初始5分钟更关注短期波动
//MajorStep = 60,
//MinorStep = 10
Minimum = 0,
Maximum = 600, // 改为10分钟
MajorStep = 60, // 每分钟一个主刻度
MinorStep = 10 // 每10秒一个次刻度
};
// Y轴温度轴- 重点显示750±20°C范围
var tempAxis = new LinearAxis
{
Position = AxisPosition.Left,
Title = "温度 (°C)",
TitleFontSize = 12,
AxislineColor = OxyColors.Black,
MinorGridlineColor = OxyColor.FromArgb(40, 200, 200, 200),
MajorGridlineColor = OxyColor.FromArgb(80, 150, 150, 150),
Minimum = 730, // 750-20
Maximum = 770, // 750+20
MajorStep = 10,
MinorStep = 2 // 更细的网格,便于观察波动
};
// 添加坐标轴
plotModel.Axes.Add(timeAxis);
plotModel.Axes.Add(tempAxis);
// 1. 先添加目标区域(作为背景)
var targetArea = new AreaSeries
{
Color = OxyColor.FromArgb(30, 76, 175, 80), // 浅绿色区域
Fill = OxyColor.FromArgb(30, 76, 175, 80),
StrokeThickness = 0
};
// 设置目标区域范围
targetArea.Points.Add(new DataPoint(0, TARGET_TEMPERATURE + TOLERANCE));
targetArea.Points.Add(new DataPoint(10000, TARGET_TEMPERATURE + TOLERANCE)); // 足够大的X值
targetArea.Points2.Add(new DataPoint(0, TARGET_TEMPERATURE - TOLERANCE));
targetArea.Points2.Add(new DataPoint(10000, TARGET_TEMPERATURE - TOLERANCE));
// 2. 添加目标线
var targetLine = new LineSeries
{
Color = OxyColors.Green,
StrokeThickness = 1.5,
LineStyle = LineStyle.Dash
};
targetLine.Points.Add(new DataPoint(0, TARGET_TEMPERATURE));
targetLine.Points.Add(new DataPoint(10000, TARGET_TEMPERATURE));
// 3. 添加温度曲线
var temperatureSeries = new LineSeries
{
Title = "炉内温度",
Color = OxyColors.Blue,
StrokeThickness = 2,
MarkerType = MarkerType.None, // 不要数据点标记,保持曲线简洁
CanTrackerInterpolatePoints = true // 允许鼠标悬停时显示插值点
};
// 添加到图表(注意顺序:背景在最下面)
plotModel.Series.Add(targetArea);
plotModel.Series.Add(targetLine);
plotModel.Series.Add(temperatureSeries);
// 绑定到PlotView
TemperaturePlot.Model = plotModel;
}
private void AddTemperatureData(double timeInSeconds, double temperature)
{
try
{
// 添加数据点
temperatureData.Add(new DataPoint(timeInSeconds, temperature));
// 更新图表
UpdateChart();
// 更新统计信息
UpdateStatistics();
}
catch (Exception ex)
{
Console.WriteLine($"添加数据时出错: {ex.Message}");
}
}
private void UpdateChart()
{
if (plotModel == null || temperatureData.Count == 0)
return;
// 获取温度曲线系列
var temperatureSeries = plotModel.Series[2] as LineSeries;
if (temperatureSeries == null)
return;
// 更新数据点限制最多显示1000个点避免性能问题
temperatureSeries.Points.Clear();
if (temperatureData.Count <= 1000)
{
// 数据量少,显示所有点
foreach (var point in temperatureData)
{
temperatureSeries.Points.Add(point);
}
}
else
{
// 数据量大只显示最近1000个点
var recentData = temperatureData.Skip(temperatureData.Count - 1000);
foreach (var point in recentData)
{
temperatureSeries.Points.Add(point);
}
}
// 自动调整X轴范围显示最近的数据
//var xAxis = plotModel.Axes[0] as LinearAxis;
//if (xAxis != null && temperatureData.Count > 0)
//{
// double maxTime = temperatureData.Last().X;
// // 保持显示最近300秒的数据
// xAxis.Minimum = Math.Max(0, maxTime - 300);
// xAxis.Maximum = Math.Max(300, maxTime);
//}
// 刷新图表
plotModel.InvalidatePlot(true);
}
private void StartDataCollection()
{
try
{
// 清空数据
temperatureData.Clear();
_elapsedSeconds = 0;
// 更新显示
txtElapsedTime.Text = "0秒";
UpdateStatistics();
// 初始化定时器
_updateTimer = new DispatcherTimer();
_updateTimer.Interval = TimeSpan.FromSeconds(1);
_updateTimer.Tick += UpdateTimer_Tick;
// 添加初始数据点
AddInitialDataPoint();
// 启动定时器
_updateTimer.Start();
}
catch (Exception ex)
{
MessageBox.Show($"启动数据收集失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void UpdateTimer_Tick(object sender, EventArgs e)
{
if (_elapsedSeconds >= COLLECTION_DURATION)
{
_updateTimer?.Stop();
return;
}
try
{
// 更新时间
_elapsedSeconds++;
txtElapsedTime.Text = $"{_elapsedSeconds}秒";
// 获取当前温度
if (_getFurnaceTemperature != null)
{
double currentTemp = _getFurnaceTemperature();
// 添加数据点即使温度为0也记录代表没有数据
AddTemperatureData(_elapsedSeconds, currentTemp);
}
}
catch (Exception ex)
{
Console.WriteLine($"定时器更新失败: {ex.Message}");
}
}
private void AddInitialDataPoint()
{
try
{
if (_getFurnaceTemperature != null)
{
double initialTemp = _getFurnaceTemperature();
AddTemperatureData(0, initialTemp);
}
}
catch (Exception ex)
{
Console.WriteLine($"添加初始数据点失败: {ex.Message}");
}
}
private void UpdateStatistics()
{
if (temperatureData == null || temperatureData.Count == 0)
{
ResetStatistics();
return;
}
try
{
// 获取当前温度(最后一个数据点)
double currentTemp = temperatureData.Last().Y;
// 计算统计信息
double maxTemp = temperatureData.Max(p => p.Y);
double minTemp = temperatureData.Min(p => p.Y);
double difference = currentTemp - TARGET_TEMPERATURE;
// 更新显示
txtCurrentTemp.Text = $"{currentTemp:F1}°C";
txtMaxTemp.Text = $"{maxTemp:F1}°C";
txtMinTemp.Text = $"{minTemp:F1}°C";
txtDataPoints.Text = temperatureData.Count.ToString();
txtTempDifference.Text = $"{(difference >= 0 ? "+" : "")}{difference:F1}°C";
// 根据差值设置颜色
if (Math.Abs(difference) <= TOLERANCE)
{
txtTempDifference.Foreground = System.Windows.Media.Brushes.Green;
}
else if (Math.Abs(difference) <= TOLERANCE * 2)
{
txtTempDifference.Foreground = System.Windows.Media.Brushes.Orange;
}
else
{
txtTempDifference.Foreground = System.Windows.Media.Brushes.Red;
}
}
catch (Exception)
{
ResetStatistics();
}
}
private void ResetStatistics()
{
txtCurrentTemp.Text = "0°C";
txtMaxTemp.Text = "0°C";
txtMinTemp.Text = "0°C";
txtDataPoints.Text = "0";
txtTempDifference.Text = "0°C";
txtTempDifference.Foreground = System.Windows.Media.Brushes.Black;
}
#region
private void Window_Loaded(object sender, RoutedEventArgs e)
{
StartDataCollection();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
_updateTimer?.Stop();
_updateTimer = null;
}
private void btnClearData_Click(object sender, RoutedEventArgs e)
{
var result = MessageBox.Show("确定要清空所有数据吗?", "确认",
MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
// 停止定时器
_updateTimer?.Stop();
// 清空数据
temperatureData.Clear();
_elapsedSeconds = 0;
// 重置统计
ResetStatistics();
txtElapsedTime.Text = "0秒";
// 重新开始
_updateTimer?.Start();
}
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
_updateTimer?.Stop();
this.Close();
}
#endregion
}
}