Mục lục:

1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284: 9 bước
1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284: 9 bước

Video: 1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284: 9 bước

Video: 1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284: 9 bước
Video: PART4: FFT ANALYSIS WITH MATLAB - PHÂN TÍCH PHỔ SỐNG HÀI VÀ HỆ SỐ THD CÙNG MATLAB/SIMULINK 2024, Tháng mười một
Anonim
1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284
1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284
1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284
1024 mẫu Máy phân tích phổ FFT sử dụng Atmega1284

Hướng dẫn tương đối dễ dàng này (xét đến độ phức tạp của chủ đề này) sẽ chỉ cho bạn cách bạn có thể tạo một máy phân tích phổ 1024 mẫu rất đơn giản bằng cách sử dụng bảng mạch loại Arduino (1284 Hẹp) và máy vẽ nối tiếp. Bất kỳ loại bo mạch tương thích Arduino nào cũng được, nhưng càng có nhiều RAM thì bạn sẽ nhận được độ phân giải tần số tốt nhất. Nó sẽ cần hơn 8 KB RAM để tính FFT với 1024 mẫu.

Phân tích phổ được sử dụng để xác định các thành phần tần số chính của tín hiệu. Nhiều âm thanh (như âm thanh do một nhạc cụ tạo ra) bao gồm một tần số cơ bản và một số hài có tần số là bội số nguyên của tần số cơ bản. Máy phân tích quang phổ sẽ hiển thị cho bạn tất cả các thành phần quang phổ này.

Bạn có thể muốn sử dụng thiết lập này như một bộ đếm tần số hoặc để kiểm tra bất kỳ loại tín hiệu nào mà bạn nghi ngờ đang mang lại một số tiếng ồn trong mạch điện tử của bạn.

Chúng tôi sẽ tập trung ở đây vào phần phần mềm. Nếu bạn muốn tạo một mạch cố định cho một ứng dụng cụ thể, bạn sẽ cần phải khuếch đại và lọc tín hiệu. Việc điều chỉnh trước này hoàn toàn phụ thuộc vào tín hiệu bạn muốn nghiên cứu, tùy thuộc vào biên độ, trở kháng, tần số tối đa của nó, v.v. Bạn có thể kiểm tra

Bước 1: Cài đặt Thư viện

Chúng tôi sẽ sử dụng thư viện ArduinoFFT do Enrique Condes viết. Vì chúng tôi muốn tiết kiệm RAM nhiều nhất có thể, chúng tôi sẽ sử dụng nhánh phát triển của kho lưu trữ này cho phép sử dụng kiểu dữ liệu float (thay vì kép) để lưu trữ dữ liệu được lấy mẫu và tính toán. Vì vậy, chúng tôi phải cài đặt nó theo cách thủ công. Đừng lo lắng, chỉ cần tải xuống tệp lưu trữ và giải nén nó trong thư mục thư viện Arduino của bạn (ví dụ: trên cấu hình mặc định của Windows 10: C: / Users / _your_user_name_ / Documents / Arduino / architects)

Bạn có thể kiểm tra xem thư viện đã được cài đặt chính xác chưa bằng cách biên dịch một trong các ví dụ được cung cấp, chẳng hạn như "FFT_01.ino."

Bước 2: Biến đổi Fourier và khái niệm FFT

Cảnh báo: nếu bạn không thể nhìn thấy bất kỳ ký hiệu toán học nào, bạn có thể muốn chuyển sang Bước 3. Dù sao, nếu bạn không hiểu hết, chỉ cần xem xét kết luận ở cuối phần.

Phổ tần số thu được thông qua thuật toán Biến đổi Fourier Nhanh. FFT là một triển khai kỹ thuật số gần đúng với khái niệm toán học của Biến đổi Fourier. Theo khái niệm này khi bạn nắm được sự phát triển của tín hiệu theo một trục thời gian, bạn có thể biết biểu diễn của nó trong miền tần số, bao gồm các giá trị phức tạp (thực + ảo). Khái niệm này là tương hỗ, vì vậy khi bạn biết biểu diễn miền tần số, bạn có thể biến đổi nó trở lại miền thời gian và nhận lại tín hiệu giống hệt như trước khi biến đổi.

