FFT和IFFT实现——分别用控制台和MFC实现

  这个学期学了《数字信号处理》,当中最重要的就是快速傅里叶变换(FFT)了,FFT发展到现在已经出现了好几种算法,他们各有优劣,我这里就不一一列出来,因为我不想搞的博客又臭又长。我这里的FFT是FFT-DIT(时域抽取法FFT),算法来自西安电子科技大学出版社的教材《数字信号处理》(高西全,丁美玉),这本书里面有对FFT-DIT适用于计算机算法的详细介绍,我这里也不讲具体算法,要想清楚我的程序为什么是这样子,请自己看教材里面的内容。软件是VS2008。

  这里接直接贴代码。先是用C++控制台的代码:

头文件:

  1 #include <complex>
  2 
  3 using namespace std;
  4 
  5 //蝶形变换
  6 complex<double> *bitRev(complex<double> *x ,int N)
  7 {
  8     complex<double> temp = 0;    //
  9     int n;            //normal index
 10     int r = 0;            //bit-reversed index
 11     int k;            //array 
 12 
 13     for(n = 0; n <= N-2;n++)
 14     {
 15         if( n < r)    //swap samples only for first half of the array
 16         {
 17             temp = x[n];
 18             x[n] = x[r];
 19             x[r] = temp;
 20         }
 21 
 22         k = N/2;    //even n: adds to the previous r
 23                     //odd n: subtract from the previous r      
 24 
 25         while( r>k || r==k)
 26         {
 27             r= r - k;    //keep subtracting reverse carry
 28             k = k/2;    //generated next reverse array
 29         }
 30 
 31         r = r + k;
 32     }
 33 
 34     return x;
 35 }
 36 
 37 //FFT 
 38 complex<double> *FFTdit(complex<double> *a,int N)
 39 {
 40     int t=2;
 41     int m,L = 1 ,L2 ,ir ,ib, it;
 42     complex<double> temp(0,0),j(0,1);
 43     complex<double> *x;
 44     complex<double> W(0,0);                    //twiddle factor
 45     complex<double> pi(3.1415926535898,0);  //define value of pi
 46     int nu;
 47 
 48 
 49     x = bitRev(a,N);
 50 
 51     nu = (int)(log((double)N)/log((double)t));
 52     
 53     for(m = 1; m <= nu; m++)
 54     {
 55         L = L*2;
 56 
 57         L2 = L/2;
 58 
 59         for(ir = 0; ir < L2; ir++)
 60         {
 61             W = exp(-j*(complex<double>)2*pi*(complex<double>)ir/(complex<double>)L);
 62             for(it = ir; it < N;it = it + L)
 63             {
 64                 ib = it + L2;
 65                 temp = x[ib] * W;    
 66                 x[ib] = x[it] - temp;
 67                 x[it] = x[it] + temp;        
 68             }    
 69         }        
 70     }
 71 
 72     return x;
 73 }
 74 
 75 //IFFT--inverse FFT
 76 complex<double> *IFFT(complex<double> *X,int N)
 77 {
 78     int m = (int)ceil(log((double)N)/log(2.0));
 79     int n = 1 << m;
 80     int i;
 81     complex<double> *tempx ;
 82     complex<double> *x = new complex<double>[n];
 83 
 84     for(i = 0; i < n; i++)
 85         X[i].imag(-imag(X[i]));
 86 
 87     tempx = FFTdit(X,n);
 88     
 89     for(i = 0; i < N; i++)
 90     {
 91         if((real<double>(tempx[i]))/n < 1e-14)            
 92             x[i].real(0);
 93         else
 94             x[i].real((real<double>(tempx[i]))/n);
 95 
 96         if((imag<double>(tempx[i]))/n < 1e-14)
 97             x[i].imag(0);
 98         else
 99             x[i].imag(-(imag<double>(tempx[i]))/n);
100     }
101 
102     return x;
103 }
View Code

