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;
            }
        }








    }
}







posted @   古兴越  阅读(412)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 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
点击右上角即可分享
微信分享提示