Nhưng chúng ta sẽ làm gì với tập hợp các giá trị phức được tính toán này trong miền thời gian? Vâng, hầu hết nó sẽ được để cho các kỹ sư. Đối với chúng tôi, chúng tôi sẽ gọi một thuật toán khác sẽ biến đổi các giá trị phức tạp này thành dữ liệu mật độ phổ: đó là giá trị cường độ (= cường độ) được liên kết với mỗi dải tần số. Số lượng dải tần sẽ giống như số lượng mẫu.

Bạn chắc chắn đã quen với khái niệm bộ chỉnh âm, giống như khái niệm này Quay lại những năm 1980 Với EQ đồ họa. Chà, chúng ta sẽ thu được cùng một loại kết quả nhưng với 1024 dải thay vì 16 và độ phân giải cường độ cao hơn nhiều. Khi bộ cân bằng cung cấp một cái nhìn toàn cầu về âm nhạc, phân tích quang phổ tốt cho phép tính toán chính xác cường độ của từng dải trong số 1024 dải.

Một khái niệm hoàn hảo, nhưng:

  1. Vì FFT là phiên bản số hóa của phép biến đổi Fourier, nên nó xấp xỉ tín hiệu số và mất một số thông tin. Vì vậy, nói một cách chính xác, kết quả của FFT nếu được chuyển đổi ngược trở lại với một thuật toán FFT đảo ngược sẽ không đưa ra chính xác tín hiệu ban đầu.
  2. Ngoài ra, lý thuyết còn coi một tín hiệu không phải là hữu hạn, nhưng đó là một tín hiệu không đổi lâu dài. Vì chúng tôi sẽ chỉ số hóa nó trong một khoảng thời gian nhất định (tức là các mẫu), một số lỗi khác sẽ được đưa ra.
  3. Cuối cùng, độ phân giải của chuyển đổi tương tự sang kỹ thuật số sẽ ảnh hưởng đến chất lượng của các giá trị được tính toán.

Trong thực tế

1) Tần số lấy mẫu (fs lưu ý)

Chúng tôi sẽ lấy mẫu một tín hiệu, tức là đo biên độ của nó, cứ sau 1 / fs giây. fs là tần số lấy mẫu. Ví dụ: nếu chúng tôi lấy mẫu ở 8 KHz, ADC (bộ chuyển đổi tương tự sang kỹ thuật số) tích hợp trên chip sẽ cung cấp phép đo sau mỗi 1/8000 giây.

2) Số lượng mẫu (ghi chú N hoặc mẫu trong mã)

Vì chúng ta cần lấy tất cả các giá trị trước khi chạy FFT, chúng ta sẽ phải lưu trữ chúng và vì vậy chúng ta sẽ giới hạn số lượng mẫu. Thuật toán FFT cần số lượng mẫu là lũy thừa của 2. Chúng ta càng có nhiều mẫu thì càng tốt nhưng nó tốn rất nhiều bộ nhớ, do đó chúng ta cũng sẽ cần nhiều hơn nữa để lưu trữ dữ liệu đã biến đổi, đó là các giá trị phức tạp. Thư viện Arduino FFT tiết kiệm một số dung lượng bằng cách sử dụng

  • Một mảng có tên "vReal" để lưu trữ dữ liệu được lấy mẫu và sau đó là phần thực của dữ liệu được chuyển đổi
  • Một mảng có tên "vImag" để lưu trữ phần ảo của dữ liệu đã chuyển đổi

Số lượng RAM cần thiết tương đương với 2 (mảng) * 32 (bit) * N (mẫu).