测试文件:

 1 #include <iostream>
 2 #include "DIT_FFT.h"
 3 
 4 using namespace std;
 5 
 6 void main()
 7 {
 8     int i,N;
 9     complex<double> *p ,*x;
10     complex<double> a[16]={0,1,2,3,4,5,6,7,9,10,11,12,13,14,15};
11 
12     N = sizeof(a)/sizeof(complex<double>);
13 
14     p = FFTdit(a,N);
15 
16     cout << "经过FFT之后的排列:" << endl;
17     for(i = 0; i < N; i++)
18         cout << *(p+i) << endl;
19 
20     cout << "经过abs(FFT)之后的排列:" << endl;
21     for(i = 0; i < N; i++)
22         cout << abs(*(p+i))/(N/2) << endl;
23     
24     x = IFFT(p,N);
25     cout << "经过IFFT之后的排列:" << endl;
26     for(i = 0; i < N; i++)
27         cout << *(x+i) << endl;
28 
29     cout << "x取绝对值" << endl;
30     for(i = 0; i < N; i++)
31         cout << abs(*(x+i)) << endl;
32 
33     cout << endl << endl;
34     cout << "522/400 = ";
35     cout << (double)(522.0/400.0) << endl;
36 
37 }
View Code

  上面的内容可直接拷贝出来直接用,但是要注意我用的是VS2008。

  其实MFC的实现FFT和控制台的没什么不同,只是MFC要进行一些操作而已。

首先我想要在在对话框中用FFT进行信号的幅频分析显示,在对话框中加入Picture控件用于显示,再加入一个Button控件用于打开文件获取要分析的数据。然后利用类视图中选中

相应的类,比如我的是FFTDlg类右键添加函数,添加函数时没有的类型就自己手动添加。如下图:

 1 // FFT前的蝶形变换
 2 complex<double>* CFFTDlg::bitRev(complex<double>* x, int N)
 3 {
 4     complex<double> temp = 0;    //
 5     int n;            //normal index
 6     int r = 0;            //bit-reversed index
 7     int k;            //array 
 8     
 9     for(n = 0; n <= N-2;n++)
10     {
11         if( n < r)    //swap samples only for first half of the array
12         {
13             temp = x[n];
14             x[n] = x[r];
15             x[r] = temp;
16         }
17 
18         k = N/2;    //even n: adds to the previous r
19                     //odd n: subtract from the previous r      
20 
21         while( r>k || r==k)
22         {
23             r= r - k;    //keep subtracting reverse carry
24             k = k/2;    //generated next reverse array
25         }
26 
27         r = r + k;
28     }
29 
30     return x;
31 }
View Code
 1 // FFT-DIT变换
 2 complex<double>* CFFTDlg::FFTdit(complex<double>* a, int N)
 3 {
 4     int t=2;
 5     int m,L = 1 ,L2 ,ir ,ib, it;
 6     complex<double> temp(0,0),j(0,1);
 7     complex<double> *x;
 8     complex<double> W(0,0);                    //twiddle factor
 9     complex<double> pi(3.1415926535898,0);  //define value of pi
10     int nu;
11 
12     x = bitRev(a,N);
13 
14     nu = (int)(log((double)N)/log((double)t));
15     
16     for(m = 1; m <= nu; m++)
17     {
18         L = L*2;
19 
20         L2 = L/2;
21 
22         for(ir = 0; ir < L2; ir++)
23         {
24             W = exp(-j*(complex<double>)2*pi*(complex<double>)ir/(complex<double>)L);
25             for(it = ir; it < N;it = it + L)
26             {
27                 ib = it + L2;
28                 temp = x[ib] * W;    
29                 x[ib] = x[it] - temp;
30                 x[it] = x[it] + temp;        
31             }    
32         }        
33     }
34 
35     return x;
36 }
View Code

头文件所需:

 1 #include <complex>
 2 
 3 using namespace std;
 4 
 5 
 6 
 7 
 8 
 9 
10 complex<double> *cydata;
11 complex<double> *dataFFT;
View Code

下面对Button控件添加消息处理函数:

 1 void CFFTDlg::OnBnClickedButtonInputfile()
 2 {
 3     // TODO: 在此添加控件通知处理程序代码
 4     CFileDialog dlg(TRUE); // 定义一个文件对话框变量
 5     if(dlg.DoModal()==IDOK)    
 6     { 
 7     //成功打开文件时先销毁链表,再获取链表
 8         xdata.clearList();
 9         ydata.clearList();
10 //取得文件路径及文件名
11         CString m_FilePath = dlg.GetPathName(); 
12         CStdioFile File; 
13 //以读模式打开文本文件
14         File.Open(m_FilePath,CFile::modeRead); 
15         CString FileData;        //定义一个CString变量作为缓冲区
16         File.ReadString(FileData);//读取第一行数据,第一行数据为坐标点数据
17 //字符数组,如果出现"TempStr2 was corrupted",这时要把TempStr2的内存再改大一些 
18         char TempStr1[20]; 
19         char TempStr2[20]; 
20 
21         memset(TempStr1,'\0',10); 
22         memset(TempStr2,'\0',10); 
23         sscanf(FileData,"%s",TempStr1); 
24         m_PointNum = atoi(TempStr1);   // 获取坐标点个数
25 //初始化cydata
26         cydata = new complex<double>[m_PointNum];
27 //逐行读取坐标数据     
28         for (int i = 0;i<m_PointNum;i++) 
29         { 
30             File.ReadString(FileData); 
31             sscanf(FileData,"%s %s",TempStr1,TempStr2); 
32             if(i < m_PointNum/2)
33                 xdata.insertAt(i,atof(TempStr1));
34             //ydata.insertAt(i,atof(TempStr2));
35             *(cydata+i) = atof(TempStr2);
36         } 
37 //进行FFT变化
38         dataFFT =  FFTdit(cydata,m_PointNum);
39 
40         for(int i = 0;i <m_PointNum/2; i++)
41         {
42             ydata.insertAt(i,abs(*(dataFFT+i))/(m_PointNum/2));
43         }
44 //删除内存
45         delete cydata;
46    } 
47 }
View Code

