查表法实现FFT
/**************************************************************************//*** @file fft_lut.h
* @versionV1.00
* @brief Fast Fourier Transform Parameter Look-up Table
*
* @CopyRight (C) 2019 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef __FFT_LUT_H__
#define __FFT_LUT_H__
/* This example provides 3 types of selectable data length */
#define FFT_128_POINT (0)
#define FFT_256_POINT (1)
#define FFT_512_POINT (2)
/* User can select one of the length setting here. */
#define FFT_N_POINT_SEL (FFT_512_POINT)
/* Assign the corresponding look-up table according to the length setting.
Do not modify the contents here. */
#if (FFT_N_POINT_SEL == FFT_128_POINT)
#define SEQUENCE_LEN (128)
#define RESCALE(x) (x>>7)
#define COS_LUT COS_SCALED_LUT_128
#define SIN_LUT SIN_SCALED_LUT_128
#define REV_LUT REV_LUT_128
#elif (FFT_N_POINT_SEL == FFT_256_POINT)
#define SEQUENCE_LEN (256)
#define RESCALE(x) (x>>8)
#define COS_LUT COS_SCALED_LUT_256
#define SIN_LUT SIN_SCALED_LUT_256
#define REV_LUT REV_LUT_256
#elif (FFT_N_POINT_SEL == FFT_512_POINT)
#define SEQUENCE_LEN (512)
#define RESCALE(x) (x>>9)
#define COS_LUT COS_SCALED_LUT_512
#define SIN_LUT SIN_SCALED_LUT_512
#define REV_LUT REV_LUT_512
#else
#define "configuration error"
#endif
#if (FFT_SEQUENCE_LEN == FFT_SEQUENCE_LEN_128)
#define COS_SCALED_LUT_128 \
{ \
127, 127, 126, 126, 125, 123, 122, 120, 117, 115, 112, 109, 106, 102, 98, 94, \
90, 85, 81, 76, 71, 65, 60, 54, 49, 43, 37, 31, 25, 19, 12, 6, \
0, -6, -12, -19, -25, -31, -37, -43, -49, -54, -60, -65, -71, -76, -81, -85, \
-90, -94, -98,-102,-106,-109,-112,-115,-117,-120,-122,-123,-125,-126,-126,-127, \
-127,-127,-126,-126,-125,-123,-122,-120,-117,-115,-112,-109,-106,-102, -98, -94, \
-90, -85, -81, -76, -71, -65, -60, -54, -49, -43, -37, -31, -25, -19, -12, -6, \
0, 6, 12, 19, 25, 31, 37, 43, 49, 54, 60, 65, 71, 76, 81, 85, \
90, 94, 98, 102, 106, 109, 112, 115, 117, 120, 122, 123, 125, 126, 126, 127, \
}
#define SIN_SCALED_LUT_128 \
{ \
0, 6, 12, 19, 25, 31, 37, 43, 49, 54, 60, 65, 71, 76, 81, 85, \
90, 94, 98, 102, 106, 109, 112, 115, 117, 120, 122, 123, 125, 126, 126, 127, \
127, 127, 126, 126, 125, 123, 122, 120, 117, 115, 112, 109, 106, 102, 98, 94, \
90, 85, 81, 76, 71, 65, 60, 54, 49, 43, 37, 31, 25, 19, 12, 6, \
0, -6, -12, -19, -25, -31, -37, -43, -49, -54, -60, -65, -71, -76, -81, -85, \
-90, -94, -98,-102,-106,-109,-112,-115,-117,-120,-122,-123,-125,-126,-126,-127, \
-127,-127,-126,-126,-125,-123,-122,-120,-117,-115,-112,-109,-106,-102, -98, -94, \
-90, -85, -81, -76, -71, -65, -60, -54, -49, -43, -37, -31, -25, -19, -12, -6, \
}
#define REV_LUT_128 \
{ \
0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, \
4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124, \
2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122, \
6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126, \
1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121, \
5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, \
3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, \
7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127, \
}
#endif
#if (FFT_SEQUENCE_LEN == FFT_SEQUENCE_LEN_256)
#define COS_SCALED_LUT_256 \
{ \
255, 255, 255, 254, 254, 253, 252, 251, 250, 249, 247, 246, 244, 242, 240, 238, \
236, 233, 231, 228, 225, 222, 219, 215, 212, 208, 205, 201, 197, 193, 189, 185, \
180, 176, 171, 167, 162, 157, 152, 147, 142, 136, 131, 126, 120, 115, 109, 103, \
98, 92, 86, 80, 74, 68, 62, 56, 50, 44, 37, 31, 25, 19, 13, 6, \
0, -6, -13, -19, -25, -31, -37, -44, -50, -56, -62, -68, -74, -80, -86, -92, \
-98,-103,-109,-115,-120,-126,-131,-136,-142,-147,-152,-157,-162,-167,-171,-176, \
-180,-185,-189,-193,-197,-201,-205,-208,-212,-215,-219,-222,-225,-228,-231,-233, \
-236,-238,-240,-242,-244,-246,-247,-249,-250,-251,-252,-253,-254,-254,-255,-255, \
-255,-255,-255,-254,-254,-253,-252,-251,-250,-249,-247,-246,-244,-242,-240,-238, \
-236,-233,-231,-228,-225,-222,-219,-215,-212,-208,-205,-201,-197,-193,-189,-185, \
-180,-176,-171,-167,-162,-157,-152,-147,-142,-136,-131,-126,-120,-115,-109,-103, \
-98, -92, -86, -80, -74, -68, -62, -56, -50, -44, -37, -31, -25, -19, -13, -6, \
0, 6, 13, 19, 25, 31, 37, 44, 50, 56, 62, 68, 74, 80, 86, 92, \
98, 103, 109, 115, 120, 126, 131, 136, 142, 147, 152, 157, 162, 167, 171, 176, \
180, 185, 189, 193, 197, 201, 205, 208, 212, 215, 219, 222, 225, 228, 231, 233, \
236, 238, 240, 242, 244, 246, 247, 249, 250, 251, 252, 253, 254, 254, 255, 255, \
}
#define SIN_SCALED_LUT_256 \
{ \
0, 6, 13, 19, 25, 31, 37, 44, 50, 56, 62, 68, 74, 80, 86, 92, \
98, 103, 109, 115, 120, 126, 131, 136, 142, 147, 152, 157, 162, 167, 171, 176, \
180, 185, 189, 193, 197, 201, 205, 208, 212, 215, 219, 222, 225, 228, 231, 233, \
236, 238, 240, 242, 244, 246, 247, 249, 250, 251, 252, 253, 254, 254, 255, 255, \
255, 255, 255, 254, 254, 253, 252, 251, 250, 249, 247, 246, 244, 242, 240, 238, \
236, 233, 231, 228, 225, 222, 219, 215, 212, 208, 205, 201, 197, 193, 189, 185, \
180, 176, 171, 167, 162, 157, 152, 147, 142, 136, 131, 126, 120, 115, 109, 103, \
98, 92, 86, 80, 74, 68, 62, 56, 50, 44, 37, 31, 25, 19, 13, 6, \
0, -6, -13, -19, -25, -31, -37, -44, -50, -56, -62, -68, -74, -80, -86, -92, \
-98,-103,-109,-115,-120,-126,-131,-136,-142,-147,-152,-157,-162,-167,-171,-176, \
-180,-185,-189,-193,-197,-201,-205,-208,-212,-215,-219,-222,-225,-228,-231,-233, \
-236,-238,-240,-242,-244,-246,-247,-249,-250,-251,-252,-253,-254,-254,-255,-255, \
-255,-255,-255,-254,-254,-253,-252,-251,-250,-249,-247,-246,-244,-242,-240,-238, \
-236,-233,-231,-228,-225,-222,-219,-215,-212,-208,-205,-201,-197,-193,-189,-185, \
-180,-176,-171,-167,-162,-157,-152,-147,-142,-136,-131,-126,-120,-115,-109,-103, \
-98, -92, -86, -80, -74, -68, -62, -56, -50, -44, -37, -31, -25, -19, -13, -6, \
}
#define REV_LUT_256 \
{ \
0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, \
8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, \
4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, \
12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, \
2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, \
10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, \
6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, \
14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, \
1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, \
9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, \
5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, \
13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, \
3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, \
11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, \
7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, \
15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255, \
}
#endif
#if (FFT_SEQUENCE_LEN == FFT_SEQUENCE_LEN_512)
#define COS_SCALED_LUT_512 \
{ \
511, 511, 511, 511, 510, 510, 510, 509, 509, 508, 507, 506, 505, 505, 503, 502, \
501, 500, 499, 497, 496, 494, 492, 491, 489, 487, 485, 483, 481, 479, 477, 474, \
472, 470, 467, 465, 462, 459, 456, 454, 451, 448, 445, 441, 438, 435, 432, 428, \
425, 421, 418, 414, 410, 407, 403, 399, 395, 391, 387, 383, 379, 374, 370, 366, \
361, 357, 352, 348, 343, 338, 334, 329, 324, 319, 314, 309, 304, 299, 294, 289, \
284, 279, 273, 268, 263, 257, 252, 246, 241, 235, 230, 224, 218, 213, 207, 201, \
196, 190, 184, 178, 172, 166, 160, 154, 148, 142, 136, 130, 124, 118, 112, 106, \
100, 94, 87, 81, 75, 69, 63, 56, 50, 44, 38, 31, 25, 19, 13, 6, \
0, -6, -13, -19, -25, -31, -38, -44, -50, -56, -63, -69, -75, -81, -87, -94, \
-100,-106,-112,-118,-124,-130,-136,-142,-148,-154,-160,-166,-172,-178,-184,-190, \
-196,-201,-207,-213,-218,-224,-230,-235,-241,-246,-252,-257,-263,-268,-273,-279, \
-284,-289,-294,-299,-304,-309,-314,-319,-324,-329,-334,-338,-343,-348,-352,-357, \
-361,-366,-370,-374,-379,-383,-387,-391,-395,-399,-403,-407,-410,-414,-418,-421, \
-425,-428,-432,-435,-438,-441,-445,-448,-451,-454,-456,-459,-462,-465,-467,-470, \
-472,-474,-477,-479,-481,-483,-485,-487,-489,-491,-492,-494,-496,-497,-499,-500, \
-501,-502,-503,-505,-505,-506,-507,-508,-509,-509,-510,-510,-510,-511,-511,-511, \
-511,-511,-511,-511,-510,-510,-510,-509,-509,-508,-507,-506,-505,-505,-503,-502, \
-501,-500,-499,-497,-496,-494,-492,-491,-489,-487,-485,-483,-481,-479,-477,-474, \
-472,-470,-467,-465,-462,-459,-456,-454,-451,-448,-445,-441,-438,-435,-432,-428, \
-425,-421,-418,-414,-410,-407,-403,-399,-395,-391,-387,-383,-379,-374,-370,-366, \
-361,-357,-352,-348,-343,-338,-334,-329,-324,-319,-314,-309,-304,-299,-294,-289, \
-284,-279,-273,-268,-263,-257,-252,-246,-241,-235,-230,-224,-218,-213,-207,-201, \
-196,-190,-184,-178,-172,-166,-160,-154,-148,-142,-136,-130,-124,-118,-112,-106, \
-100, -94, -87, -81, -75, -69, -63, -56, -50, -44, -38, -31, -25, -19, -13, -6, \
0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 63, 69, 75, 81, 87, 94, \
100, 106, 112, 118, 124, 130, 136, 142, 148, 154, 160, 166, 172, 178, 184, 190, \
196, 201, 207, 213, 218, 224, 230, 235, 241, 246, 252, 257, 263, 268, 273, 279, \
284, 289, 294, 299, 304, 309, 314, 319, 324, 329, 334, 338, 343, 348, 352, 357, \
361, 366, 370, 374, 379, 383, 387, 391, 395, 399, 403, 407, 410, 414, 418, 421, \
425, 428, 432, 435, 438, 441, 445, 448, 451, 454, 456, 459, 462, 465, 467, 470, \
472, 474, 477, 479, 481, 483, 485, 487, 489, 491, 492, 494, 496, 497, 499, 500, \
501, 502, 503, 505, 505, 506, 507, 508, 509, 509, 510, 510, 510, 511, 511, 511, \
}
#define SIN_SCALED_LUT_512 \
{ \
0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 63, 69, 75, 81, 87, 94, \
100, 106, 112, 118, 124, 130, 136, 142, 148, 154, 160, 166, 172, 178, 184, 190, \
196, 201, 207, 213, 218, 224, 230, 235, 241, 246, 252, 257, 263, 268, 273, 279, \
284, 289, 294, 299, 304, 309, 314, 319, 324, 329, 334, 338, 343, 348, 352, 357, \
361, 366, 370, 374, 379, 383, 387, 391, 395, 399, 403, 407, 410, 414, 418, 421, \
425, 428, 432, 435, 438, 441, 445, 448, 451, 454, 456, 459, 462, 465, 467, 470, \
472, 474, 477, 479, 481, 483, 485, 487, 489, 491, 492, 494, 496, 497, 499, 500, \
501, 502, 503, 505, 505, 506, 507, 508, 509, 509, 510, 510, 510, 511, 511, 511, \
511, 511, 511, 511, 510, 510, 510, 509, 509, 508, 507, 506, 505, 505, 503, 502, \
501, 500, 499, 497, 496, 494, 492, 491, 489, 487, 485, 483, 481, 479, 477, 474, \
472, 470, 467, 465, 462, 459, 456, 454, 451, 448, 445, 441, 438, 435, 432, 428, \
425, 421, 418, 414, 410, 407, 403, 399, 395, 391, 387, 383, 379, 374, 370, 366, \
361, 357, 352, 348, 343, 338, 334, 329, 324, 319, 314, 309, 304, 299, 294, 289, \
284, 279, 273, 268, 263, 257, 252, 246, 241, 235, 230, 224, 218, 213, 207, 201, \
196, 190, 184, 178, 172, 166, 160, 154, 148, 142, 136, 130, 124, 118, 112, 106, \
100, 94, 87, 81, 75, 69, 63, 56, 50, 44, 38, 31, 25, 19, 13, 6, \
0, -6, -13, -19, -25, -31, -38, -44, -50, -56, -63, -69, -75, -81, -87, -94, \
-100,-106,-112,-118,-124,-130,-136,-142,-148,-154,-160,-166,-172,-178,-184,-190, \
-196,-201,-207,-213,-218,-224,-230,-235,-241,-246,-252,-257,-263,-268,-273,-279, \
-284,-289,-294,-299,-304,-309,-314,-319,-324,-329,-334,-338,-343,-348,-352,-357, \
-361,-366,-370,-374,-379,-383,-387,-391,-395,-399,-403,-407,-410,-414,-418,-421, \
-425,-428,-432,-435,-438,-441,-445,-448,-451,-454,-456,-459,-462,-465,-467,-470, \
-472,-474,-477,-479,-481,-483,-485,-487,-489,-491,-492,-494,-496,-497,-499,-500, \
-501,-502,-503,-505,-505,-506,-507,-508,-509,-509,-510,-510,-510,-511,-511,-511, \
-511,-511,-511,-511,-510,-510,-510,-509,-509,-508,-507,-506,-505,-505,-503,-502, \
-501,-500,-499,-497,-496,-494,-492,-491,-489,-487,-485,-483,-481,-479,-477,-474, \
-472,-470,-467,-465,-462,-459,-456,-454,-451,-448,-445,-441,-438,-435,-432,-428, \
-425,-421,-418,-414,-410,-407,-403,-399,-395,-391,-387,-383,-379,-374,-370,-366, \
-361,-357,-352,-348,-343,-338,-334,-329,-324,-319,-314,-309,-304,-299,-294,-289, \
-284,-279,-273,-268,-263,-257,-252,-246,-241,-235,-230,-224,-218,-213,-207,-201, \
-196,-190,-184,-178,-172,-166,-160,-154,-148,-142,-136,-130,-124,-118,-112,-106, \
-100, -94, -87, -81, -75, -69, -63, -56, -50, -44, -38, -31, -25, -19, -13, -6, \
}
#define REV_LUT_512 \
{ \
0, 256, 128, 384, 64, 320, 192, 448, 32, 288, 160, 416, 96, 352, 224, 480, \
16, 272, 144, 400, 80, 336, 208, 464, 48, 304, 176, 432, 112, 368, 240, 496, \
8, 264, 136, 392, 72, 328, 200, 456, 40, 296, 168, 424, 104, 360, 232, 488, \
24, 280, 152, 408, 88, 344, 216, 472, 56, 312, 184, 440, 120, 376, 248, 504, \
4, 260, 132, 388, 68, 324, 196, 452, 36, 292, 164, 420, 100, 356, 228, 484, \
20, 276, 148, 404, 84, 340, 212, 468, 52, 308, 180, 436, 116, 372, 244, 500, \
12, 268, 140, 396, 76, 332, 204, 460, 44, 300, 172, 428, 108, 364, 236, 492, \
28, 284, 156, 412, 92, 348, 220, 476, 60, 316, 188, 444, 124, 380, 252, 508, \
2, 258, 130, 386, 66, 322, 194, 450, 34, 290, 162, 418, 98, 354, 226, 482, \
18, 274, 146, 402, 82, 338, 210, 466, 50, 306, 178, 434, 114, 370, 242, 498, \
10, 266, 138, 394, 74, 330, 202, 458, 42, 298, 170, 426, 106, 362, 234, 490, \
26, 282, 154, 410, 90, 346, 218, 474, 58, 314, 186, 442, 122, 378, 250, 506, \
6, 262, 134, 390, 70, 326, 198, 454, 38, 294, 166, 422, 102, 358, 230, 486, \
22, 278, 150, 406, 86, 342, 214, 470, 54, 310, 182, 438, 118, 374, 246, 502, \
14, 270, 142, 398, 78, 334, 206, 462, 46, 302, 174, 430, 110, 366, 238, 494, \
30, 286, 158, 414, 94, 350, 222, 478, 62, 318, 190, 446, 126, 382, 254, 510, \
1, 257, 129, 385, 65, 321, 193, 449, 33, 289, 161, 417, 97, 353, 225, 481, \
17, 273, 145, 401, 81, 337, 209, 465, 49, 305, 177, 433, 113, 369, 241, 497, \
9, 265, 137, 393, 73, 329, 201, 457, 41, 297, 169, 425, 105, 361, 233, 489, \
25, 281, 153, 409, 89, 345, 217, 473, 57, 313, 185, 441, 121, 377, 249, 505, \
5, 261, 133, 389, 69, 325, 197, 453, 37, 293, 165, 421, 101, 357, 229, 485, \
21, 277, 149, 405, 85, 341, 213, 469, 53, 309, 181, 437, 117, 373, 245, 501, \
13, 269, 141, 397, 77, 333, 205, 461, 45, 301, 173, 429, 109, 365, 237, 493, \
29, 285, 157, 413, 93, 349, 221, 477, 61, 317, 189, 445, 125, 381, 253, 509, \
3, 259, 131, 387, 67, 323, 195, 451, 35, 291, 163, 419, 99, 355, 227, 483, \
19, 275, 147, 403, 83, 339, 211, 467, 51, 307, 179, 435, 115, 371, 243, 499, \
11, 267, 139, 395, 75, 331, 203, 459, 43, 299, 171, 427, 107, 363, 235, 491, \
27, 283, 155, 411, 91, 347, 219, 475, 59, 315, 187, 443, 123, 379, 251, 507, \
7, 263, 135, 391, 71, 327, 199, 455, 39, 295, 167, 423, 103, 359, 231, 487, \
23, 279, 151, 407, 87, 343, 215, 471, 55, 311, 183, 439, 119, 375, 247, 503, \
15, 271, 143, 399, 79, 335, 207, 463, 47, 303, 175, 431, 111, 367, 239, 495, \
31, 287, 159, 415, 95, 351, 223, 479, 63, 319, 191, 447, 127, 383, 255, 511, \
}
#endif
#endif
/**************************************************************************//**
* @file main.c
* @versionV1.00
* @brief Perform Fast Fourier Transform with ADC samples.
*
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <math.h>
#include "NuMicro.h"
#include "fft_lut.h"
/* Select the macro FFT_N_POINT_SEL defined in fft_lut.h.
* The look-up table for fft algorithm requires user indicates specific data length.
*/
/* System clock frequency */
#define PLL_CLOCK (48000000)
/* The parameter SAMPLE_RATE is configurable. It is based on your application.
* The unit of SAMPLE_RATE is hertz.
*/
#define SAMPLE_RATE (1024)
/* The parameter SAMPLE_DATA_RSHIFT is configurable, the purpose is to truncate
* the data size by right shifting the raw ADC data, and it can prevent the buffer
* from overflow when calculating a large amount N point of FFT. The longer data
* length is selected, the higher SAMPLE_DATA_RSHIFT is required. If the spectrum
* buffer is overflow, try to increase the SAMPLE_DATA_RSHIFT parameter.
*/
#define SAMPLE_DATA_RSHIFT (5)
#define SHRINK(x) ((x) >> SAMPLE_DATA_RSHIFT)
/* Macros to simplify the math presentations for FFT algorithm */
#define COS(angle_index) (g_ai16cos)
#define SIN(angle_index) (g_ai16sin)
#define REV(origin_index) (g_ai16rev)
/*----------------------------------------------------------------------------------------------------------*/
/* Define Function Prototypes */
/*----------------------------------------------------------------------------------------------------------*/
void SYS_Init(void);
void UART0_Init(void);
void TIMER0_Init(void);
void ADC_Init(void);
void Remove_DC_Component(int *pi32DataBuffer, uint32_t u32Len);
void NuFFT(int *pi32RealBuffer, int *pi32ImageBuffer, uint32_t u32Len);
void Display_Spectrum(int *pi32Spectrum, uint32_t u32Len, uint32_t u32SampleRate);
void Display_AdcData(int *pi32Data, uint32_t u32Len);
/*----------------------------------------------------------------------------------------------------------*/
/* Define global variables and constants */
/*----------------------------------------------------------------------------------------------------------*/
const uint8_t g_u8AdcChannel = 2;
/* Look-up table for FFT twiddle factors and the bit-reversal index */
const int16_t g_ai16cos = COS_LUT;
const int16_t g_ai16sin = SIN_LUT;
const int16_t g_ai16rev = REV_LUT;
/* The data buffer for storing the ADC data samples and the output spectrum */
int g_i32RealBuffer ;
int g_i32ImageBuffer;
int g_i32Spectrum ;
/* Global variables for handing ADC conversions */
volatile uint32_t g_u32AdcConvNum = 0;
/*----------------------------------------------------------------------------------------------------------*/
/*Function: SYS_Init */
/*Parameters:None. */
/*Returns: None. */
/*Description: System and periphial module clock setting. */
/*----------------------------------------------------------------------------------------------------------*/
void SYS_Init(void)
{
/* Enable HIRC clock (Internal RC 48MHz) */
CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
/* Enable HIRC clock (Internal RC 48MHz) */
CLK_EnableXtalRC(CLK_PWRCTL_HXTEN);
/* Wait for HIRC clock ready */
CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);
/* Set core clock as PLL_CLOCK from PLL (From HXT if HXT is enabled)*/
CLK_SetCoreClock(PLL_CLOCK);
/* Enable UART module clock */
CLK_EnableModuleClock(UART0_MODULE);
/* Select UART module clock source as HIRC/2 and UART module clock divider as 1 */
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UARTSEL_HIRC_DIV2, CLK_CLKDIV0_UART(1));
/* Enable TMR0 module clock */
CLK_EnableModuleClock(TMR0_MODULE);
/* Set TMR0 module clock source as HIRC/2 */
CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_HXT, 0);
/* Enable ADC module clock */
CLK_EnableModuleClock(ADC_MODULE);
/* Set ADC clock source to PCLK0=48MHz, set divider to 3, ADC clock will be 16 MHz */
CLK_SetModuleClock(ADC_MODULE, CLK_CLKSEL1_ADCSEL_PCLK0, CLK_CLKDIV0_ADC(3));
/* Update core clock */
SystemCoreClockUpdate();
/* Set GPB multi-function pins for UART0 RXD and TXD */
SYS->GPB_MFPL = SYS_GPB_MFPL_PB0MFP_UART0_RXD | SYS_GPB_MFPL_PB1MFP_UART0_TXD;
/* Set PD.2 and PD.3 to input mode */
PD->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);
/* Set PD2 and PD3 to ADC mode for ADC input channel 2 and 3 */
SYS->GPD_MFPL &= ~(SYS_GPD_MFPL_PD2MFP_Msk | SYS_GPD_MFPL_PD3MFP_Msk);
SYS->GPD_MFPL |= (SYS_GPD_MFPL_PD2MFP_ADC_CH2 | SYS_GPD_MFPL_PD3MFP_ADC_CH3);
/* Disable the digital input paths of ADC analog pins */
GPIO_DISABLE_DIGITAL_PATH(PD, BIT2 | BIT3);
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: UART0_Init */
/*Parameters:None. */
/*Returns: None. */
/*Description: Initialize UART0 module, setting buadrate is 115200 bps */
/*----------------------------------------------------------------------------------------------------------*/
void UART0_Init(void)
{
/* Reset UART0 */
SYS_ResetModule(UART0_RST);
/* Configure UART0 and set UART0 baud rate */
UART_Open(UART0, 115200);
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: TIMER0_Init */
/*Parameters:None. */
/*Returns: None. */
/*Description: Initialize TIMER0 module. Setup timeout trigger ADC. */
/*----------------------------------------------------------------------------------------------------------*/
void TIMER0_Init(void)
{
uint32_t u32Freq;
/* Set TIMER0 working frequency to SAMPLE_RATE */
u32Freq = TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, SAMPLE_RATE);
if (u32Freq != SAMPLE_RATE)
{
printf("# Warning. Sample rate does not equal to the pre-defined setting.\n\r");
}
/* Enable timer timeout interrupt trigger ADC */
TIMER0->CTL |= TIMER_TRGSRC_TIMEOUT_EVENT | TIMER_TRG_TO_ADC | TIMER_CTL_INTEN_Msk;
printf(" CTL:0x%08X\n\r", TIMER0->CTL);
printf(" CMP:0x%08X\n\r", TIMER0->CMP);
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: ADC_Init */
/*Parameters:None. */
/*Returns: None. */
/*Description: Initialize ADC module channel 2. Enable TIMER trigger ADC function. */
/*----------------------------------------------------------------------------------------------------------*/
void ADC_Init(void)
{
/* Set the ADC operation mode as single, input mode as single-end and enable the analog input channel 2 */
ADC_Open(ADC, ADC_ADCR_DIFFEN_SINGLE_END, ADC_ADCR_ADMD_SINGLE, 0x1 << g_u8AdcChannel);
/* Enable TIMER Trigger ADC */
ADC_EnableTimerTrigger(ADC, ADC_ADCR_TRGS_TIMER, 0);
/* Power on ADC module */
ADC_POWER_ON(ADC);
/* Clear the A/D interrupt flag for safe */
ADC_CLR_INT_FLAG(ADC, ADC_ADF_INT);
/* Enable the ADC interrupt */
ADC_EnableInt(ADC, ADC_ADF_INT);
NVIC_EnableIRQ(ADC_IRQn);
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: Remove_DC_Component */
/*Parameters:pi32DataBuffer is the raw data buffer pointer. */
/*Parameters:u32Len is the length of the raw data buffer. */
/*Returns: None. */
/*Description: None. */
/*----------------------------------------------------------------------------------------------------------*/
void Remove_DC_Component(int *pi32DataBuffer, uint32_t u32Len)
{
uint32_t i, u32Mean, u32Accumulate = 0;
for (i = 0; i < u32Len; i++)
{
u32Accumulate += pi32DataBuffer;
}
u32Mean = u32Accumulate / u32Len;
for (i = 0; i < u32Len; i++)
{
pi32DataBuffer -= u32Mean;
}
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: NuFFT */
/*Parameters:pi32RealBufferis the pointer to the realpart of the data buffer. */
/*Parameters:pi32ImageBuffer is the pointer to the image part of the data buffer. */
/*Parameters:u32Len indicates the length of the data sequence. */
/*Returns: None. */
/*Description: Fast Fourier Transform Algorithm. Transform the time-domain data */
/* sequence into a frequency-domain spectrum. */
/*----------------------------------------------------------------------------------------------------------*/
void NuFFT(int *pi32RealBuffer, int *pi32ImageBuffer, uint32_t u32Len)
{
const uint32_t N = u32Len;
const uint32_t u32TotalStage = log(N) / log(2);
uint32_t u32Stage, u32Span, u32Node, u32Twiddle, u32Angle;
int32_t i32X1Real, i32X1Image, i32X2Real, i32X2Image;
/* Iterations for log2(N) FFT butterfly stages */
for (u32Stage = 0; u32Stage < u32TotalStage; u32Stage++)
{
/* Span indicates the buffer index for constituting a butterfly matrix */
u32Span = pow(2, u32Stage);
for (u32Twiddle = 0; u32Twiddle < u32Span; u32Twiddle++)
{
u32Angle = (N >> 1) / u32Span * u32Twiddle;
for (u32Node = u32Twiddle; u32Node < N; u32Node += 2 * u32Span)
{
/* Get the real and image part of the input variable X1 */
i32X1Real= pi32RealBuffer ;
i32X1Image = pi32ImageBuffer;
/* Get the real and image part of the input variable X2 */
i32X2Real= pi32RealBuffer ;
i32X2Image = pi32ImageBuffer;
/* Y1 = X1 + X2 * twiddle factor
* The real part is real * cos() + image * sin()
* The image part is -real * sin() + image * cos()
*/
pi32RealBuffer = i32X1Real+ RESCALE(i32X2Real * COS(u32Angle)) + RESCALE(i32X2Image * SIN(u32Angle));
pi32ImageBuffer = i32X1Image - RESCALE(i32X2Real * SIN(u32Angle)) + RESCALE(i32X2Image * COS(u32Angle));
/* Y2 = X1 - X2 * twiddle factor
* The real part is-real * cos() - image * sin()
* The image part isreal * sin() - image * cos()
*/
pi32RealBuffer = i32X1Real- RESCALE(i32X2Real * COS(u32Angle)) - RESCALE(i32X2Image * SIN(u32Angle));
pi32ImageBuffer = i32X1Image + RESCALE(i32X2Real * SIN(u32Angle)) - RESCALE(i32X2Image * COS(u32Angle));
}
}
}
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: Display_Spectrum */
/*Parameters:pi32Spectrum is the spectrum buffer pointer. */
/*Parameters:u32Len is the length of the spectrum buffer. */
/*Parameters:u32SampleRate is the frequency of TIMER trigger EADC. */
/*Returns: none. */
/*Description: Show the detail informations from the spectrum bffer. */
/*----------------------------------------------------------------------------------------------------------*/
void Display_Spectrum(int *pi32Spectrum, uint32_t u32Len, uint32_t u32SampleRate)
{
const floatfconstResolution = (float)u32SampleRate / (float)u32Len;
int i, i32Base, i32Accumulate = 0;
printf("+-----------------------------------------------------------+\n\r");
printf("Spectrum Parameters \n\r");
printf("# Sample rate: %d Hz \n\r", u32SampleRate);
printf("# Data length: %d samples \n\r", u32Len);
printf("# Resolution : %.2f Hz \n\r", fconstResolution);
printf("+-----------------------------------------------------------+\n\r");
printf("#Index #Frequency(Hz) #Amplitude #Ratio \n\r");
for (i = 0; i < u32Len; i++)
{
i32Accumulate += pi32Spectrum;
}
for (i = 0; i < u32Len; i++)
{
i32Base = (i <= u32Len / 2) ? (i) : (i - u32Len);
printf(" %-7d %-15.2f %-11d %.2f%%\n\r", i, (float)(fconstResolution * i32Base), pi32Spectrum, (float)pi32Spectrum / (float)i32Accumulate * 100);
}
printf("+-----------------------------------------------------------+\n\r");
printf("FFT complete\n\r");
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: Display_AdcData */
/*Parameters:pi32Spectrum is the Time Domian Data buffer pointer. */
/*Parameters:u32Len is the length of the Data. */
/*Returns: none. */
/*Description: Show the detail informations from the spectrum bffer. */
/*----------------------------------------------------------------------------------------------------------*/
void Display_AdcData(int *pi32Data, uint32_t u32Len)
{
int i;
printf("+-----------------------------------------------------------+\n\r");
printf("| Display Time-Domain Data +\n\r");
printf("+-----------------------------------------------------------+\n\r");
printf("#Index before reversal #Index after reversal #ADC Data \n\r");
for (i = 0; i < u32Len; i++)
{
printf(" %-22d %-21d %d\n\r", i, REV(i), pi32Data);
}
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: ADC_IRQHandler */
/*Parameters:None. */
/*Returns: None. */
/*Description: Interrupt service routine for EADC interrupt. */
/*----------------------------------------------------------------------------------------------------------*/
void ADC_IRQHandler(void)
{
/* clear the A/D conversion flag */
ADC_CLR_INT_FLAG(ADC, ADC_ADF_INT);
/* Toggle PB.0 to indicate an ADC data conversion is complete */
PB0 ^= 1;
/* Place the time-domain signal into the real part buffer */
g_i32RealBuffer = SHRINK(ADC_GET_CONVERSION_DATA(ADC, g_u8AdcChannel));
/* The image part buffer is initialized to zeros */
g_i32ImageBuffer = 0;
/* Increase the buffer index by 1 */
g_u32AdcConvNum++;
}
/*----------------------------------------------------------------------------------------------------------*/
/*Function: main */
/*Parameters:None. */
/*Returns: None. */
/*Description: main routine of the example. */
/*----------------------------------------------------------------------------------------------------------*/
int32_t main(void)
{
int i;
/* Unlock protected registers */
SYS_UnlockReg();
/* Init System, peripheral clock and multi-function I/O */
SYS_Init();
/* Lock protected registers */
SYS_LockReg();
/* Init UART0 for printf */
UART0_Init();
/* Init TIMER0 to trigger ADC sampling later. */
TIMER0_Init();
/* Init ADC channel 2.*/
ADC_Init();
printf("\n");
printf("+-----------------------------------------------------------+\n\r");
printf("| Fast Fourier Transform Example Code |\n\r");
printf("+-----------------------------------------------------------+\n\n\r");
printf("# Demonstrate the decimate-in-time(DIT) radix-2 FFT \n\r");
printf("# This example code supports 3 kinds of data length: \n\r");
printf(" * 128 samples \n\r");
printf(" * 256 samples \n\r");
printf(" * 512 samples \n\r");
printf("# Please confirm the selected length of fft sequence is [%d].\n\r", SEQUENCE_LEN);
printf(" Otherwise, change the fft sequence length settings and \n\r");
printf(" re-compile again to acquire the correct look-up table. \n\r");
printf("# Connect PD.2 to the signal source. \n\r");
printf("# Press any key to start ADC capturing....\n\n\r");
getchar();
/* Reset the ADC numbers of conversion and Start A/D conversion */
g_u32AdcConvNum = 0;
PB0 = 0;
GPIO_SetMode(PB, BIT0, GPIO_MODE_OUTPUT);
/* Start capturing data. */
TIMER_Start(TIMER0);
while (g_u32AdcConvNum != SEQUENCE_LEN)
{
/* Wait for the number of ADC data samples reach SEQUENCE_LEN samples. */
__NOP();
}
/* Stop TIMER trigger EADC */
TIMER_Stop(TIMER0);
/* Disable EDC module */
ADC_Close(ADC);
/* Disable ADC IP clock */
CLK_DisableModuleClock(ADC_MODULE);
/* Disable TIMER0 IP clock */
CLK_DisableModuleClock(TMR0_MODULE);
/* Disable External Interrupt */
NVIC_DisableIRQ(ADC_IRQn);
Display_AdcData(g_i32RealBuffer, SEQUENCE_LEN);
/* Remove the DC component from the spectrum by zero-mean the time-domain signal before
performing FFT. Otherwise, it will remain a high DC component at the 0 Hz point. */
Remove_DC_Component(g_i32RealBuffer, SEQUENCE_LEN);
/* Transform the time domain signal into frequency domain */
NuFFT(g_i32RealBuffer, g_i32ImageBuffer, SEQUENCE_LEN);
for (i = 0; i < SEQUENCE_LEN ; i++)
{
/* The amplitude of the spectrum could be presented as the sum of square of the real part and the complex part. */
g_i32Spectrum = (((g_i32RealBuffer * g_i32RealBuffer) + (g_i32ImageBuffer * g_i32ImageBuffer)));
}
Display_Spectrum(g_i32Spectrum, SEQUENCE_LEN, SAMPLE_RATE);
while (1);
}
我觉得这个方法应该大部分单片机都可以用。直接通过表内存储的正弦离散表数据计算 需要有足够的精度,以保证FFT计算的准确性。 旋转因子的生成可以通过预先计算并存储在表中。表的生成应在程序初始化时完成,以确保在FFT计算过程中能够快速查表 可以使用高精度的数学库来进行预计算,并在存储时选择合适的浮点数格式。 对于较大的FFT点数,查表**占用大量内存。需要权衡内存使用和计算效率,避免内存溢出 如果硬件支持,可以考虑使用多线程或向量化指令来进一步提高计算速度。 查表法在一定复杂度下可以节省开支 在嵌入式系统或实时处理环境中,查表法的效率和资源使用尤为重要。需要确保查表法能够在有限的资源和时间内完成计算。 预先计算所有可能的基向量乘积结果并存储在查找表中,确保这些结果的准确性至关重要。任何微小的计算错误都可能导致最终的FFT结果出现偏差。例如,在计算正弦和余弦值时,要保证足够的精度。 在应用FFT之前,通常需要对原始信号进行一些预处理,如去除直流分量、滤除噪声、加窗等,以提高FFT的性能和准确性。 在实际计算过程中,需要高效地索引和查找查表中的数据。查表的索引方式应尽量简单和高效,以减少查找时间。 实现一个有效的位逆序算法来重新排列输入数据,这是FFT算法中的一个关键步骤。 查表法通常需要将大点数的DFT分解为多个小点数的DFT。分解过程需要遵循FFT的对称性和周期性特性。
蝶形运算是FFT的核心操作,需要结合查表中的预先计算值来完成复数乘法和加法操作。蝶形运算的实现需要高效且准确。 查表法适用于特定点数的FFT计算。例如,64点查表法FFT适用于64个复数样本的DFT计算。如果需要处理其他点数的FFT,需要重新生成相应的查表数据。 查表法依赖于预先计算的DFT值的准确性。因此,预计算过程需要确保计算精度,以避免由于精度问题导致的计算误差。 查表法需要预先计算并存储旋转因子(正弦和余弦值),表的精度直接影响计算结果的准确性。表的分辨率越高,精度越高,但占用的存储空间也越大 在使用查找表时,需要准确计算索引值。索引计算错误会导致从表中读取到错误的数据,从而影响 FFT 的计算结果。索引计算通常与 FFT 的蝶形运算步骤和数据排列顺序相关。 根据采样定理,信号的采样率应大于信号频率的两倍才能正常重构信号。确保输入信号的采样率满足这一要求。