Vì vậy, trong Atmega1284 của chúng tôi có RAM 16 KB đẹp, chúng tôi sẽ lưu trữ tối đa N = 16000 * 8/64 = 2000 giá trị. Vì số lượng giá trị phải là lũy thừa của 2, chúng tôi sẽ lưu trữ tối đa 1024 giá trị.

3) Độ phân giải tần số

FFT sẽ tính toán các giá trị cho bao nhiêu dải tần số bằng số lượng mẫu. Các dải này sẽ trải dài từ 0 HZ đến tần số lấy mẫu (fs). Do đó, độ phân giải tần số là:

Độ phân giải = fs / N

Độ phân giải tốt hơn khi thấp hơn. Vì vậy, để có độ phân giải tốt hơn (thấp hơn), chúng tôi muốn:

  • nhiều mẫu hơn và / hoặc
  • fs thấp hơn

Nhưng…

4) fs tối thiểu

Vì chúng ta muốn xem nhiều tần số, một số tần số cao hơn nhiều so với "tần số cơ bản", chúng ta không thể đặt fs quá thấp. Trên thực tế, có định lý lấy mẫu Nyquist – Shannon buộc chúng ta phải có tần số lấy mẫu cao hơn gấp đôi tần số tối đa mà chúng ta muốn kiểm tra.

Ví dụ, nếu chúng ta muốn phân tích tất cả phổ từ 0 Hz, giả sử là 15 KHz, xấp xỉ tần số tối đa mà hầu hết con người có thể nghe rõ ràng, chúng ta phải đặt tần số lấy mẫu ở 30 KHz. Trên thực tế, các nhà điện tử thường đặt nó ở tần số tối đa là 2,5 (hoặc thậm chí 2,52) *. Trong ví dụ này, đó sẽ là 2,5 * 15 KHz = 37,5 KHz. Các tần số lấy mẫu thông thường trong âm thanh chuyên nghiệp là 44,1 KHz (ghi âm CD), 48 KHz và hơn thế nữa.

Phần kết luận:

Các điểm từ 1 đến 4 dẫn đến: chúng tôi muốn sử dụng càng nhiều mẫu càng tốt. Trong trường hợp của chúng tôi với thiết bị RAM 16 KB, chúng tôi sẽ xem xét 1024 mẫu. Chúng tôi muốn lấy mẫu ở tần số lấy mẫu thấp nhất có thể, miễn là nó đủ cao để phân tích tần số cao nhất mà chúng tôi mong đợi trong tín hiệu của mình (ít nhất là 2,5 * tần số này).

Bước 3: Mô phỏng tín hiệu

Mô phỏng một tín hiệu
Mô phỏng một tín hiệu

Đối với lần thử đầu tiên của chúng tôi, chúng tôi sẽ sửa đổi một chút ví dụ TFT_01.ino được cung cấp trong thư viện, để phân tích một tín hiệu bao gồm

  • Tần số cơ bản, được đặt thành 440 Hz (âm nhạc A)
  • Sóng hài bậc 3 ở một nửa công suất của cơ bản ("-3 dB")
  • Sóng hài thứ 5 ở 1/4 công suất của cơ bản ("-6 dB)

Bạn có thể thấy trong hình trên tín hiệu kết quả. Nó thực sự trông rất giống một tín hiệu thực mà đôi khi người ta có thể nhìn thấy trên máy hiện sóng (tôi sẽ gọi nó là "Batman") trong tình huống có một đoạn tín hiệu hình sin.

Bước 4: Phân tích tín hiệu mô phỏng - Mã hóa

0) Bao gồm thư viện

#include "arduinoFFT.h"

1. Định nghĩa

Trong phần khai báo, chúng tôi có

const byte adcPin = 0; // A0

const uint16_t mẫu = 1024; // Giá trị này LUÔN PHẢI là lũy thừa của 2 const uint16_t samplingFrequency = 8000; // Sẽ ảnh hưởng đến giá trị tối đa của bộ hẹn giờ trong timer_setup () SYSCLOCK / 8 / sampling Tần số phải là một số nguyên