其中,xdata和 ydata为我自己写的模板类arrayListType,这个类的模板也是从我之前上课练习的控制台代码拿出来的,因为我里面有添加一些我需要的函数。这里也贴出来,不完善,但是能用,不会报错。

  1 #include <cassert>
  2 //#include <iostream>
  3 
  4 //using namespace std;
  5 
  6 template<class elemType>
  7 class arrayListType
  8 {
  9 public:
 10     const arrayListType<elemType>&
 11                     operator=(const arrayListType<elemType>&);
 12         //Overload the assigment operator
 13 
 14     bool isEmpty();
 15         //Function to determine whether the list is empty
 16         //Postcondition:Return true if the list is empty;
 17         //                otherwise,returns false.
 18 
 19     bool isFull();
 20         //Function to determine whether the list is full.
 21         //Postcondition:Return true if the list is empty
 22         //                otherwise,return false.
 23 
 24     int listSize();
 25         //Function to determine the number of elements in
 26         //the list.
 27         //Postcondition:Return the value of length.
 28 
 29     int maxListSize();
 30         //Function to determine the size of the lise.
 31         //Postcondition:Returns the value of maxSize.
 32 
 33     void print();
 34         //Function to output the elements of the list.
 35         //Postcondition:The elements of the list are output
 36         //                on the standard output device.
 37 
 38     bool isItemAtEqual(int location,const elemType& item);
 39         //Function to determine whether the item is the
 40         //same as the item in the list at the position
 41         //specified by location.
 42         //Postcondition:Returns true if the list[location]
 43         //                is the same as the item ;otherwise
 44         //                returns false.
 45 
 46     void insertAt(int location,const elemType& insertItem);
 47         //Function to insert an item in the list at the 
 48         //position specified by location.The item to be
 49         //inserted is passed as a parameter to the function
 50         //Postcondition:Starting at location ,the elements 
 51         //                of the list are shifted down,
 52         //                list[location] = insertItem; ,
 53         //                and length++;
 54         //                If the list is full or location is
 55         //                out of range ,an appropriate message
 56         //                is displayed.
 57 
 58     void insertEnd(const elemType& insertItem);
 59         //Function to insert an item at the of the list.
 60         //The parameter insertItem specified the item to 
 61         //be inserted.
 62         //Postcondition:list[length] = insetItem; and length++;
 63         //    If the list is full, an appropriate message is
 64         //    displayed.
 65 
 66     void removeAt(int location);
 67         //Function to remove the item from the list at 
 68         //the position specified by location.
 69         //Postcondition:The list elememt at list[location]
 70         //                is removed.and length is determined by 1.
 71         //    If location is out of range ,an appropriate message
 72         //    is displayed.
 73     
 74     //void retrieveAt(int location,elemType& retItem);
 75     //    //Function to retrieve the element from the list at
 76     //    //the position specified by location .
 77     //    //Postcondition:retItem = list[location]
 78     //    //                If location is out of range,an appropiate
 79     //    //                message is displayed.
 80 
 81     elemType retrieveAt(int location);
 82         //Function to retrieve the element from the list at
 83         //the position specified by location .
 84         //Postcondition:list[location]
 85         //                If location is out of range,an appropiate
 86         //                message is displayed.
 87 
 88     void replaceAt(int location, const elemType& repItem);
 89         //Function to replace the element in the list at
 90         //the position specified by location .The item to be
 91         //Postcondition:list[location] = repItem
 92         //                If location is out of range ,an appropriate
 93         //                message is displayed.
 94 
 95     void clearList();
 96         //Function to remove all the elements from the list.
 97         //After this operation ,the size of the list is zero.
 98 
 99     int seqSearch(const elemType& item);
100         //Function to search the list for a given item
101         //Postcondition:If the item is found ,teturns the 
102         //                location in the array where the 
103         //                item is found ;otherwise return -1.
104 
105     void insert(const elemType& insertItem);
106         //Function to insert the item specified by the
107         //parameter insertItem at the end of the list.
108         //However,first the list is searched to see whether
109         //the item to be inserted is already in the list.
110         //Postcondition:list[length] = insertItem;and length++
111         //    If the item is already in the list or the list is
112         //    full,an appropriate message is displayed.
113 
114     void remove(const elemType& removeItem);
115         //Function to remove an item from the list.The
116         //parameter removeItem specified the item to be
117         //removed.
118         //Postcondition:If removeItem is found in the list
119         //                it is removed from the list and
120         //                length is decremented by one.
121 
122     elemType maxValue();
123         //Function to determne the max value in the list
124         //Postcondition:Return the max value int the list
125 
126     elemType minValue();
127         //Function to determne the min value in the list
128         //Postcondition:Return the min value int the list
129 
130     arrayListType(int size = 10000);
131         //constructor 
132         //Creates an array of the size specified  by parameter 
133         // size.The default array size is 100.
134         //Postcondition:The list points to the array;
135         //                length = 0;and maxSize = size
136 
137     arrayListType(const arrayListType<elemType>& otherList);
138         //copy constructor 
139 
140     ~arrayListType();
141         //destructor 
142         //Deallocates the memory occuped by the array
143 
144 protected:
145     elemType *list;        //array to hold the list
146                         //elements
147     int length;            //variable to store the length of 
148                         //the list
149     int maxSize;        //variable to store the maximum size
150                         //of the list.
151 };
152 
153 
154 template<class elemType>
155 bool arrayListType<elemType>::isEmpty()
156 {
157     return(length == 0);
158 }
159 
160 template<class elemType>
161 bool arrayListType<elemType>::isFull()
162 {
163     return(length == maxSize);
164 }
165 
166 template<class elemType>
167 int arrayListType<elemType>::listSize()
168 {
169     return length;
170 }
171 
172 template<class elemType>
173 int arrayListType<elemType>::maxListSize()
174 {
175     return maxSize;
176 }
177 
178 template<class elemType>
179 void arrayListType<elemType>::print()
180 {
181     for(int i = 0; i < length; i++);
182         //cout << list[i] << " " << endl;
183 }
184 
185 template<class elemType>
186 bool arrayListType<elemType>::isItemAtEqual
187                             (int location, const elemType &item)
188 {
189     return(list[location] == item);
190 }
191 
192 template<class elemType>
193 void arrayListType<elemType>::insertAt
194                             (int location, const elemType &insertItem)
195 {
196     if(location < 0 || location >= maxSize);
197     /*    cerr << "The position of the item to be inserted"
198              << " is out of range." << endl;*/
199     else
200         if(length >= maxSize)
201         {
202             //cout << "Can not insert in a full list" << endl;
203             maxSize = length;    //我添加的
204         }
205         else
206         {
207             for(int i = length; i > location; i--)
208                 list[i] = list[i-1];
209 
210             list[location] = insertItem;
211 
212             length++;
213         }
214 }
215 
216 template<class elemType>
217 void arrayListType<elemType>::insertEnd(const elemType &insertItem)
218 {
219     if(length >= maxSize);
220         //cerr << "Cannot insert in a full list" << endl;
221     else
222     {
223         list[length] = inserItem;
224         length++;
225     }
226 }
227 
228 template<class elemType>
229 void arrayListType<elemType>::removeAt(int location)
230 {
231     if(location < 0 || location >= length);
232     /*    cerr << "The location of the item to be removed "
233              << "is out of range." << endl;*/
234     else
235     {
236         for(int i = location; i < length; i++)
237             list[i] = list[i+1];
238 
239         length--;
240     }
241 }
242 
243 //template<class elemType>
244 //void arrayListType<elemType>::retrieveAt(int location, elemType &retItem)
245 //{
246 //    if(location <0 || location >= length)
247 //        cerr << "The location of the item to be retrieved is "
248 //             << "out of range." << endl;
249 //    else
250 //        retItem = list[location];
251 //}
252 
253 
254 template<class elemType>
255 elemType arrayListType<elemType>::retrieveAt(int location)
256 {
257     if(location <0 || location >= length);
258     /*    cerr << "The location of the item to be retrieved is "
259              << "out of range." << endl;*/
260     else
261         return list[location];
262 }
263 
264 template<class elemType>
265 void arrayListType<elemType>::replaceAt(int location, const elemType &repItem)
266 {
267     if(location < 0 || location >= length);
268     /*    cerr << "The location of the item to be retrieved is "
269              << "out of range." << endl;*/
270     else
271         list[location] = repItem;
272 }
273 
274 template<class elemType>
275 void arrayListType<elemType>::clearList()
276 {
277     length = 0;
278 }
279 
280 template<class elemType>
281 arrayListType<elemType>::arrayListType(int size)
282 {
283     if(size < 0)
284     {
285     /*    cerr << "The array size must be positive.Creating " 
286              << "an array of size 100" << endl;*/
287     ;}
288     else
289         maxSize = 10000;
290 
291     length = 0;
292 
293     list = new elemType[maxSize];
294     assert(list != NULL);
295 }
296 
297 template<class elemType>
298 arrayListType<elemType>::~arrayListType()
299 {
300     delete []list;
301 }
302 
303 template<class elemType>
304 arrayListType<elemType>::arrayListType
305                 (const arrayListType<elemType> &otherList)
306 {
307     maxSize = otherList.maxSize;
308     length = otherList.length;
309     list = new elemType[maxSize];
310     assert(list != NULL);
311 
312     for(int i = 0; i < length; i++)
313         list[i] = otherList.list[i];
314 }
315 
316 template<class elemType>
317 const arrayListType<elemType>&
318                     arrayListType<elemType>::operator =
319                     (const arrayListType<elemType> &otherList)
320 {
321     if(this != &otherList)
322     {
323         delete [] list;
324         maxSize = otherList.maxSize;
325         length = otherList.length;
326 
327         list = new elemType[maxSize];
328         assert(list != NULL);
329 
330         for(int i= 0; i < lenght; i++)
331             list[i] = otherList.list[i];
332     }
333 
334     return *this;
335 }
336 
337 
338 template<class elemType>
339 int arrayListType<elemType>::seqSearch(const elemType &item)
340 {
341     int loc;
342     bool found = false;
343 
344     for(loc = 0;loc < length; loc++)
345         if(list[loc] == item)
346         {
347             found = true;
348             break;
349         }
350 
351         if(found)
352             return loc;
353         else
354             return -1;
355 }
356 
357 template<class elemType>
358 void arrayListType<elemType>::insert(const elemType& insertItem)
359 {
360     int loc;
361 
362     if(length == 0)
363         list[length++] = insertItem;
364     else
365         if(length == maxSize);
366             //cerr << "Cannot insert in a full list." << endl;
367         else
368         {
369             loc = seqSearch(insertTtem);
370             if(loc == -1)
371                 list[length++] = insertItem;
372         /*    else
373                 cerr << "The item to be inserted is already in " 
374                      << "list .No duplicates are allowed." << endl;*/
375         }
376 }
377 
378 template<class elemType>
379 void arrayListType<elemType>::remove(const elemType& removeItem)
380 {
381     int loc;
382 
383     if(length == 0);
384         //cerr << "Cannot delete from an empty list." << endl;
385     else
386         loc = seqSearch(removeItem);
387 
388     if(loc != -1)
389         removeAt(loc);
390 /*    else
391         co*/ut << "The item to be deleted is not in the list." << endl;
392 }
393 
394 template<class elemType>
395 elemType arrayListType<elemType>::maxValue()
396 {
397     elemType temp;
398 
399     temp = list[0];
400     for(int i = 0; i < length; i++)
401         if(temp < list[i])
402             temp = list[i];
403 
404     return temp;
405 }
406 
407 template<class elemType>
408 elemType arrayListType<elemType>::minValue()
409 {
410     elemType temp;
411 
412     temp = list[0];
413     for(int i = 0; i < length; i++)
414         if(temp > list[i])
415             temp = list[i];
416 
417     return temp;
418 }
View Code

