Math.Net——Fourier变换

        最近公司做一个实验与仿真协同平台的项目,采用的是BS/CS的一种混合式架构方案。最初我提案用Electron技术实现客户端,后来经过几轮讨论限于人力将该方案枪决了。最终,客户端采用基于开源项目CSharpBrowser实现。但项目迭代到第二轮,产品想要加入一些计算资源框架,来解决实验数据处理中的高等运算问题。你懂的,小项目组的一贯原则是首选免费开源框架,在千挑万选之下,Math.Net渐渐浮出水面,虽然这套框架的API和Demo目前尚缺,但是不失为一套有力的数值计算开源框架,限于晚上对于该框架的Fourier介绍较少,这里仅做一点补充。(简书的排版能力还是不行啊→_→!!!)

1. Fourier变换简介

        网络博客中关于连续/离散Fourier变换的文章已经非常详实,本无需赘述。但毕竟下文要用到,所以这里还要简明扼要的说一下。
        简单说,Fourier变换就是将周期信号沿正交基分解,而一组良好的正交基就是正弦/余弦函数。不过套用伟大的欧拉公式后,我们更多是把

作为正交基。基于此连续域上的Fourier变换及其逆变换可以写为

不过,对于归一化参数可以略作调整,从而将Fourier变换对写为

但是,对于计算机是无法处理连续变量的,从而在上述工作基础之上发展了离散Fourier变换(DFT),将其变换对写为
形式1

此即是Matlab做快速Fourier变换(FFT)的基础。但是同样的,我们可以对变换对的归一化参数,继而将DFT写为
形式2

以上只是扼要的介绍了Fourier变换。

2. Math.Net——C#开源数值计算框架

        说道数值计算,脑海中第一浮现的当然是Matlab/Octave这种高级语言,如果嫌弃它们安装麻烦,那么我们还有伟大的Python可用,就算再不济C/C++中也有很多相当不错的开源项目来支撑高效率的数值计算环境。所以C#当中的计算框架就显得弱鸡了一些。事实也证明,大多时候C#更适合客户端的表现和业务处理,鲜有用它去做计算类的东西。但是当真的遇到这种需求的时候,我其实还是更多的维护一个原则,那就是原生框架的效率优先于差异语言编译。
        C#当中Math.Net框架是一个相当不错开源工具包,但是相关的资料却不甚丰富,也缺乏深度。Math.Net能够支撑大部分数值计算处理,例如微分,积分,积分变换,线性代数计算,统计,信号处理,复变函数以及大规模稀疏矩阵的存储和并行等等问题。在语言方面能够兼顾C#和F#,同时支持一定程度的符号运算,并且符号运算的结果可以是Matlab展示形式,也可以直接Format成Latex样式。所以说Math.Net的综合能力还是令人为之一振的,敲起代码有一种Matlab/Mathematica/Maple任你摆布的感觉。

3. Math.Net——从复数(Complex)开始

        老实说,类似于C#/Java这些老牌业务型语言,在兼顾计算资源的时候,真的很难像Matlab等专业软件表现的那样优雅。例如创建一个复数

  Complex32 c = new Complex32(1f,2f);
  Console.WriteLine(c);//print (1,2)

如此可想而知,要创建一个复数序列是多麻烦的事情。但是在Matlab这种软件当中大可以优雅的多

>>c = 1+2j;

当然,优雅当不了饭吃,能用就是好滴。Math.Net中构造的复数,其实部和虚部只能是float类型,当然他也给出了许多复数的常规计算,例如

  Complex32 c = new Complex32(1f,2f);
  c.CommonLogarithm();\\取对数
  c.Conjugate();\\共轭
  var img = c.Imaginary;\\return 2
  var real = c.Real;\\return 1
  var magnitude = c.Magnitude;\\return 幅值
  var phase = c.Phase;\\return 相位

4. Fourier变换

        正常来说,Fourier变换是指对一个复数序列进行变换,如下例子

Complex32[] series = new Complex32[] 
{ 
  new Complex32(1, 2), 
  new Complex32(2, 1), 
  new Complex32(3, -2), 
  new Complex32(-1, 4) 
};
//print series  未经过FFT的samples序列
Fourier.Forward(series);//Fast Fourier变换
//Fourier.Forward(series, FourierOptions.Default);上一行等同于该行
//print series  已被FFT的spectrum序列
Fourier.Inverse(series);//Fast Fourier逆变换
//print series  已被逆变换的spectrum序列

Math.Net中采用的是内部运算,所以当执行Fourier变换之后,结果装入原有序列,其中值得关注的是,当FourierOptions采用Default值时,FFT遵循的是我们在第一部分讨论的形式2FFT,而如果想得到与Matlab运算相同的结果可以将FourierOptions修改为FourierOptions.Matlab,即

Fourier.Forward(series, FourierOptions.Matlab)

但是现实中,我们的实际信号采用往往是一个实数序列,而不是上述的复数序列。其实Forward方法还有很多其他的重载,这里我们不妨提供一个实现实序列Fourier变换的思路

double[] RealSamples = new double[100];//构造采样信号
double[] ImgSamples = new double[RealSamples .Length];//辅助虚部
Random r = new Random();
for(int i = 0; i<RealSamples.Length;i++)
{
  RealSamples[i] = r.NextDouble()*10-5;//随机噪声信号
  ImgSamples[i] = 0;
}
Fourier.Forward(RealSamples , ImgSamples, FourierOptions.Matlab );
double[] result = new double[RealSamples.Length];//结果序列
for(int i = 0; i<RealSamples.Length;i++)
{
  Complex32 temp = new Complex32(RealSamples[i],ImgSamples [i]);
  result[i] = temp.Magnitude();//从计算结果中检出结果序列
}

大家看到了,上面过程中使用了一个全部为0的虚数列来补足信号的采样序列,从而来完成Fourier变换过程。但是显然我们为这样一个API付出的太多了,有没有更简洁的办法呢,答案当然是有的

int N = 512;
 Fourier.ForwardReal(NewRealSamples,N);
//这里NewRealSamples是对RealSamples重新构造的一个实序列

是不是瞬间简洁多了,不过这里面API对RealSamples要求是如果RealSamples.Length是偶数,那么NewRealSample.Length就要是RealSamples.Length+2的,而如果RealSamples.Length是奇数,那么NewRealSample.Length就等于RealSamples.Length+1;那么你可能会问为什么是这个样子的?另外,这里为什么无缘无故多出来一个整数N?其实这些问题就牵扯出了另外一个话题——DFT计算流,限于篇幅和主题,本人计划以后再去讨论。这里值得一提的是,FFT 的结果数据长度等于采样信号序列的长度,但由于FFT计算结果的对称性,其实真正的结果是结果数组中的前N/2或(N+1)/2个元素。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容