산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

EasyFFT:Arduino용 고속 푸리에 변환(FFT)

구성품 및 소모품

Arduino Nano R3
× 1

앱 및 온라인 서비스

Arduino IDE

이 프로젝트 정보

캡처된 신호의 주파수 측정은 계산 능력이 낮기 때문에 특히 Arduino에서 어려운 작업이 될 수 있습니다. 주어진 시간 내에 신호가 제로 라인을 교차하는 횟수를 확인하여 주파수가 캡처되는 제로 크로싱을 캡처하는 데 사용할 수 있는 방법이 있습니다. 이러한 방법은 신호가 다양한 주파수의 조합일 때 작동하지 않을 수 있습니다.

이러한 배경이 아닌 경우 코딩하기가 다소 어렵습니다. 그러나 땜장이인 이 코드는 음악, 신호 분석과 관련된 다양한 프로젝트에 매우 유용할 수 있습니다. 이 프로젝트의 동기는 배경에 얽매이지 않고 Arduino에서 쉽게 구현할 수 있는 코드를 준비하는 것이었습니다.

이 프로젝트는 FFT의 작동을 설명하는 것이 아니라 FFT 기능의 응용을 설명합니다. 첨부된 영상에서도 같은 과정을 설명하고 있습니다.

코드에 대한 설명이 아닌 적용에만 관심이 있는 경우. 3단계로 바로 건너뛸 수 있습니다.

정확도에서 약간의 타협(약 5%)으로 고속(3x)으로 FFT를 수행해야 하는 경우 ApproxFFT에 대한 다른 기사를 참조하십시오.

https://create.arduino.cc/projecthub/abhilashpatel121/approxfft-fastest-fft-function-for-arduino-fd4917?ref=user&ref_id=1593632&offset=0

1단계:고속 푸리에 변환

DFT의 계산을 더 빠르게 하기 위해 FFT 알고리즘은 James Cooley와 John Tukey에 의해 개발되었습니다. 이 알고리즘은 또한 20세기의 가장 중요한 알고리즘 중 하나로 간주됩니다. 신호를 홀수 및 짝수 시퀀스 부분으로 분할하여 필요한 계산 수를 낮춥니다. 이를 사용하여 필요한 총 복소수 곱셈을 NlogN으로 줄일 수 있습니다. 이는 상당한 개선입니다. 일반적인 DFT는 결과에 대해 N*N 복소 곱셈을 사용하는 반면 FFT는 N*logN만 사용합니다. 이는 샘플 수가 많을 때 상당한 이점이 됩니다.

FFT 이면의 수학에 대한 자세한 이해를 위해 코드를 작성하는 동안 참조한 아래 참조를 참조할 수 있습니다.

1. https://flylib.com/books/en/2.729.1/derivation_of_...

2. https://jakevdp.github.io/blog/2013/08/28/understa...

3. https://cnx.org/contents/[email protected]:zmcmahhR@7/D...

4. https://en.wikipedia.org/wiki/Fast_Fourier_transfo...

2단계:코드 설명

1. 빠른 사인과 코사인:

계산 FFT는 다양한 사인 및 코사인 값을 여러 번 취합니다. Arduino의 내장 기능은 충분히 빠르지 않고 필요한 값을 제공하는 데 상당한 시간이 걸립니다. 이로 인해 코드가 상당히 느려집니다(64개 샘플의 경우 시간이 두 배). 이 문제에 대응하기 위해 0 ~ 90도에 대한 사인 값은 255의 배수로 저장됩니다. 이렇게 하면 숫자를 float로 저장할 필요가 없고 Arduino에서 1/4 공간을 차지하는 바이트로 저장할 수 있습니다. sine_data[ ]를 전역 변수로 선언하려면 코드 상단에 붙여넣어야 합니다.

sine_data와는 별도로 f_peaks[]라는 배열이 전역 변수로 선언됨 . FFT 기능을 실행할 때마다 이 배열이 업데이트됩니다. 여기서 f_peaks[0]은 가장 지배적인 주파수이며 내림차순으로 추가 값입니다.

<사전><코드>바이트 사인 데이터 [91]={0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79 , 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 4, 150, 153, 4, 15 , 177, 180, 183, 186, 189, 192, 195, 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, 2, 223, 272, 3 피크 ];