Vì tín hiệu có sóng hài bậc 5 (tần số của sóng hài này = 5 * 440 = 2200 Hz) nên chúng ta cần đặt tần số lấy mẫu trên 2.5 * 2200 = 5500 Hz. Ở đây tôi chọn 8000 Hz.

Chúng tôi cũng khai báo các mảng nơi chúng tôi sẽ lưu trữ dữ liệu thô và dữ liệu được tính toán

float vReal [mẫu];

float vImag [mẫu];

2) Thuyết minh

Chúng tôi tạo một đối tượng ArduinoFFT. Phiên bản dành cho nhà phát triển của ArduinoFFT sử dụng một mẫu để chúng ta có thể sử dụng kiểu dữ liệu float hoặc double. Float (32 bit) là đủ đối với độ chính xác tổng thể của chương trình của chúng tôi.

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, mẫu, samplingFrequency);

3) Mô phỏng tín hiệu bằng cách điền vào mảng vReal, thay vì đặt nó bằng các giá trị ADC.

Ở đầu Vòng lặp, chúng tôi điền vào mảng vReal với:

float cycle = (((mẫu) * signalFrequency) / samplingFrequency); // Số chu kỳ tín hiệu mà lấy mẫu sẽ đọc

for (uint16_t i = 0; i <samples; i ++) {vReal = float ((biên độ * (sin ((i * (TWO_PI * chu kỳ)) / mẫu))))); / * Xây dựng dữ liệu với số dương và giá trị âm * / vReal + = float ((biên độ * (sin ((3 * i * (TWO_PI * chu kỳ)) / mẫu))) / 2.0); / * Xây dựng dữ liệu với các giá trị âm và dương * / vReal + = float ((biên độ * (sin ((5 * i * (TWO_PI * chu kỳ)) / mẫu))) / 4.0); / * Xây dựng dữ liệu với các giá trị âm và dương * / vImag = 0.0; // Phần ảo phải bằng 0 trong trường hợp lặp để tránh tính toán sai và tràn}

Chúng tôi thêm một số hóa của sóng cơ bản và hai sóng hài với biên độ nhỏ hơn. Hơn chúng ta khởi tạo mảng ảo với các số 0. Vì mảng này được phổ biến bởi thuật toán FFT nên chúng ta cần xóa nó một lần nữa trước mỗi lần tính toán mới.

4) Máy tính FFT

Sau đó, chúng tôi tính toán FFT và mật độ quang phổ

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward);

FFT.compute (FFTDirection:: Chuyển tiếp); / * Tính FFT * / FFT.complexToMagosystem (); / * Tính toán độ lớn * /

Thao tác FFT.windowing (…) sửa đổi dữ liệu thô vì chúng tôi chạy FFT trên một số mẫu hạn chế. Mẫu đầu tiên và mẫu cuối cùng thể hiện sự gián đoạn (không có "gì" ở một bên của chúng). Đây là một nguồn lỗi. Thao tác "mở cửa sổ" có xu hướng làm giảm lỗi này.

FFT.compute (…) với hướng "Chuyển tiếp" tính toán sự chuyển đổi từ miền thời gian sang miền tần số.

Sau đó, chúng tôi tính toán các giá trị cường độ (tức là cường độ) cho mỗi dải tần số. Mảng vReal hiện chứa đầy các giá trị cường độ.

5) Bản vẽ máy vẽ nối tiếp

Hãy in các giá trị trên máy vẽ nối tiếp bằng cách gọi hàm printVector (…)

PrintVector (vReal, (mẫu >> 1), SCL_FREQUENCY);

Đây là một chức năng chung cho phép in dữ liệu với trục thời gian hoặc trục tần số.

Chúng tôi cũng in tần số của dải có giá trị độ lớn cao nhất

float x = FFT.majorPeak ();

Serial.print ("f0 ="); Serial.print (x, 6); Serial.println ("Hz");