记得把要用的头文件和变量添加到自己对话框类的头文件中

1 #include "arrayListType.h"
2 
3 
4     
5 CArray<CPoint,CPoint> m_PointArray; // 用于记录坐标点数据
6 int m_PointNum;   // 用于记录坐标点个数,在视图类构造函数中初始化为0。
7 
8 arrayListType<double> xdata;
9 arrayListType<double> ydata;
View Code
下面就是绘图的函数,有点乱。首先在对话框中绘图要在OnPaint当中,如果没有出现这个函数,请在属性框中选择“消息”项,再选择WM_PAINT。图如下:
在OnPaint中的代码如下:
 1 void CFFTDlg::OnPaint()
 2 {
 3     CPaintDC dc(this); // device context for painting
 4     // TODO: 在此处添加消息处理程序代码
 5     CRect rc;
 6     CWnd* pWnd;
 7     pWnd = GetDlgItem(IDC_STATIC_DISFFT);    //IDC_STATIC_DISFFT是Picture控件的ID
 8     pWnd->GetWindowRect(rc);    //获取Picture控件的方框大小
 9     CDC* pDC = pWnd->GetDC();    //获取DC
10 //绘图函数,
11     DrawGrid(rc.Width(), rc.Height(), 1, pDC);
12     // 不为绘图消息调用 CDialog::OnPaint()
13 }
View Code