사인 값을 0도에서 90도까지 저장했기 때문에 사인이나 코사인 값을 계산할 수 있습니다. 아래 함수는 소수점 이하 0까지 숫자의 첫 번째 반올림 및 저장된 데이터의 값을 반환합니다. 이 방법은 하나의 부동 분할만 필요합니다. 이것은 사인 값(255 배수 아님)을 직접 저장하여 더 줄일 수 있습니다. 하지만 이는 Arduino에서 많은 메모리를 차지합니다.

위의 절차를 사용하면 정확도는 떨어지지만 속도는 향상됩니다. 64포인트의 경우 8ms의 이점을 제공하고 128포인트의 경우 20ms의 이점을 제공합니다.

3단계:코드 설명:FFT 기능

FFT는 2, 4, 8, 16, 32, 64 등의 샘플 크기에 대해서만 수행할 수 있습니다. 값이 2^n이 아니면 값의 더 낮은 쪽을 취합니다. 예를 들어 샘플 크기를 70으로 선택하면 처음 64개 샘플만 고려하고 나머지는 생략합니다.

항상 2^n의 샘플 크기를 갖는 것이 좋습니다. 다음과 같을 수 있습니다.

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,...

두 개의 float out_r 및 out_im은 많은 양의 메모리를 사용합니다. Arduino nano의 경우 사용 가능한 메모리 부족으로 인해 128개(경우에 따라 128개)보다 높은 샘플에서는 작동하지 않습니다.

부호 없는 int 데이터[13]={1,2,4,8,16,32,64,128,256,512,1024,2048};int a,c1,f,o,x;a=N; for(int i=0;i<12;i++) //레벨 계산 { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //시퀀싱을 위한 입력float out_r[data[o]]={}; // transformfloat out_im[data[o]]={}의 실수부; //변환의 허수 부분 

추가 흐름은 다음과 같습니다.

1. 코드는 주어진 샘플 크기에 대해 역순으로 비트를 생성합니다(참조에서 비트 반전에 대한 세부사항:2단계)

2. 생성된 주문에 따라 정렬된 데이터 입력,

3. FFT 수행

4. 계산된 복소수의 진폭,

5. 피크가 감지되고 내림차순으로 정렬됩니다.

6. f_peaks[]에서 결과에 액세스할 수 있습니다.

[다른 데이터에 액세스하려면(피크 주파수 제외) 코드를 수정해야 로컬 변수를 미리 정의된 전역 변수에 복사할 수 있습니다.]

4단계:코드 테스트

샘플 삼각파가 입력으로 제공됩니다. 이 파동 샘플링 주파수는 10Hz이고 파동 자체의 주파수는 1.25Hz입니다.

원시 출력에서 ​​알 수 있듯이 값은 Scilab에서 계산한 FFT와 일치합니다. 그러나 이 값은 정확도가 낮지만 더 빠른 사인파와 정확히 동일하지 않습니다.

출력 주파수 배열에서 주파수는 1.25와 3.75입니다. 매번 정확한 값을 얻을 필요는 없습니다. 일반적으로 이러한 숫자를 주파수 빈이라고 합니다. 따라서 출력 값은 지정된 bin 내의 임의의 위치에 있을 수 있습니다.

속도:

Arduino nano의 경우:

<울>
  • 16포인트 :4ms
  • <울>
  • 32 포인트 :10ms
  • <울>
  • 64 포인트 :26ms
  • <울>
  • 128 포인트 :53ms
  • 5단계:결론

    이 FFT 코드는 실시간 애플리케이션에서 사용할 수 있습니다. 계산을 완료하는 데 약 30ms가 걸리기 때문입니다. 그러나, 그것의 해상도는 샘플의 수에 의해 제한됩니다. 샘플 수는 Arduino 메모리에 의해 제한됩니다. Arduino Mega 또는 기타 고성능 보드를 사용하여 보드 정확도를 높일 수 있습니다.

    질문, 제안 또는 수정 사항이 있으면 언제든지 의견을 말하십시오.

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • EasyFFT
  • EasyFFTArduino
    이 코드는 FFT를 수행하고 상위 5개의 가장 지배적인 주파수로 F_peasks 배열을 업데이트합니다.
    /*//Example data:int data[64]={14, 30, 35, 34, 34, 40, 46, 45, 30 , 4, -26, -48, -55, -49, -37, -28, -24, -22, -13, 6, 32, 55, 65, 57, 38, 17, 1, -6, - 11, -19, -34, -51, -61, -56, -35, -7, 18, 32, 35, 34, 35, 41, 46, 43, 26, -2, -31, -50, -55, -47, -35, -27, -24, -21, -10, 11, 37, 58, 64, 55, 34, 13, -1, -7};*///---- -------------------------------------------------- ----------------------//바이트 사인 데이터 [91]={0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79, 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 3, 53,1, 146, 150, 153, 157, 160, 164, 167, 171, 174, 177, 180, 183, 186, 189, 192, 195, //프로그램 상단에 붙여넣기198, 2, 201,9, , 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 5, 241, 243, 244, 245, 4746, 245, 8246, , 253, 253, 254, 254, 254, 255, 255, 255, 255 }; float f_peaks[5]; // 내림차순으로 상위 5개 주파수 피크 //--------------------------------------- ------------------------------------//설정 무효화() { Serial.begin(250000); } 무효 루프() {/*//exampleFFT(데이터,64,100); //100Hz에서 64개의 샘플을 갖는 X의 주파수의 상위 5개 값을 얻기 위해 샘플링Serial.println(f_peaks[0]);Serial.println(f_peaks[1]);delay(99999);*//* FFT( ), f_peaks[0],f_peaks[1],f_peaks[2],f_peaks[3],f_peaks[4],*/ }//---------------에서 사용 가능한 주파수 --------------FFT 기능----------------------------------- ------------//float FFT(int in[],int N,float Frequency){/*arduino에서 FFT를 수행하는 코드, setup:paste sine_data [91] to top of program [ 전역 변수], programTerm:1 끝에 FFT 함수를 붙여넣습니다. in[] :데이터 배열, 2. N :샘플 수(권장 샘플 크기 2,4,8,16,32,64,128...)3. 주파수:입력으로 필요한 샘플링 주파수(Hz) 샘플 크기가 2의 거듭제곱이 아닌 경우 숫자의 아래쪽으로 잘립니다. 즉, 150개 샘플의 경우 코드는 처음 128개 샘플을 고려하고 나머지 샘플은 생략됩니다. Arduino nano의 경우 128개 이상의 샘플 FFT는 mamory 제한으로 인해 불가능(64개 권장) 샘플 수가 많을수록 Mamory 관련 문제가 발생할 수 있습니다. 문제, 코드 ABHILASHContact:[email protected] 문서:https://www.instructables.com/member/abhilash_patel/instructables/2/3/2021:>=256개 샘플에 대해 N의 데이터 유형을 float에서 int로 변경* /unsigned int 데이터[13]={1,2,4,8,16,32,64,128,256,512,1024,2048};int a,c1,f,o,x;a=N; for(int i=0;i<12;i++) //레벨 계산 { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //시퀀싱을 위한 입력float out_r[data[o]]={}; // transformfloat out_im[data[o]]={}의 실수부; //변환의 허수부 x=0; for(int b=0;ba) {out_r[i]=in[in_ps[i]-a];} }int i10,i11,n1;float e,c,s,tr,ti; for(int i=0;i 여기에서 out_r은 진폭을 포함하고 our_in은 주파수(Hz)를 포함합니다. for(int i=0;iout_r[i-1] &&out_r[i]>out_r[i+1] ) {in_ps[x]=i; // 피크 수 저장에 사용되는 in_ps 배열 x=x+1;} }s=0;c=0; for(int i=0;i360){j=j-360;} if(j>-1 &&j<91){out=sine_data[j];} else if (j>90 &&j<181){out=sine_data[180-j];} else if(j>180 &&j<271){out=-sine_data[j-180];} else if(j>270 &&j<361){out=-sine_data[360-j];} return (out/255);}부동 코사인(int i){ int j=i; 떠다니다; while(j<0){j=j+360;} while(j>360){j=j-360;} if(j>-1 &&j<91){out=사인 데이터[90-j];} else if(j>90 &&j<181){out=-sine_data[j-90];} else if(j>180 &&j<271){out=-sine_data[270-j];} else if(j>270 &&j<361){out=sine_data[j-270];} return (out/255);}//---------------------- -------------------------------------------------- ----------//

    회로도


    제조공정

    1. 푸리에 변환이란 무엇입니까?
    2. Arduino만 사용하는 DTMF 디코더
    3. Arduino 알람 시스템:SERENA
    4. Python3 및 Arduino 통신
    5. 학교를 위한 SMART 온도 모니터링
    6. Arduino용 8비트 IO 포트 라이브러리
    7. Arduino용 64키 프로토타이핑 키보드 매트릭스
    8. Arduino용 절연 아날로그 입력
    9. 멋진 실내 내비게이션용 로봇
    10. 유압 펌프의 HS 코드는 무엇입니까?