using IStation.Model;
|
using MathNet.Numerics;
|
using MathNet.Numerics.Interpolation;
|
using MathNet.Numerics.LinearRegression;
|
using MathNet.Numerics.Statistics;
|
using System.Data;
|
using System.Text;
|
namespace IStation.Test
|
{
|
internal class Program
|
{
|
|
//// 过滤无效数据
|
//// 1输模型修正
|
//// 2输数据修正
|
//// 修正组合偏差
|
//static void Main(string[] args)
|
//{
|
// Station2Helper.Start();
|
// Console.WriteLine();
|
// Console.WriteLine();
|
// Console.WriteLine("ok");
|
// Console.ReadKey();
|
//}
|
|
|
// 过滤无效数据
|
// 1输模型修正
|
// 2输数据修正
|
// 修正组合偏差
|
static void Main(string[] args)
|
{
|
var splineList = new List<CurvePoint>();
|
var measuredList = new List<CurvePoint>();
|
|
var path = AppDomain.CurrentDomain.BaseDirectory;
|
var lienPaht = path + @"\pumpcsv\23_34_old_curve.csv";
|
var measuredPath = path + @"\pumpcsv\23_34.csv";
|
|
using (var fs = new FileStream(lienPaht, FileMode.Open, FileAccess.Read))
|
using (var sr = new StreamReader(fs, Encoding.UTF8))
|
{
|
var strLine = string.Empty;
|
sr.ReadLine();
|
while (!string.IsNullOrEmpty(strLine = sr.ReadLine()))
|
{
|
var strList = strLine.Split(',');
|
var x = double.Parse(strList[0]);
|
var y = double.Parse(strList[1]);
|
splineList.Add(new CurvePoint(x, y));
|
}
|
}
|
|
using (var fs = new FileStream(measuredPath, FileMode.Open, FileAccess.Read))
|
using (var sr = new StreamReader(fs, Encoding.UTF8))
|
{
|
var strLine = string.Empty;
|
sr.ReadLine();
|
while (!string.IsNullOrEmpty(strLine = sr.ReadLine()))
|
{
|
var strList = strLine.Split(',');
|
var x = double.Parse(strList[4]);
|
var y = double.Parse(strList[5]);
|
measuredList.Add(new CurvePoint(x, y));
|
}
|
}
|
|
|
// 样条曲线处理
|
double[] splineX = splineList.Select(x => x.X).ToArray();
|
double[] splineY = splineList.Select(x => x.Y).ToArray();
|
|
// 实测数据处理
|
double[] measuredXAll = measuredList.Select(x => x.X).ToArray();
|
double[] measuredYAll = measuredList.Select(x => x.Y).ToArray();
|
|
|
// 基于稳健回归的异常值检测
|
// 使用 MathNet 进行线性回归
|
(double A, double B) = SimpleRegression.Fit(measuredXAll, measuredYAll);
|
double intercept = A;
|
double slope = B;
|
|
// 计算预测值
|
double[] predictedY = new double[measuredXAll.Length];
|
for (int i = 0; i < measuredXAll.Length; i++)
|
{
|
predictedY[i] = slope * measuredXAll[i] + intercept;
|
}
|
|
// 计算残差
|
double[] residuals = new double[measuredYAll.Length];
|
for (int i = 0; i < measuredYAll.Length; i++)
|
{
|
residuals[i] = measuredYAll[i] - predictedY[i];
|
}
|
|
// 使用改进的异常值过滤策略(Z-Score)
|
double[] zScores = new ZScore(residuals).Scores;
|
bool[] validMask = new bool[zScores.Length];
|
double zScoreThreshold = Config.Z_SCORE_THRESHOLD; // 假设 Config 是一个配置类
|
|
for (int i = 0; i < zScores.Length; i++)
|
{
|
validMask[i] = Math.Abs(zScores[i]) < zScoreThreshold;
|
}
|
|
// 过滤掉异常值
|
double[] measuredXValid = new double[validMask.Length];
|
double[] measuredYValid = new double[validMask.Length];
|
int validCount = 0;
|
|
for (int i = 0; i < validMask.Length; i++)
|
{
|
if (validMask[i])
|
{
|
measuredXValid[validCount] = measuredXAll[i];
|
measuredYValid[validCount] = measuredYAll[i];
|
validCount++;
|
}
|
}
|
|
// 截断数组到有效长度
|
Array.Resize(ref measuredXValid, validCount);
|
Array.Resize(ref measuredYValid, validCount);
|
|
// 此处可以继续处理 measuredXValid 和 measuredYValid
|
Console.WriteLine("有效数据点数量: " + validCount);
|
|
var dataFusion = new DataFusionKimi(splineX, splineY, measuredXValid, measuredYValid, 3, 500);
|
(double[] mergedX, double[] mergedY, double[] optimizedX, double[] optimizedY) = dataFusion.ProcessData();
|
|
Console.WriteLine($"{splineX.Min()},{splineX.Max()}");
|
Console.WriteLine($"{mergedX.Min()},{mergedX.Max()}");
|
Console.WriteLine($"{optimizedX.Min()},{optimizedX.Max()}");
|
|
Console.WriteLine($"{splineY.Min()},{splineY.Max()}");
|
Console.WriteLine($"{mergedY.Min()},{mergedY.Max()}");
|
Console.WriteLine($"{optimizedY.Min()},{optimizedY.Max()}");
|
|
var pt_list=new List<CurvePoint>();
|
for (int i = 0; i < optimizedX.Length; i++)
|
{
|
var x = optimizedX[i];
|
var y = optimizedY[i];
|
pt_list.Add(new CurvePoint(x,y));
|
}
|
var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "pumpcsv");
|
CsvHelper.ExportToCsv(pt_list, Path.Combine(fullPath, $"{23_34}_c.csv"));
|
|
Console.WriteLine("ok");
|
|
Console.WriteLine("ok");
|
Console.ReadKey();
|
}
|
|
|
}
|
|
|
|
|
// 配置类(假设)
|
public static class Config
|
{
|
public const double Z_SCORE_THRESHOLD = 2.5;
|
public const double TRANSITION_WIDTH = 500.0;
|
}
|
|
// Z-Score 计算辅助类
|
public class ZScore
|
{
|
private readonly double[] _data;
|
private readonly double _mean;
|
private readonly double _stdDev;
|
|
public ZScore(double[] data)
|
{
|
_data = data;
|
_mean = data.Mean();
|
_stdDev = data.StandardDeviation();
|
}
|
|
public double[] Scores
|
{
|
get
|
{
|
double[] scores = new double[_data.Length];
|
for (int i = 0; i < _data.Length; i++)
|
{
|
scores[i] = (_data[i] - _mean) / _stdDev;
|
}
|
return scores;
|
}
|
}
|
}
|
|
|
public class DataFusion
|
{
|
private double[] splineX;
|
private double[] splineY;
|
private double[] measuredXValid;
|
private double[] measuredYValid;
|
private int polyDegree;
|
private double transitionWidth;
|
|
public DataFusion(double[] splineX, double[] splineY, double[] measuredXValid, double[] measuredYValid, int polyDegree, double transitionWidth)
|
{
|
this.splineX = splineX;
|
this.splineY = splineY;
|
this.measuredXValid = measuredXValid;
|
this.measuredYValid = measuredYValid;
|
this.polyDegree = polyDegree;
|
this.transitionWidth = transitionWidth;
|
}
|
|
public (double[] mergedX, double[] mergedY) ProcessData()
|
{
|
// 多项式拟合实测数据
|
double[] polyCoeff = Fit.Polynomial(measuredXValid, measuredYValid, polyDegree);
|
Polynomial polyFunc = new Polynomial(polyCoeff);
|
|
// 初始化融合曲线
|
double[] mergedX = SortAndUnique(
|
splineX.Concat(
|
Enumerable.Range(0, 200).Select(i => measuredXValid.Min() + i * (measuredXValid.Max() - measuredXValid.Min()) / 199.0).ToArray()
|
).ToArray()
|
);
|
|
var interpolator = LinearSpline.InterpolateSorted(splineX, splineY);
|
double[] mergedY = mergedX.Select(x => interpolator.Interpolate(x)).ToArray();
|
|
// 核心区域修正
|
bool[] coreMask = mergedX.Select(x => x >= measuredXValid.Min() && x <= measuredXValid.Max()).ToArray();
|
for (int i = 0; i < mergedX.Length; i++)
|
{
|
if (coreMask[i])
|
{
|
mergedY[i] = polyFunc.Evaluate(mergedX[i]);
|
}
|
}
|
|
// 动态过渡处理
|
ApplyTransition(
|
transitionRange: (measuredXValid.Min() - transitionWidth, measuredXValid.Min()),
|
baseFunc: CreateSplinePolynomial(),
|
targetFunc: polyFunc,
|
mergedX: mergedX,
|
mergedY: mergedY
|
);
|
|
ApplyTransition(
|
transitionRange: (measuredXValid.Max(), measuredXValid.Max() + transitionWidth),
|
baseFunc: polyFunc,
|
targetFunc: polyFunc,
|
mergedX: mergedX,
|
mergedY: mergedY
|
);
|
|
return (mergedX, mergedY);
|
}
|
|
private void ApplyTransition(
|
(double start, double end) transitionRange,
|
Polynomial baseFunc,
|
Polynomial targetFunc,
|
double[] mergedX,
|
double[] mergedY
|
)
|
{
|
double start = transitionRange.start;
|
double end = transitionRange.end;
|
|
bool[] transitionMask = mergedX.Select(x => x >= start && x <= end).ToArray();
|
double[] transitionX = mergedX.Where((x, i) => transitionMask[i]).ToArray();
|
|
if (transitionX.Length == 0)
|
{
|
return;
|
}
|
|
// 计算混合权重
|
double[] weights = transitionX.Select(x => (x - start) / (end - start)).ToArray();
|
|
for (int i = 0; i < mergedX.Length; i++)
|
{
|
if (transitionMask[i])
|
{
|
double x = mergedX[i];
|
double weight = weights[i];
|
mergedY[i] = (1 - weight) * baseFunc.Evaluate(x) + weight * targetFunc.Evaluate(x);
|
}
|
}
|
}
|
|
private Polynomial CreateSplinePolynomial()
|
{
|
double[] polyCoeff = Fit.Polynomial(splineX, splineY, polyDegree);
|
return new Polynomial(polyCoeff);
|
}
|
|
private double[] SortAndUnique(double[] array)
|
{
|
Array.Sort(array);
|
return array.Distinct().ToArray();
|
}
|
}
|
|
|
|
|
|
|
}
|