Bước 5: Phân tích tín hiệu mô phỏng - Kết quả

Phân tích tín hiệu mô phỏng - Kết quả
Phân tích tín hiệu mô phỏng - Kết quả

Chúng ta thấy 3 xung đột tương ứng với tần số cơ bản (f0), sóng hài thứ 3 và thứ 5, với một nửa và 1/4 cường độ f0, như mong đợi. Chúng ta có thể đọc ở trên cùng của cửa sổ f0 = 440.430114 Hz. Giá trị này không chính xác là 440 Hz, vì tất cả các lý do đã giải thích ở trên, nhưng nó rất gần với giá trị thực. Nó không thực sự cần thiết để hiển thị quá nhiều số thập phân không đáng kể.

Bước 6: Phân tích tín hiệu thực - Nối dây ADC

Phân tích tín hiệu thực - Nối dây ADC
Phân tích tín hiệu thực - Nối dây ADC

Vì chúng tôi biết cách tiến hành trên lý thuyết, chúng tôi muốn phân tích một tín hiệu thực tế.

Hệ thống dây điện rất đơn giản. Nối các mặt đất với nhau và dây tín hiệu vào chân A0 của bảng mạch của bạn thông qua một điện trở nối tiếp có giá trị từ 1 KOhm đến 10 KOhm.

Điện trở nối tiếp này sẽ bảo vệ đầu vào tương tự và tránh đổ chuông. Nó phải cao nhất có thể để tránh đổ chuông và càng thấp càng tốt để cung cấp đủ dòng điện để sạc ADC nhanh chóng. Tham khảo biểu dữ liệu MCU để biết trở kháng dự kiến của tín hiệu được kết nối tại đầu vào ADC.

Đối với bản trình diễn này, tôi đã sử dụng một bộ tạo chức năng để cấp tín hiệu hình sin có tần số 440 Hz và biên độ xung quanh 5 vôn (tốt nhất là nếu biên độ là từ 3 đến 5 vôn để ADC được sử dụng ở gần thang đo đầy đủ), thông qua một điện trở 1,2 KOhm.

Bước 7: Phân tích tín hiệu thực - Mã hóa

0) Bao gồm thư viện

#include "arduinoFFT.h"

1) Khai báo và cài đặt

Trong phần khai báo, chúng tôi xác định đầu vào ADC (A0), số lượng mẫu và tần suất lấy mẫu, giống như trong ví dụ trước.

const byte adcPin = 0; // A0

const uint16_t mẫu = 1024; // Giá trị này LUÔN PHẢI là lũy thừa của 2 const uint16_t samplingFrequency = 8000; // Sẽ ảnh hưởng đến giá trị tối đa của bộ hẹn giờ trong timer_setup () SYSCLOCK / 8 / sampling Tần số phải là một số nguyên

Chúng tôi tạo đối tượng ArduinoFFT

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, mẫu, samplingFrequency);

2) Thiết lập bộ hẹn giờ và ADC

Chúng tôi đặt bộ định thời 1 để nó quay vòng ở tần số lấy mẫu (8 KHz) và tạo ra một ngắt trên so sánh đầu ra.

