• 两个移相算法


    方法一: 积分移项
    这个移项是不是90度, 不太好说. 得到的幅值会变大,需要缩小. 而且还有相位逐渐下移的趋势. 下移的原因未知.也未深入探索, 因计算量比较大, 也没采用顾抛弃掉.

    private double[] 积分移相90( List<float> sindata)
    {
    	 double[] cosdata = new double[sindata.Count];
    	 double s = 0;
    	 for (int i = 0; i < sindata.Count; i++)
    	 {
    	      var d = sindata[i];
    	      s += sindata[i];
    	      cosdata[i] =s; 
    	 }
    	 return cosdata;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    方法二: 索引移相位
    利用数字计算机的下标索引, 将数值提前或者移后1/4
    第一步,先测量出,两个正弦波峰值之间数据的个数 N.
    第二步,将下标索引 前移1/4 或者后移 3/4.

    /*
     检测波峰测量周期宽度 代码比较简单,速度也比较快,  如果是程序生成的波形, 比较容易测量两个波峰的数值.  如果是ADC转换测量得到的数据. 测量峰值比较麻烦.  . .  经过测试,此测量峰值求脉宽算法只对完美的正弦波比较适用. 对于有点干扰杂波的不太适用, 会陷入局部最小宽度. 不建议使用, 使用过零点检测脉宽更合适.
    */
    private void 检测波峰测量周期宽度(List<float> sindata,out double width_count, out double avg_max_data)
    {
     //求索引的个数
     double pre = double.MinValue;
     double max = double.MinValue;
     int maxIndex = 0;
     //int preIndex = 0;
     List<int> 波峰Index = new List<int>();
     List<double> maxs = new List<double>();
    
     //上升或下降次数
     int upcount = 0;
     int downcount = 0;
     for (int i = 1; i < sindata.Count; i++)
     {
         if (sindata[i] > sindata[i-1]  )
         {
             upcount++;
    
             max = sindata[i];
             maxIndex = i;
    
             //连续10个以上的,上升视为真正的上升
             if (upcount > 10)
             { 
                 downcount = 0;
             } 
         }
         //连续下降2次的视为真正的下降
         else if ( sindata[i] < sindata[i - 1])
         {
             downcount ++; 
             //下降了10个数, 视为真正的下降,防止波形干扰.
             if (downcount == 10 )
             {
                 //说明开始走下降趋势,那么认为 max 中的值便是真的波峰值.
                 波峰Index.Add(maxIndex);
                 maxs.Add(max);
    
                 max = double.MinValue;
                 maxIndex = 0; 
                 upcount = 0;
    
                 if (波峰Index.Count >= 10)
                 {
                     break;
                 }
             }
    
         }
     }
    
     var juli = new List<int>();
     for (int i = 1; i < 波峰Index.Count; i++)
     { 
         juli.Add(波峰Index[i] - 波峰Index[i - 1]);
     }
    
    
     width_count = juli.Average();
     avg_max_data = maxs.Average();
     return;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    检测过零点测量周期宽度

    /// 检测过零点测量周期宽度, 要求数据必须无直流分量.否则无效.
    /// 
    ///  
    private double 检测过零点测量周期宽度(List<float> sindata )
    {
        //求索引的个数 
        List<int> 过零点Index = new List<int>();  
        //上升或下降次数 
        for (int i = 1; i < sindata.Count; i++)
        {
            if (sindata[i -1] <= 0 &&  sindata[i]>=0)
            { 
                过零点Index.Add(i);
                if (过零点Index.Count >= 10)
                {
                    break;
                }
            } 
        }
    
        var juli = new List<int>();
        for (int i = 1; i < 过零点Index.Count; i++)
        {
            juli.Add(过零点Index[i] - 过零点Index[i - 1]);
        }
    
    
        var width_count = juli.Average(); 
        return width_count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    索引实现移相的使用方法.

     //去掉参考信号的直流部分
    //取前面10000个数据,求平均值,平均值约等于直流分量,
    //完美的去直流方案,建议通过在电路中串联一个合适的电容.起到隔直通交的作用.
    var sinAvg = Sin_data.Take(10000).Average();
    for (int i = 0; i < LN; i++)
    { 
        Sin_data[i] = Sin_data[i] - sinAvg;
    }
    
    //2.移相90度
    //2.1 移项先计算两个波峰之间的数据的个数.
    //2.2 知道了每个波峰之间数据的个数, 再把索引提前1/4 就是移项90度.
     
     //var cos_data = 积分移相90度(Sin_data);
     double width_count =  检测过零点测量周期宽度(Sin_data);
    
     //360度往前移相位1/4是90度. 往后移3/4是270度也是90度,也是同一个相位. 为了程序更容易运行,减少一个判断. 无法取未来的数据, 可以改成取历史的数据
     //所以从第270个相位的数据, 开始, 一般情况下. 数据很多的, 不在乎这点数据.
     var his270index = (int) width_count / 4  *  3;
     //var N90 = this.trackBar1.Value;  
    
     for (int i = his270index; i < LN; i++)
     { 
         //this.chartMathNet.Series[0].Points.AddXY(i, GD_data[i]);
         //this.chartMathNet.Series[1].Points.AddXY(i, A_data[i]);
         this.chartMathNet.Series[2].Points.AddXY(i, Sin_data[i]); //显示
         this.chartMathNet.Series[0].Points.AddXY(i, Sin_data[i - his270index]); //移相90度后的数据显示
         
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    经过测试, 更改索引实现移项的算法还是比较快速和稳定的.建议使用过零检测算法.
    在这里插入图片描述

  • 相关阅读:
    MCE | 曲贝替定——来自海洋的抗软组织肿瘤化合物
    2195. 深海机器人问题(网络流,费用流,上下界可行流,网格图模型)
    STM32H5开发(5)----串口打印配置
    【python版CV】- 银行卡号识别项目
    Spring 通过注解来存储和读取对象
    聊聊零拷贝技术原理和应用
    [Codeforces] number theory (R1200) Part.8
    WPF不弹出控件的情况下,将控件内容生成截图
    LightDB中的存储过程(五)
    中小企业数字化转型的痛点分析
  • 原文地址:https://blog.csdn.net/phker/article/details/126084806