两个移相算法

这篇博客介绍了两种数字信号处理中实现90度相位移位的方法:积分移项和索引移位。积分移项通过对数据累加实现相位变化,而索引移位则通过计算波峰间周期并调整索引来完成。文章提供了具体的代码示例,并推荐使用过零点检测的索引移位算法,因为它在实际应用中表现稳定且快速。
摘要由CSDN通过智能技术生成

方法一: 积分移项
这个移项是不是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/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;
}

检测过零点测量周期宽度

/// 检测过零点测量周期宽度, 要求数据必须无直流分量.否则无效.
/// </summary>
/// <param name="sindata"></param> 
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;
}

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

 //去掉参考信号的直流部分
//取前面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度后的数据显示
     
 }

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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值