void timer_setup () {

// đặt lại Timer 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, bộ định mức 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000/8) / lấy mẫuFrequency) -1; }

Và đặt ADC để nó

  • Sử dụng A0 làm đầu vào
  • Tự động kích hoạt trên mỗi bộ hẹn giờ 1 đầu ra so sánh khớp B
  • Tạo ngắt khi quá trình chuyển đổi hoàn tất

Đồng hồ ADC được đặt ở 1 MHz, bằng cách đặt trước đồng hồ hệ thống (16 MHz) bằng 16. Vì mọi chuyển đổi cần khoảng 13 đồng hồ ở quy mô đầy đủ, nên có thể đạt được chuyển đổi ở tần số 1/13 = 0,076 MHz = 76 KHz. Tần số lấy mẫu phải thấp hơn đáng kể so với 76 KHz để ADC có thời gian lấy mẫu dữ liệu. (chúng tôi chọn fs = 8 KHz).

void adc_setup () {

ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // bật ADC, muốn ngắt khi hoàn thành ADCSRA | = bit (ADPS2); // Bộ định mức 16 ADMUX = bit (REFS0) | (adcPin & 7); // thiết lập đầu vào ADC ADCSRB = bit (ADTS0) | bit (ADTS2); // Timer / Counter1 So sánh Nguồn kích hoạt Match B ADCSRA | = bit (ADATE); // bật kích hoạt tự động}

Chúng tôi khai báo trình xử lý ngắt sẽ được gọi sau mỗi lần chuyển đổi ADC để lưu trữ dữ liệu được chuyển đổi trong mảng vReal và xóa ngắt

// ISR hoàn chỉnh của ADC

ISR (ADC_vect) {vReal [resultNumber ++] = ADC; if (resultNumber == mẫu) {ADCSRA = 0; // tắt ADC}} EMPTY_INTERRUPT (TIMER1_COMPB_vect);

Bạn có thể giải thích đầy đủ về chuyển đổi ADC trên Arduino (analogRead).

3) Thiết lập

Trong chức năng thiết lập, chúng tôi xóa bảng dữ liệu ảo và gọi chức năng hẹn giờ và thiết lập ADC

zeroI (); // một hàm đặt thành 0 tất cả dữ liệu ảo - được giải thích trong phần trước

timer_setup (); adc_setup ();

3) Vòng lặp

FFT.dcRemoval (); // Loại bỏ thành phần DC của tín hiệu này vì ADC được tham chiếu đến mặt đất

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward); // Cân dữ liệu FFT.compute (FFTDirection:: Forward); // Tính FFT FFT.complexToMagosystem (); // Tính toán độ lớn // in phổ và tần số cơ bản f0 PrintVector (vReal, (mẫu >> 1), SCL_FREQUENCY); float x = FFT.majorPeak (); Serial.print ("f0 ="); Serial.print (x, 6); Serial.println ("Hz");

Chúng tôi loại bỏ thành phần DC vì ADC được tham chiếu đến mặt đất và tín hiệu được tập trung xung quanh xấp xỉ 2,5 vôn.

Sau đó, chúng tôi tính toán dữ liệu như đã giải thích trong ví dụ trước.

Bước 8: Phân tích tín hiệu thực - Kết quả

Phân tích tín hiệu thực - Kết quả
Phân tích tín hiệu thực - Kết quả

Thật vậy, chúng ta chỉ thấy một tần số trong tín hiệu đơn giản này. Tần số cơ bản được tính là 440.118194 Hz. Ở đây một lần nữa giá trị là một giá trị gần đúng với tần số thực.

Bước 9: Điều gì về một dấu hiệu xoang bị cắt?

Điều gì về một tín hiệu hình sin bị cắt?
Điều gì về một tín hiệu hình sin bị cắt?

Bây giờ, hãy tăng cường một chút ADC bằng cách tăng biên độ của tín hiệu trên 5 volt, vì vậy nó bị cắt bớt. Đừng đẩy quá nhiều để không phá hủy đầu vào ADC!

Chúng ta có thể thấy một số sóng hài xuất hiện. Cắt tín hiệu tạo ra các thành phần tần số cao.

Bạn đã thấy các nguyên tắc cơ bản của phân tích FFT trên bảng Arduino. Bây giờ bạn có thể thử thay đổi tần suất lấy mẫu, số lượng mẫu và tham số cửa sổ. Thư viện cũng thêm một số tham số để tính toán FFT nhanh hơn với độ chính xác thấp hơn. Bạn sẽ nhận thấy rằng nếu bạn đặt tần số lấy mẫu quá thấp, các cường độ được tính toán sẽ hoàn toàn sai do sự gấp khúc của quang phổ.

Đề xuất: