傅里叶变换(FT):
F
(
ω
)
=
F
[
f
(
t
)
]
=
∫
−
∞
+
∞
f
(
t
)
e
−
j
ω
t
d
t
F(\omega)=F[f(t)]=\int_{-\infty}^{+\infty}f(t)e^{-j\omega t}dt
F(ω)=F[f(t)]=∫−∞+∞f(t)e−jωtdt
离散傅里叶变换(DFT):
X
(
k
)
=
∑
0
N
−
1
x
(
n
)
W
N
k
n
(
k
=
0
,
1
,
2
,
3
⋯
N
−
1
)
X(k)=\sum_0^{N-1}x(n)W_N^{kn} \quad (k=0,1,2,3\cdots N-1)
X(k)=0∑N−1x(n)WNkn(k=0,1,2,3⋯N−1)
其中
W
N
k
n
=
e
−
j
2
π
N
k
n
W_N^{kn}=e^{-j\frac{2\pi}{N}kn}
WNkn=e−jN2πkn,称为旋转因子。
\quad FFT是基于DFT的一种算法,将长序列的DFT分解为短序列的DFT,利用旋转因子的周期性、对称性、可约性,减少了重复运算。
对于一个多项式
A
(
x
)
=
∑
0
n
−
1
a
i
x
i
=
a
0
+
a
1
x
+
a
2
x
2
+
⋯
+
a
n
−
1
x
n
−
1
A(x)=\sum_0^{n-1}a_ix^i=a_0+a_1x+a_2x^2+\cdots +a_{n-1}x^{n-1}
A(x)=0∑n−1aixi=a0+a1x+a2x2+⋯+an−1xn−1
按照下标的奇偶性把A(x)分成两部分
A
(
x
)
=
(
a
0
+
a
2
x
2
+
a
4
x
4
+
⋯
+
a
n
−
2
x
n
−
2
)
+
(
a
1
x
+
a
3
x
3
+
a
5
x
5
+
a
n
−
1
x
n
−
1
)
=
(
a
0
+
a
2
x
2
+
a
4
x
4
+
⋯
+
a
n
−
2
x
n
−
2
)
+
x
(
a
1
+
a
3
x
2
+
a
5
x
4
+
a
n
−
1
x
n
−
2
)
A(x)=(a_0+a_2x^2+a_4x^4+\cdots+a_{n-2}x^{n-2})+(a_1x+a_3x^3+a_5x^5+a_{n-1}x^{n-1}) \\ \quad\quad\; =(a_0+a_2x^2+a_4x^4+\cdots+a_{n-2}x^{n-2})+x(a_1+a_3x^2+a_5x^4+a_{n-1}x^{n-2})
A(x)=(a0+a2x2+a4x4+⋯+an−2xn−2)+(a1x+a3x3+a5x5+an−1xn−1)=(a0+a2x2+a4x4+⋯+an−2xn−2)+x(a1+a3x2+a5x4+an−1xn−2)
发现奇偶部分结构相同,系数存在差异。
对于DFT来说:
X
(
k
)
=
∑
n
为偶数
x
(
n
)
W
N
k
n
+
∑
n
为奇数
x
(
n
)
W
N
k
n
=
∑
l
=
0
N
/
2
−
1
x
(
2
l
)
W
N
k
2
l
+
∑
l
=
0
N
/
2
−
1
x
(
2
l
+
1
)
W
N
k
(
2
l
+
1
)
X(k)=\sum_{n为偶数}x(n)W_N^{kn}+\sum_{n为奇数}x(n)W_N^{kn}\\ =\sum_{l=0}^{N/2-1}x(2l)W_N^{k2l}+\sum_{l=0}^{N/2-1}x(2l+1)W_N^{k(2l+1)}
X(k)=n为偶数∑x(n)WNkn+n为奇数∑x(n)WNkn=l=0∑N/2−1x(2l)WNk2l+l=0∑N/2−1x(2l+1)WNk(2l+1)
令
x
1
(
l
)
=
x
(
2
l
)
,
x
2
(
l
)
=
x
(
2
l
+
1
)
x_1(l)=x(2l),x_2(l)=x(2l+1)
x1(l)=x(2l),x2(l)=x(2l+1),注意根据可约性有
W
N
2
k
l
=
W
N
/
2
k
l
W_N^{2kl}=W_{N/2}^{kl}
WN2kl=WN/2kl
那么
X
(
k
)
=
∑
l
=
0
N
/
2
−
1
x
1
(
l
)
W
N
/
2
k
l
+
W
N
k
∑
l
=
0
N
/
2
−
1
x
2
(
l
)
W
N
/
2
k
l
X(k)=\sum_{l=0}^{N/2-1}x_1(l)W_{N/2}^{kl}+W_N^k\sum_{l=0}^{N/2-1}x_2(l)W_{N/2}^{kl}
X(k)=l=0∑N/2−1x1(l)WN/2kl+WNkl=0∑N/2−1x2(l)WN/2kl
便于表示
X
1
(
k
)
=
∑
l
=
0
N
/
2
−
1
x
1
(
l
)
W
N
/
2
k
l
X
2
(
k
)
=
∑
l
=
0
N
/
2
−
1
x
2
(
l
)
W
N
/
2
k
l
X_1(k)=\sum_{l=0}^{N/2-1}x_1(l)W_{N/2}^{kl}\\ X_2(k)=\sum_{l=0}^{N/2-1}x_2(l)W_{N/2}^{kl}
X1(k)=l=0∑N/2−1x1(l)WN/2klX2(k)=l=0∑N/2−1x2(l)WN/2kl
均以N/2为周期
利用旋转因子对称性
W
N
m
+
N
/
2
=
−
W
N
m
\quad W_N^{m+N/2}=-W_N^{m}
WNm+N/2=−WNm
当
k
=
0
,
1
,
2
,
⋯
,
N
2
−
1
k=0,1,2,\cdots,\frac{N}{2}-1
k=0,1,2,⋯,2N−1时:
X
(
k
)
=
X
1
(
k
)
+
W
N
k
X
2
(
k
)
X
(
k
+
N
2
)
=
X
1
(
k
+
N
2
)
+
W
N
k
+
N
/
2
X
2
(
k
+
N
2
)
=
X
1
(
k
)
−
W
N
k
X
2
(
k
)
X(k)=X_1(k)+W_N^kX_2(k)\\ X(k+\frac{N}{2})=X_1(k+\frac{N}{2})+W_N^{k+N/2}X_2(k+\frac{N}{2})=X_1(k)-W_N^kX_2(k)
X(k)=X1(k)+WNkX2(k)X(k+2N)=X1(k+2N)+WNk+N/2X2(k+2N)=X1(k)−WNkX2(k)
可以看到,只需要一半的数据即可获得整个序列的离散傅里叶变换。
基础的,可以通过递归分治的方法计算DFT;进阶的,通过递归发现规律,优化成蝶形算法进行计算。
下面先介绍递归法
因为涉及复数的运算,所以可以先设计一个复数类。
复数类应该包含复数的实部和虚部,重载运算符,使其支持加减法、乘法和求模运算。
class Complex{//复数类
public:
Complex(double re=0,double im=0):real{re},image{im}{
}
Complex(const Complex&cp):real{cp.real},image{cp.image}{
}
Complex operator +(const Complex cp){
return Complex(real+cp.real,image+cp.image);
}
Complex operator -(const Complex cp){
return Complex(real-cp.real,image-cp.image);
}
Complex operator *(const Complex cp){
double re=real*cp.real-image*cp.image;
double im=image*cp.real+real*cp.image;
return Complex(re,im);
}
double model(){
return sqrt(real*real+image*image);
}
double real=0;
double image=0;
};
定义两个复数类数组,resource代表数据源,result代表对resource按照奇偶区分的数组。
void Page_Tool::fftIterate(Complex *resource, Complex *result, int n)
{
if(n>1) { //迭代结束标志
for(int i=0; i<n; i+=2) {
result[i/2]=resource[i];
result[i/2+n/2]=resource[i+1];
}
fftIterate( result,resource,n/2);
fftIterate( result+n/2,resource,n/2 );
for(int i=0;i<n/2;i++) {
Complex omega(cos(2*PI*i/double(n)),-sin(2*PI*i/double(n)));
Complex temp=omega*result[i+n/2];
resource[i]=result[i]+temp;
resource[i+n/2]=result[i]-temp;
}
}
}
验证代码,设置采样点数N=32768,采样频率Fs=32768,给定两个不同频率和幅值的正弦波,进行傅里叶变换,查看结果。注意,这里的分辨率为N/Fs=1Hz,波形频率分量不满足该分辨率时会存在频率泄露现象。最后的结果需要进行频谱变换才能代表实际的频率及幅值。
void Page_Tool::on_pushButton_2_clicked()
{
//一些画图的代码不用管
ui->widget_1->m_plot->clearGraphs();
ui->widget_2->m_plot->clearGraphs();
ui->widget_1->addGraph();
ui->widget_2->addGraph();
int N=32768;//采样点数
double Fs=32768;//采样频率
double W1=500;//波形1频率
double W2=10000;//波形2频率
Complex resource[N],result[N];
for(int k=0; k<N; k++) {
resource[k]=Complex(20*sin(2*PI*W1*k/Fs)+100*sin(2*PI*W2*k/Fs),0);//两个正弦波合成信号
}
for(int i=0;i<N;i++){
ui->widget_1->m_plot->graph(0)->addData(i/Fs,resource[i].real);
}
fftIterate(resource,result,N);//验证fft代码
for(int i=0;i<N/2+1;i++){
ui->widget_2->m_plot->graph(0)->addData(i*Fs/N,resource[i].model()*2/N);
}
ui->widget_1->m_plot->replot();
ui->widget_2->m_plot->replot();
}
结果:

可以看到频率500Hz、幅值20的正弦波和频率10000HZ、幅值100的正弦波都被表示出来了。
原理大家可以搜一搜,这里给出参考代码。效果和上面是一样的。原始数据要组成2的整数倍,不满足的可以补0。
void Page_Tool::fftButterFly(Complex *resource, Complex *result, int n)
{
int M=int(log2(n));
for(int i=0;i<n;i++){
int k=0;
for(int j=0;j<M;j++){
if(((i>>j)&1)==1){
k+=1<<(M-j-1);
}
}
result[k]=resource[i];//取二进制倒码
}
for(int L=1;L<=M;L++){
int B=int(pow(2,L-1));//间隔
int k=int(pow(2,M-L));//增量
for(int i=0;i<k;i++){//蝶形运算的次数
for(int j=0;j<B;j++){//每个蝶形运算的乘法次数
int index=j+2*B*i;//数组下标
int p=j*k;
Complex omega(cos(2*PI*p/double(n)),-sin(2*PI*p/double(n)));
Complex temp=omega*result[index+B];
result[index+B]=result[index]-temp;
result[index]=result[index]+temp;
}
}
}
}
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
我目前有一个reddit克隆类型的网站。我正在尝试根据我的用户之前喜欢的帖子推荐帖子。看起来K最近邻或k均值是执行此操作的最佳方法。我似乎无法理解如何实际实现它。我看过一些数学公式(例如k表示维基百科页面),但它们对我来说并没有真正意义。有人可以推荐一些伪代码,或者可以查看的地方,以便我更好地了解如何执行此操作吗? 最佳答案 K最近邻(又名KNN)是一种分类算法。基本上,您采用包含N个项目的训练组并对它们进行分类。如何对它们进行分类完全取决于您的数据,以及您认为该数据的重要分类特征是什么。在您的示例中,这可能是帖子类别、谁发布了该项
有没有办法快速将表格格式的ruby哈希打印到文件中?如:keyAkeyBkeyC...1232343451253474456...其中散列的值是不同大小的数组。还是使用双循环是唯一的方法?谢谢 最佳答案 试试我写的这个gem(在表中打印散列、ruby对象、ActiveRecord对象):http://github.com/arches/table_print 关于ruby-如何以表格格式快速打印Ruby哈希值?,我们在StackOverflow上找到一个类似的问题:
我查看了Stripedocumentationonerrors,但我仍然无法正确处理/重定向这些错误。基本上无论发生什么,我都希望他们返回到edit操作(通过edit_profile_path)并向他们显示一条消息(无论成功与否)。我在edit操作上有一个表单,它可以POST到update操作。使用有效的信用卡可以正常工作(费用在Stripe仪表板中)。我正在使用Stripe.js。classExtrasController5000,#amountincents:currency=>"usd",:card=>token,:description=>current_user.email)