上面代码中函数DrawGrid用于双缓存绘图,其中的flag不用理会,这是我有别的用处加进去的,不用对flag进行处理。代码如下:

 1 void CFFTDlg::DrawGrid(int width, int height, int flag, CDC* pDC)
 2 { 
 3     CPen newPen;       // 用于创建新画笔   
 4     CPen *pOldPen;     // 用于存放旧画笔   
 5     CBrush newBrush;   // 用于创建新画刷   
 6     CBrush *pOldBrush; // 用于存放旧画刷   
 7 
 8     CRect rectPicture;
 9     CWnd* pWnd;
10     pWnd = GetDlgItem(IDC_STATIC_DISFFT); //IDC_STATIC_DISFFT是Picture控件的ID
11     pWnd->GetWindowRect(rectPicture);
12 
13 //这里是从网上摘下,自己改的
14 //*******************************************************************    
15     CDC   MemDC;   //首先定义一个显示设备对象   
16     CBitmap   MemBitmap;//定义一个位图对象    
17   //随后建立与屏幕显示兼容的内存显示设备   
18     MemDC.CreateCompatibleDC(NULL);   
19   //这时还不能绘图,因为没有地方画   ^_^   
20   //下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小   
21     MemBitmap.CreateCompatibleBitmap(pDC,width,height);   
22       
23   //将位图选入到内存显示设备中   
24   //只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上   
25     CBitmap   *pOldBit=MemDC.SelectObject(&MemBitmap);   
26     
27   //先用背景色将位图清除干净,这里我用的是白色作为背景   
28   //你也可以用自己应该用的颜色   
29     MemDC.FillSolidRect(0,0,width,height,RGB(0,0,0));   
30 //*******************************************************************
31 
32     // 创建黑色新画刷   
33     /*if(nreverse == 0)*/
34         newBrush.CreateSolidBrush(RGB(0,0,0)); 
35     /*else
36         newBrush.CreateSolidBrush(RGB(255,255,255)); */
37     // 选择新画刷,并将旧画刷的指针保存到pOldBrush   
38     pOldBrush = MemDC.SelectObject(&newBrush);   
39     // 以黑色画刷为绘图控件填充黑色,形成黑色背景   
40     MemDC.Rectangle(rectPicture);   
41     // 恢复旧画刷   
42     MemDC.SelectObject(pOldBrush);   
43     // 删除新画刷   
44     newBrush.DeleteObject();   
45   
46     // 创建实心画笔,粗度为1,颜色为绿色   
47     newPen.CreatePen(PS_SOLID, 1, RGB(0,255,0));   
48     // 选择新画笔,并将旧画笔的指针保存到pOldPen   
49     pOldPen = MemDC.SelectObject(&newPen);   
50  
51 //这两个函数是自己添加的
52 //*******************************************************************
53 //绘制网格
54     DrawPic(width, height, &MemDC);
55 //绘制图形
56     Plot(width, height,1,rectPicture,&MemDC);
57 //*******************************************************************
58        
59     MemDC.SelectObject(pOldPen);   // 恢复旧画笔   
60     newPen.DeleteObject();   // 删除新画笔   
61   //*******************************************************************
62 //将内存中的图拷贝到屏幕上进行显示    
63     pDC->BitBlt(0,0,width,height,&MemDC,0,0,SRCCOPY);  
64     
65   //绘图完成后的清理   
66     MemBitmap.DeleteObject();   
67     MemDC.DeleteDC();  
68 }
View Code

上面的DrawPic用于绘制网格和边框以及刻度,不需要刻度的,请自己修改,这是没来得及完善的作品。DrawPic的代码如下:

  1 oid CFFTDlg::DrawPic(int width, int height, CDC* pDC)
  2 {
  3     //边框到窗口的距离
  4     int g = 10;    
  5 //绘制网格的参数
  6     int x = g;
  7     int y = g;
  8     int h = height - 2*g;
  9     int w = width - 2*g;
 10     int wg = (int)(w/10);
 11     int hg = (int)(h/6);
 12     int sg = (width - 2*g)/50;
 13 
 14     int wi[10];
 15     int hi[5];
 16     int i;
 17 //竖线
 18     switch(w%10)
 19     {
 20     case 0:
 21         for(i = 0; i < 10; i++)
 22             wi[i] = wg;
 23         break;
 24     case 1:
 25         for(i = 0; i < 10; i++)
 26         {
 27             if(i == 0)
 28                 wi[i] = wg+1;
 29             else
 30                 wi[i] = wg;
 31         }
 32         break;
 33     case 2:
 34         for(i = 0; i < 10; i++)
 35         {
 36             if(i <= 1)
 37                 wi[i] = wg+1;
 38             else
 39                 wi[i] = wg;
 40         }
 41         break;
 42     case 3:
 43         for(i = 0; i < 10; i++)
 44         {
 45             if(i <= 2)
 46                 wi[i] = wg+1;
 47             else
 48                 wi[i] = wg;
 49         }
 50         break;
 51     case 4:
 52         for(i = 0; i < 10; i++)
 53         {
 54             if(i <= 3)
 55                 wi[i] = wg+1;
 56             else
 57                 wi[i] = wg;
 58         }
 59         break;
 60     case 5:
 61         for(i = 0; i < 10; i++)
 62         {
 63             if(i <= 4)
 64                 wi[i] = wg+1;
 65             else
 66                 wi[i] = wg;
 67         }
 68         break;
 69     case 6:
 70         for(i = 0; i < 10; i++)
 71         {
 72             if(i <= 5)
 73                 wi[i] = wg+1;
 74             else
 75                 wi[i] = wg;
 76         }
 77         break;
 78     case 7:
 79         for(i = 0; i < 10; i++)
 80         {
 81             if(i <= 6)
 82                 wi[i] = wg+1;
 83             else
 84                 wi[i] = wg;
 85         }
 86         break;
 87     case 8:
 88         for(i = 0; i < 10; i++)
 89         {
 90             if(i <= 7)
 91                 wi[i] = wg+1;
 92             else
 93                 wi[i] = wg;
 94         }
 95         break;
 96     case 9:
 97         for(i = 0; i < 10; i++)
 98         {
 99             if(i <= 8)
100                 wi[i] = wg+1;
101             else
102                 wi[i] = wg;
103         }
104         break;
105     }
106 //横线
107     switch(h%6)
108     {
109     case 0:
110         for(i = 0; i < 5; i++)
111             hi[i] = hg;
112         break;
113     case 1:
114         for(i = 0; i < 5; i++)
115         {
116             if(i == 0)
117                 hi[i] = hg+1;
118             else
119                 hi[i] = hg;
120         }
121         break;
122     case 2:
123         for(i = 0; i < 5; i++)
124         {
125             if(i <= 1)
126                 hi[i] = hg+1;
127             else
128                 hi[i] = hg;
129         }
130         break;
131     case 3:
132         for(i = 0; i < 5; i++)
133         {
134             if(i <= 2)
135                 hi[i] = hg+1;
136             else
137                 hi[i] = hg;
138         }
139         break;
140     case 4:
141         for(i = 0; i < 5; i++)
142         {
143             if(i <= 3)
144                 hi[i] = hg+1;
145             else
146                 hi[i] = hg;
147         }
148         break;
149     case 5:
150         for(i = 0; i < 5; i++)
151         {
152             if(i <= 4)
153                 hi[i] = hg+1;
154             else
155                 hi[i] = hg;
156         }
157         break;
158 
159     }
160 
161 //刻度
162     int temp1;
163     int temp2;
164     int j = 0;
165     int gi[50];
166     for(i = 0; i < 10; i++)
167     {
168         temp1 = wi[i]/5;
169         temp2 = wi[i]%5;
170         switch(temp2)
171         {
172         case 0:
173             for(j = 0; j < 5; j++)
174                 gi[5*i+j] = temp1;
175             break;
176         case 1:
177             for(j = 0; j < 5; j++)
178             {
179                 if(j == 0)
180                     gi[5*i+j] = temp1 + 1;
181                 else
182                     gi[5*i+j] = temp1;
183             }
184             break;
185         case 2:
186             for(j = 0; j < 5; j++)
187             {
188                 if(j <= 1)
189                     gi[5*i+j] = temp1 + 1;
190                 else
191                     gi[5*i+j] = temp1;
192             }
193             break;
194         case 3:
195             for(j = 0; j < 5; j++)
196             {
197                 if(j <= 2)
198                     gi[5*i+j] = temp1 + 1;
199                 else
200                     gi[5*i+j] = temp1;
201             }
202             break;
203         case 4:
204             for(j = 0; j < 5; j++)
205             {
206                 if(j <= 3)
207                     gi[5*i+j] = temp1 + 1;
208                 else
209                     gi[5*i+j] = temp1;
210             }
211             break;
212         }
213     }
214 
215 
216     CPen newPen;
217     CPen* pOldPen;
218 
219     //if(flag == 0)
220     //    newPen.CreatePen(PS_DOT,1,RGB(128,128,128));    //网格的颜色为灰色
221     //else
222         newPen.CreatePen(PS_DOT,1,RGB(169,169,169));    //网格的颜色为深灰色
223     pOldPen = pDC->SelectObject(&newPen);        //选择画笔
224 
225 //绘制竖线
226     for(int i = 0; i < 9 ; i++)
227     {
228         x = x + wi[i];
229         y = y + hi[i];
230         //绘制竖虚线
231         pDC->MoveTo(x,g);
232         pDC->LineTo(x,height-g);
233         //绘制横虚线
234         if(i < 5 && i != 2)
235         {
236             pDC->MoveTo(g,y);
237             pDC->LineTo(width-g,y);
238         }
239     }
240 
241 //销毁画笔
242     newPen.DeleteObject();
243 
244     /*if(flag == 0)*/
245         newPen.CreatePen(PS_SOLID,1,RGB(255,255,255));    //定义画笔,颜色为白色
246     //else
247     //    newPen.CreatePen(PS_SOLID,1,RGB(0,0,0));    //定义画笔,颜色为黑色
248         pDC->SelectObject(newPen);    //选择新画笔
249 
250 //绘制坐标轴的边框
251     x = g;
252     y = g;
253     pDC->MoveTo(g,g);
254     pDC->LineTo(width-g,g);
255     pDC->MoveTo(width-g,g);
256     pDC->LineTo(width-g,height-g);
257     pDC->MoveTo(width-g,height-g);
258     pDC->LineTo(g,height-g);
259     pDC->MoveTo(g,height-g);
260     pDC->LineTo(g,g);
261 //绘制x轴轴线
262     pDC->MoveTo(x,y+3*hg);
263     pDC->LineTo(width-g,y+3*hg);
264 
265 //绘制刻度
266     int x1 = g;
267     int yv = y+3*hg;
268     for(int i = 0; i < 50; i++)
269     {
270         x1 = x1 + gi[i];
271         pDC->MoveTo(x1,yv+3);
272         pDC->LineTo(x1,yv-2);
273     }
274 
275     pDC->SelectObject(pOldPen);
276     newPen.DeleteObject();
277 }
View Code

