C# 数据处理 相关算法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1.NewFolder1
{
public class Class1
{
// 滑动平均基数
// https://blog.csdn.net/hllerickson/article/details/107905844
private static int movAve = 8;
private double Smooth(Queue<double> movAveQueue, double ch)
{
double movAveTempData = 0;// 用于实时滑动平均处理
try
{
if (movAveQueue.Count < movAve)
{
movAveTempData = ch;
}
else
{
if (movAveQueue.Count > movAve)
{
while (movAveQueue.Count > movAve)
{
movAveQueue.Dequeue();
}
}
if (movAveQueue.Count == movAve)
{
movAveTempData = movAveQueue.Sum() / movAve;
}
}
return movAveTempData;
}
catch
{
movAveQueue.Clear();
return ch;
}
}
// 线性拟合平滑
// https://blog.csdn.net/qq_34773597/article/details/118495698
// 三点线性平滑
public static double[] linearSmooth3(double[] in_arr, int N)
{
double[] out_arr = new double[in_arr.Length];
int i; if (N < 3)
{
for (i = 0; i <= N - 1; i++) { out_arr[i] = in_arr[i]; }
}
else
{
out_arr[0] = (5.0 * in_arr[0] + 2.0 * in_arr[1] - in_arr[2]) / 6.0;
for (i = 1; i <= N - 2; i++) { out_arr[i] = (in_arr[i - 1] + in_arr[i] + in_arr[i + 1]) / 3.0; }
out_arr[N - 1] = (5.0 * in_arr[N - 1] + 2.0 * in_arr[N - 2] - in_arr[N - 3]) / 6.0;
}
return out_arr;
}
// 五点线性平滑
public static double[] linearSmooth5(double[] in_arr, int N)
{
double[] out_arr = new double[in_arr.Length];
int i; if (N < 5)
{
for (i = 0; i <= N - 1; i++) { out_arr[i] = in_arr[i]; }
}
else
{
out_arr[0] = (3.0 * in_arr[0] + 2.0 * in_arr[1] + in_arr[2] - in_arr[4]) / 5.0; out_arr[1] = (4.0 * in_arr[0] + 3.0 * in_arr[1] + 2 * in_arr[2] + in_arr[3]) / 10.0;
for (i = 2; i <= N - 3; i++)
{
out_arr[i] = (in_arr[i - 2] + in_arr[i - 1] + in_arr[i] + in_arr[i + 1] + in_arr[i + 2]) / 5.0;
}
out_arr[N - 2] = (4.0 * in_arr[N - 1] + 3.0 * in_arr[N - 2] + 2 * in_arr[N - 3] + in_arr[N - 4]) / 10.0;
out_arr[N - 1] = (3.0 * in_arr[N - 1] + 2.0 * in_arr[N - 2] + in_arr[N - 3] - in_arr[N - 5]) / 5.0;
}
return out_arr;
}
// 七点线性平滑
public static double[] linearSmooth7(double[] in_arr, int N)
{
double[] out_arr = new double[in_arr.Length];
int i; if (N < 7) { for (i = 0; i <= N - 1; i++) { out_arr[i] = in_arr[i]; } }
else
{
out_arr[0] = (13.0 * in_arr[0] + 10.0 * in_arr[1] + 7.0 * in_arr[2] + 4.0 * in_arr[3] + in_arr[4] - 2.0 * in_arr[5] - 5.0 * in_arr[6]) / 28.0;
out_arr[1] = (5.0 * in_arr[0] + 4.0 * in_arr[1] + 3 * in_arr[2] + 2 * in_arr[3] + in_arr[4] - in_arr[6]) / 14.0;
out_arr[2] = (7.0 * in_arr[0] + 6.0 * in_arr[1] + 5.0 * in_arr[2] + 4.0 * in_arr[3] + 3.0 * in_arr[4] + 2.0 * in_arr[5] + in_arr[6]) / 28.0;
for (i = 3; i <= N - 4; i++) { out_arr[i] = (in_arr[i - 3] + in_arr[i - 2] + in_arr[i - 1] + in_arr[i] + in_arr[i + 1] + in_arr[i + 2] + in_arr[i + 3]) / 7.0; }
out_arr[N - 3] = (7.0 * in_arr[N - 1] + 6.0 * in_arr[N - 2] + 5.0 * in_arr[N - 3] + 4.0 * in_arr[N - 4] + 3.0 * in_arr[N - 5] + 2.0 * in_arr[N - 6] + in_arr[N - 7]) / 28.0;
out_arr[N - 2] = (5.0 * in_arr[N - 1] + 4.0 * in_arr[N - 2] + 3.0 * in_arr[N - 3] + 2.0 * in_arr[N - 4] + in_arr[N - 5] - in_arr[N - 7]) / 14.0;
out_arr[N - 1] = (13.0 * in_arr[N - 1] + 10.0 * in_arr[N - 2] + 7.0 * in_arr[N - 3] + 4 * in_arr[N - 4] + in_arr[N - 5] - 2 * in_arr[N - 6] - 5 * in_arr[N - 7]) / 28.0;
}
return out_arr;
}
// 在此给出第一种边界条件下三次样条插值的C#算法实现
// https://blog.csdn.net/panjinliang066333/article/details/56682829
// 实现三次样条插值封装的类
public static class SplineMath
{
/// <summary>
/// 三次样条插值
/// </summary>
/// <param name="points">排序好的数</param>
/// <param name="xs">需要计算的插值点</param>
/// <param name="chf">写1</param>
/// <returns>返回计算好的数值</returns>
public static double[] SplineInsertPoint(PointClass[] points, double[] xs, int chf)
{
int plength = points.Length;
double[] h = new double[plength];
double[] f = new double[plength];
double[] l = new double[plength];
double[] v = new double[plength];
double[] g = new double[plength];
for (int i = 0; i < plength - 1; i++)
{
h[i] = points[i + 1].x - points[i].x;
f[i] = (points[i + 1].y - points[i].y) / h[i];
}
for (int i = 1; i < plength - 1; i++)
{
l[i] = h[i] / (h[i - 1] + h[i]);
v[i] = h[i - 1] / (h[i - 1] + h[i]);
g[i] = 3 * (l[i] * f[i - 1] + v[i] * f[i]);
}
double[] b = new double[plength];
double[] tem = new double[plength];
double[] m = new double[plength];
double f0 = (points[0].y - points[1].y) / (points[0].x - points[1].x);
double fn = (points[plength - 1].y - points[plength - 2].y) / (points[plength - 1].x - points[plength - 2].x);
b[1] = v[1] / 2;
for (int i = 2; i < plength - 2; i++)
{
b[i] = v[i] / (2 - b[i - 1] * l[i]);
}
tem[1] = g[1] / 2;
for (int i = 2; i < plength - 1; i++)
{
tem[i] = (g[i] - l[i] * tem[i - 1]) / (2 - l[i] * b[i - 1]);
}
m[plength - 2] = tem[plength - 2];
for (int i = plength - 3; i > 0; i--)
{
m[i] = tem[i] - b[i] * m[i + 1];
}
m[0] = 3 * f[0] / 2.0;
m[plength - 1] = fn;
int xlength = xs.Length;
double[] insertRes = new double[xlength];
for (int i = 0; i < xlength; i++)
{
int j = 0;
for (j = 0; j < plength; j++)
{
if (xs[i] < points[j].x)
break;
}
j = j - 1;
Console.WriteLine(j);
if (j == -1 || j == points.Length - 1)
{
if (j == -1)
throw new Exception("插值下边界超出");
if (j == points.Length - 1 && xs[i] == points[j].x)
insertRes[i] = points[j].y;
else
throw new Exception("插值下边界超出");
}
else
{
double p1;
p1 = (xs[i] - points[j + 1].x) / (points[j].x - points[j + 1].x);
p1 = p1 * p1;
double p2; p2 = (xs[i] - points[j].x) / (points[j + 1].x - points[j].x);
p2 = p2 * p2;
double p3; p3 = p1 * (1 + 2 * (xs[i] - points[j].x) / (points[j + 1].x - points[j].x)) * points[j].y + p2 * (1 + 2 * (xs[i] - points[j + 1].x) / (points[j].x - points[j + 1].x)) * points[j + 1].y;
double p4; p4 = p1 * (xs[i] - points[j].x) * m[j] + p2 * (xs[i] - points[j + 1].x) * m[j + 1];
p4 = p4 + p3;
insertRes[i] = p4;
}
}
return insertRes;
}
}
// 插值前需要对数据进行排序,需要使用PointClass类:
public class PointClass
{
public double x = 0;
public double y = 0;
public PointClass()
{
x = 0; y = 0;
}
// 写一个排序函数,使得输入的点按顺序排列,是因为插值算法的要求是,x轴递增有序的
public static PointClass[] DeSortX(PointClass[] points)
{
int length = points.Length;
double temx, temy;
for (int i = 0; i < length - 1; i++)
{
for (int j = 0; j < length - i - 1; j++)
if (points[j].x > points[j + 1].x)
{
temx = points[j + 1].x;
points[j + 1].x = points[j].x;
points[j].x = temx;
temy = points[j + 1].y;
points[j + 1].y = points[j].y;
points[j].y = temy;
}
}
return points;
}
}
// 具体实现
private void btnCalcSpline_Click()
{
double[] x = { -100, -90, -80, -70, -60, -50, -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
double[] y = { 9802, 7922, 6242, 4762, 3482, 2402, 1522, 842, 362, 82, 2, 122, 442, 962, 1682, 2602, 3722, 5142, 6562, 8282, 10202 };
PointClass[] points = new PointClass[x.Length];
for (int i = 0; i < x.Length; i++)
{
points[i] = new PointClass();
points[i].x = x[i];
points[i].y = y[i];
}
PointClass.DeSortX(points); //排序
double[] xs = { 0, 1, 80 };
double[] Y = SplineMath.SplineInsertPoint(points, xs, 1);
}
// 使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值)
// 本3σ法则仅局限于对正态或近似正态分布的样本数据处理,且适用于有较多组数据的时候。
// 这种判别处理原理及方法是以测量次数充分大为前提的,当测量次数的情形用准则剔除粗大误差是不够可靠的。
// 因此,在测量次数较少的情况下,最好不要选用准则,而用其他准则。
// http://www.javashuo.com/article/p-mralibpr-nv.html
// 定义电压-数量关系的类
public class VoltageCount
{
public Double Voltage { get; set; }
public int CountV { get; set; }
public VoltageCount()
{
}
public VoltageCount(Double voltage, int countV)
{
this.Voltage = voltage;
this.CountV = countV;
}
}
// 使用拉依达准则(3σ准则)剔除数据异常
public class ExceptionVoltageHelper
{
List<VoltageCount> listVoltageCount;
double average = 0.0;
int _badDataCount = -1;//奇异值个数
// 获取奇异值个数
public int BadDataCount
{
get { return _badDataCount; }
}
public ExceptionVoltageHelper(List<VoltageCount> list)
{
this.listVoltageCount = list;
SetAverage();
}
// 取得平均电压值
protected double GetAvgVoltage()
{
double avg = 0;
double total = 0;
int allCount = 0;
foreach (VoltageCount vc in listVoltageCount)
{
double v = vc.Voltage;
int c = vc.CountV;
total += v * c;
allCount += c;
}
avg = total / (allCount * 1.0);
return Math.Round(avg, 3, MidpointRounding.AwayFromZero);
}
// 平均值
void SetAverage()
{
this.average = GetAvgVoltage();
}
// 标准差
double StandardDeviation()
{
List<double> listDataV = new List<double>();
foreach (VoltageCount vc in this.listVoltageCount)
{
double v = vc.Voltage;
int countV = vc.CountV;
for (int i = 0; i < countV; i++)
{
listDataV.Add((v - this.average) * (v - this.average));
}
}
double sumDataV = listDataV.Sum();
double std = Math.Sqrt(sumDataV / (listDataV.Count - 1));
return std;
}
public List<VoltageCount> GetGoodList()
{
_badDataCount = 0;
double sd3 = StandardDeviation() * 3;//3倍标准差
List<VoltageCount> listVC = new List<VoltageCount>();
foreach (VoltageCount vc in this.listVoltageCount)
{
if (Math.Abs(vc.Voltage - this.average) <= sd3)
{
listVC.Add(vc);
}
else
{
_badDataCount += vc.CountV;
}
}
return listVC;
}
}
// C#零相位数字滤波器,改写自Matlab函数filtfilt
// http://www.360doc.com/content/22/0130/11/76720074_1015438776.shtml
public class DigitalFilter
{
private double[] b = new double[2];
private double[] a = new double[2];
private double[] x;
private double zi;
private double[] y = new double[1024];
private double[] zf = new double[1];
public DigitalFilter(double[] b, double[] a, double[] x, double zi)
{
this.b = b;
this.a = a;
this.x = x;
this.zi = zi;
}
private double[] getY()
{
calc();
return y;
}
private double[] getZf()
{
calc();
return zf;
}
private void calc()
{
for (int i = 0; i < y.Length; i++)
{
if (i == 0)
{
y[i] = b[0] * x[i] + zi;
}
else
{
y[i] = b[0] * x[i] + b[1] * x[i - 1] - a[1] * y[i - 1];
if (i == x.Length - 1)
{
zf[0] = y[i];
}
}
}
}
public double[] zeroFilter()
{
int len = x.Length; // length of input
int nb = b.Length;
int na = a.Length;
int nfilt = Math.Max(na, nb);
int nfact = 3 * (nfilt - 1); // length of edge transients
//运算初值
double data = 1 + a[1];
double zi;
zi = (b[1] - a[1] * b[0]) / data;
//首尾添数
double[] yTemp = new double[y.Length + 2 * nfact];
for (int i = 0; i < nfact; i++)
{
yTemp[i] = 2 * x[0] - x[nfact - i];
}
for (int i = nfact; i < y.Length + nfact; i++)
{
yTemp[i] = x[i - nfact];
}
for (int i = y.Length + nfact; i < yTemp.Length; i++)
{
yTemp[i] = 2 * x[x.Length - 1] - x[yTemp.Length - 2 - i + y.Length - nfact];
}
//正向滤波
this.zi = zi * yTemp[0];
yTemp = zeroCalc(yTemp);
//反序
yTemp = this.reverse(yTemp);
//反向滤波
this.zi = zi * yTemp[0];
yTemp = zeroCalc(yTemp);
//反序
yTemp = this.reverse(yTemp);
for (int i = 0; i < y.Length; i++)
{
y[i] = yTemp[i + nfact];
}
return y;
}
private double[] zeroCalc(double[] xx)
{
double[] yy = new double[xx.Length];
for (int i = 0; i < yy.Length; i++)
{
if (i == 0)
{
yy[i] = b[0] * xx[i] + zi;
}
else
{
yy[i] = b[0] * xx[i] + b[1] * xx[i - 1] - a[1] * yy[i - 1];
}
}
return yy;
}
private double[] reverse(double[] data)
{
double tmp;
for (int i = 0; i < data.Length / 2; i++)
{
tmp = data[data.Length - i - 1];
data[data.Length - i - 1] = data[i];
data[i] = tmp;
}
return data;
}
}
}
}
分类:
01 C#
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2019-07-18 Python 08 skimage
2018-07-18 EF ef 2
2018-07-18 EF AutoMaper