用C#复刻Matlab中的希尔伯特变换(hilbert函数)

最新写一个信号处理的项目,需要使用到各种变换,如傅里叶变换(FFT)、加窗、希尔伯特变换(hilbert)等,其中傅里叶变换使用MathNet.Numerics类中的 Fourier.Forward完成。但是希尔伯特变换hilbert却没有现成的方法,网上找了很多,有说能实现的,但测试结果与matlab的完全不一致,于是产看matlab中的hilbert函数,用C#完全复刻了一个,测试结果与matlab中的一模一样。

计算思路:

(1)输入为一段信号数组x。

(2)对数组进行傅里叶变换(FFT)用Fourier.Forward完成。结果为复数数组complex。

(3)构造一个数组h,长度与x相同。这个是重点,这个数组如何构造看代码,里面有注释,至于这个数组h为啥要这样设计,是数学的问题,我也不懂,matlab中的hilbert源码里面就是这样构建的。

(4)傅里叶变换结果数组complex,乘以数组h。结果也是一个复数数组。这个数组怎么相乘?就是complex数组中的每个元素都乘以数组h中相对应位置的元素。这里又有个问题,复数如何乘以实数?其实也简单,就是复数中的实部和虚部都相乘即可,即a*(b+ci)=a*b+a*ci。

(5)对(4)中的结果复数数组,进行傅里叶逆变换,得到的复数数组即为希尔伯特变换(hilbert函数)的结果。

(6)根据需要对这个希尔伯特变换(hilbert函数)结果复数数组进行其他处理。

这个希尔伯特变换提供一个思路,之后的其他变换,加窗,或者滤波,就是先构造一个数组h,再乘以傅里叶变换结果数组了。思路很重要。

代码如下,这几天看matlab代码看得头疼,给我点鼓励吧。

using MathNet.Numerics;
using MathNet.Numerics.IntegralTransforms;
using System;

public static Complex32[]  hilbert(double[] x)
        {
          
            int L = x.Length;//信号数组长度
         
            Complex32[] complex = new MathNet.Numerics.Complex32[L];//将实数信号序列构造复数序列,实数的就是虚部为0的复数。
            for (int i = 0; i < L; i++)
            {
                complex[i] = new MathNet.Numerics.Complex32((float)x[i], 0);
            }
            Fourier.Forward(complex, FourierOptions.Matlab);  //傅里叶变换,结果与matalb的一致,用到这里输出这个complex就这完成傅里叶变换,complex[i].Real为实部, complex[i].Imaginary为虚部
           
            //构造序列h
            float[] h = new float[L];
            for (int i=0;i<h.Length;i++)//置空
            {
                h[i] = 0;
            }
            //h是否被2整除
            if (L % 2 == 0)//是
            {
                h[0] = 1;       //第一个为1
                h[L / 2] = 1;//中间后一个位置为1
                for (int i = 1; i <L / 2; i++)//第二个到中间位置前一个元素设置为 2
                {
                    h[i] = 2;
                }
            }
            else//否
            {
                h[0] = 1;//第一个为1
                for (int i=1;i<(L+1)/2;i++)//第二个到中间位置的元素设置为 2
                {
                    h[i] = 2;
                }
            }

            //对傅里叶变换结果乘以序列h,乘法运算,复数实部和虚部都要乘乘数
            for (int i = 0; i < complex.Length; i++)
            {
                float rel = complex[i].Real *h[i];//实部乘以序列h
                float img = complex[i].Imaginary * h[i];//虚部乘以序列h,
                complex[i] = new MathNet.Numerics.Complex32(rel, img);//相乘后的结果
            }
            Fourier.Inverse(complex, FourierOptions.Matlab);//逆傅里叶变换,完成希尔伯特变换,返回这个complex则完成希尔伯特变换,及matlab中的hilbert函数

            return complex;
//Complex32是表示一个复数,例有复数2+3!,建立复数表示为 Complex32 complex=new MathNet.Numerics.Complex32(2, 3); 从这个复数中取实部  float rel = complex.Real;复数中取虚部float img = complex[i].Imaginary
        }

以下是测试代码。

using MathNet.Numerics;
using System;

namespace WpfApp2
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : System.Windows.Window
    {
        public MainWindow()
        {
            InitializeComponent();

            double[] x = { 1, 2, 3, 4, 5, 6, 7, 8 };
            Complex32[] complex = MathUtils.hilbert(x);
            for(int i = 0; i < complex.Length; i++)
            {
                Console.WriteLine(complex[i]);
            }
        }
    }
}

matlab中是这样的

x=[1,2,3,4,5,6,7,8]
y=hilbert(x)

结果对比如图,结果完全一样

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值