Plot用于绘制用FFT之后的数据绘制频谱,代码如下:

 1 // 绘图接口函数,width绘图区域的长度,height为绘图区域的高,flag为标志位,pdc为指针
 2 void CFFTDlg::Plot(int width, int height, int flag, CRect rc, CDC* pdc)
 3 {
 4     CPen newPen;
 5     CPen* pOldPen;
 6     newPen.CreatePen(PS_SOLID,2,RGB(178,34,34));    //绘制曲线的颜色,火砖色
 7     pOldPen = pdc->SelectObject(&newPen);
 8     
 9     int w = width - 20;
10     int h = height - 20;
11 
12     int x = 20;
13     int y = 20;
14     int i;
15 
16     double W = double(w*100)/100.0;
17     double H = double(h*100)/100.0;
18 
19     if(ydata.minValue()< 0.0)
20         pdc->MoveTo(10,(int)(height/2));
21     else
22         pdc->MoveTo(10,height-10);
23     for(i = 0; i < m_PointNum/2;i++)
24     {    
25         if(ydata.minValue() < 0.0)
26         {
27             x = int(10+2*W*xdata.retrieveAt(i)/xdata.maxValue());
28             y = int((int)(height/2)-H/2*ydata.retrieveAt(i)/ydata.maxValue());
29         }
30         else
31         {
32             x = int(10+W*xdata.retrieveAt(i)/xdata.maxValue());
33             y = int(height - 10 -H*ydata.retrieveAt(i)/ydata.maxValue());
34         }
35         pdc->LineTo(x,y);
36     }
37 
38     pdc->SelectObject(pOldPen);
39     newPen.DeleteObject();
40 }
View Code

我自己的程序是可以用的,上面的内容应该没有完全,自己拷贝拿来用的时候注意是否初始化了变量,是否添加了函数等,不要盲目直接用,最后一直报错却说我的代码不行,鄙视这种人!

最后的贴出粗糙的效果图,我还没有全部完成,比如图中还没有添加刻度文字等等。

 

上面三个是要用的函数,自己看。

posted @ 2013-05-21 15:35  流口水的书  阅读(1017)  评论(1编辑  收藏  举报