Phân tích âm thanh bằng Fast Fourier Transform


109

Tôi đang cố gắng tạo một bộ phân tích phổ đồ họa trong python.

Tôi hiện đang đọc 1024 byte của luồng âm thanh tốc độ mẫu 16 bit kênh đôi 44.100 Hz và tính trung bình biên độ của 2 kênh với nhau. Vì vậy, bây giờ tôi có một mảng 256 quần short đã ký. Bây giờ tôi muốn định dạng trước một fft trên mảng đó, sử dụng một mô-đun như numpy và sử dụng kết quả để tạo bộ phân tích phổ đồ họa, bắt đầu sẽ chỉ là 32 thanh.

Tôi đã đọc các bài viết trên wikipedia về Biến đổi Fourier nhanh và Biến đổi Fourier rời rạc nhưng tôi vẫn chưa rõ mảng kết quả đại diện cho điều gì. Đây là mảng trông như thế nào sau khi tôi định dạng trước một fft trên mảng của mình bằng cách sử dụng numpy:

   [ -3.37260500e+05 +0.00000000e+00j   7.11787022e+05 +1.70667403e+04j
   4.10040193e+05 +3.28653370e+05j   9.90933073e+04 +1.60555003e+05j
   2.28787050e+05 +3.24141951e+05j   2.09781047e+04 +2.31063376e+05j
  -2.15941453e+05 +1.63773851e+05j  -7.07833051e+04 +1.52467334e+05j
  -1.37440802e+05 +6.28107674e+04j  -7.07536614e+03 +5.55634993e+03j
  -4.31009964e+04 -1.74891657e+05j   1.39384348e+05 +1.95956947e+04j
   1.73613033e+05 +1.16883207e+05j   1.15610357e+05 -2.62619884e+04j
  -2.05469722e+05 +1.71343186e+05j  -1.56779748e+04 +1.51258101e+05j
  -2.08639913e+05 +6.07372799e+04j  -2.90623668e+05 -2.79550838e+05j
  -1.68112214e+05 +4.47877871e+04j  -1.21289916e+03 +1.18397979e+05j
  -1.55779104e+05 +5.06852464e+04j   1.95309737e+05 +1.93876325e+04j
  -2.80400414e+05 +6.90079265e+04j   1.25892113e+04 -1.39293422e+05j
   3.10709174e+04 -1.35248953e+05j   1.31003438e+05 +1.90799303e+05j...

Tôi đang tự hỏi chính xác những con số này đại diện cho điều gì và làm thế nào tôi sẽ chuyển những con số này thành phần trăm chiều cao cho mỗi thanh trong số 32 thanh. Ngoài ra, tôi có nên tính trung bình của 2 kênh với nhau không?

Câu trả lời:


209

Mảng bạn đang hiển thị là hệ số Biến đổi Fourier của tín hiệu âm thanh. Các hệ số này có thể được sử dụng để lấy nội dung tần số của âm thanh. FFT được xác định cho các hàm đầu vào có giá trị phức tạp, vì vậy các hệ số bạn lấy ra sẽ là số ảo mặc dù đầu vào của bạn là tất cả các giá trị thực. Để có được lượng công suất trong mỗi tần số, bạn cần tính độ lớn của hệ số FFT cho mỗi tần số. Đây không chỉ là thành phần thực của hệ số, bạn cần tính căn bậc hai của tổng bình phương các thành phần thực và ảo của nó. Nghĩa là, nếu hệ số của bạn là a + b * j, thì độ lớn của nó là sqrt (a ^ 2 + b ^ 2).

Khi bạn đã tính toán độ lớn của mỗi hệ số FFT, bạn cần phải tìm ra tần số âm thanh mà mỗi hệ số FFT thuộc về. FFT điểm N sẽ cung cấp cho bạn nội dung tần số của tín hiệu tại N tần số cách đều nhau, bắt đầu từ 0. Vì tần số lấy mẫu của bạn là 44100 mẫu / giây. và số điểm trong FFT của bạn là 256, khoảng cách tần số của bạn là 44100/256 = 172 Hz (xấp xỉ)

Hệ số đầu tiên trong mảng của bạn sẽ là hệ số tần số 0. Về cơ bản đó là mức công suất trung bình cho tất cả các tần số. Phần còn lại của các hệ số của bạn sẽ được tính từ 0 theo bội số của 172 Hz cho đến khi bạn đạt đến 128. Trong FFT, bạn chỉ có thể đo tần số lên đến một nửa điểm mẫu của mình. Đọc những liên kết trên các tần số NyquistNyquist-Shannon lấy mẫu Định lý nếu bạn là người ham ăn mê cho sự trừng phạt và cần phải biết tại sao, nhưng kết quả cơ bản là tần số thấp hơn của bạn sẽ được sao chép hoặc bí danh trong xô tần số cao hơn. Vì vậy, các tần số sẽ bắt đầu từ 0, tăng 172 Hz cho mỗi hệ số lên đến hệ số N / 2, sau đó giảm 172 Hz cho đến khi hệ số N - 1.

Đó sẽ là đủ thông tin để bạn bắt đầu. Nếu bạn muốn một phần giới thiệu dễ tiếp cận hơn về FFT so với những gì được cung cấp trên Wikipedia, bạn có thể thử Tìm hiểu về xử lý tín hiệu kỹ thuật số: 2nd Ed. . Nó rất hữu ích cho tôi.

Vì vậy, đó là những gì những con số đại diện. Việc chuyển đổi thành phần trăm chiều cao có thể được thực hiện bằng cách chia độ lớn của từng thành phần tần số bằng tổng của tất cả các cường độ thành phần. Mặc dù, điều đó sẽ chỉ cung cấp cho bạn một đại diện của phân phối tần số tương đối chứ không phải công suất thực tế cho mỗi tần số. Bạn có thể thử chia tỷ lệ bằng độ lớn tối đa có thể cho một thành phần tần số, nhưng tôi không chắc rằng điều đó sẽ hiển thị rất tốt. Cách nhanh nhất để tìm ra hệ số tỷ lệ khả thi là thử nghiệm trên các tín hiệu âm thanh to và nhẹ để tìm ra cài đặt phù hợp.

Cuối cùng, bạn nên tính trung bình của hai kênh với nhau nếu bạn muốn hiển thị nội dung tần số của toàn bộ tín hiệu âm thanh nói chung. Bạn đang trộn âm thanh nổi thành âm thanh đơn âm và hiển thị các tần số kết hợp. Nếu bạn muốn có hai màn hình riêng biệt cho các tần số phải và trái, thì bạn sẽ cần thực hiện Biến đổi Fourier trên từng kênh riêng biệt.


1
Tôi hầu như chỉ có thể tìm thấy những lời giải thích quá phức tạp về FFT trên mạng, đây là một lời giải thích tuyệt vời và đơn giản về cách số lượng điểm được lấy mẫu ảnh hưởng đến kết quả của FFT. Cảm ơn vì điều này!
echolocation

26

Mặc dù chủ đề này đã cũ, tôi thấy nó rất hữu ích. Tôi chỉ muốn cung cấp ý kiến ​​đóng góp của mình cho bất kỳ ai tìm thấy điều này và đang cố gắng tạo ra thứ gì đó tương tự.

Đối với việc phân chia thành các thanh, điều này không nên được thực hiện như antti đề xuất, bằng cách chia đều dữ liệu dựa trên số lượng thanh. Điều hữu ích nhất sẽ là chia dữ liệu thành các phần quãng tám, mỗi quãng tám sẽ gấp đôi tần số của phần trước. (tức là. 100hz là một quãng tám trên 50hz, là một quãng tám trên 25hz).

Tùy thuộc vào số lượng thanh bạn muốn, bạn chia toàn bộ phạm vi thành các phạm vi 1 / X quãng tám. Dựa trên tần số trung tâm nhất định của A trên thanh, bạn nhận được giới hạn trên và giới hạn dưới của thanh từ:

upper limit = A * 2 ^ ( 1 / 2X )
lower limit = A / 2 ^ ( 1 / 2X )

Để tính toán tần số trung tâm liền kề tiếp theo, bạn sử dụng một phép tính tương tự:

next lower =  A / 2 ^ ( 1 / X )
next higher = A * 2 ^ ( 1 / X )

Sau đó, bạn lấy trung bình dữ liệu phù hợp với các phạm vi này để lấy biên độ cho mỗi thanh.

Ví dụ: Chúng tôi muốn chia thành các phạm vi 1/3 quãng tám và chúng tôi bắt đầu với tần số trung tâm là 1khz.

Upper limit = 1000 * 2 ^ ( 1 / ( 2 * 3 ) ) = 1122.5
Lower limit = 1000 / 2 ^ ( 1 / ( 2 * 3 ) ) =  890.9

Với 44100hz và 1024 mẫu (43hz giữa mỗi điểm dữ liệu), chúng ta nên tính trung bình các giá trị từ 21 đến 26. (890,9 / 43 = 20,72 ~ 21 và 1122,5 / 43 = 26,10 ~ 26)

(Các thanh 1/3 quãng tám sẽ giúp bạn có khoảng 30 thanh từ ~ 40hz đến ~ 20khz). Như bạn có thể hình dung ngay bây giờ, khi chúng ta đi lên cao hơn, chúng ta sẽ tính trung bình một dải số lớn hơn. Các thanh thấp thường chỉ bao gồm 1 hoặc một số lượng nhỏ các điểm dữ liệu. Trong khi các thanh cao hơn có thể là giá trị trung bình của hàng trăm điểm. Lý do là 86hz là một quãng tám trên 43hz ... trong khi 10086hz âm thanh gần giống như 10043hz.


10

những gì bạn có là một mẫu có độ dài thời gian là 256/44100 = 0,00580499 giây. Điều này có nghĩa là độ phân giải tần số của bạn là 1 / 0,00580499 = 172 Hz. 256 giá trị bạn nhận được từ Python tương ứng với các tần số, về cơ bản, từ 86 Hz đến 255 * 172 + 86 Hz = 43946 Hz. Các số bạn lấy ra là số phức (do đó có chữ "j" ở cuối mỗi số thứ hai).

ĐÃ CHỈNH SỬA: THÔNG TIN SAI CỐ ĐỊNH

Bạn cần chuyển các số phức thành biên độ bằng cách tính sqrt (i 2 + j 2 ) trong đó i và j là phần thực và phần ảo, tương ứng.

Nếu bạn muốn có 32 vạch, theo như tôi hiểu, bạn nên lấy giá trị trung bình của bốn biên độ liên tiếp, nhận được 256/4 = 32 vạch như bạn muốn.


4
Xin lưu ý rằng, nếu c là một số phức tạp, sqrt (c.real 2 + c.imag 2) == abs (c)
tzot

0

FFT trả về N giá trị phức tạp mà bạn có thể tính toán module=sqrt(real_part^2+imaginary_part^2). Để có được giá trị cho mỗi dải, bạn phải tính tổng các mô-đun về tất cả các hài bên trong dải. Dưới đây, bạn có thể xem một ví dụ về máy phân tích quang phổ 10 vạch. Mã c phải được gói để có được mô-đun pyd python.

float *samples_vett;
float *out_filters_vett;
int Nsamples;
float band_power = 0.0;
float harmonic_amplitude=0.0;
int i, out_index;

out_index=0;


for (i = 0; i < Nsamples / 2 + 1; i++)       
        {
            if (i == 1 || i == 2 || i == 4 || i == 8 || i == 17 || i == 33 || i == 66 || i == 132 || i == 264 || i == 511)
            {
                out_filters_vett[out_index] = band_power; 
                band_power = 0; 
                out_index++;  
            }

            harmonic_amplitude = sqrt(pow(ttfr_out_vett[i].r, 2) + pow(ttfr_out_vett[i].i, 2));
            band_power += harmonic_amplitude;

        }

Tôi đã thiết kế và tạo toàn bộ máy phân tích quang phổ 10 thanh dẫn bằng Python. Thay vì sử dụng thư viện nunmpy (quá lớn và vô dụng để chỉ có FFT), một mô-đun pyd python (chỉ 27KB) để lấy FFT và chia toàn bộ phổ âm thanh thành các dải đã được tạo.

Ngoài ra, để đọc âm thanh đầu ra, mô-đun pyd WASapi portaudio loopback đã được tạo. Bạn có thể thấy dự án (sơ đồ khối) trong hình ảnh 10BarsSpectrumAnalyzerWithWASapi.jpg

Vừa thêm một video hướng dẫn trên kênh YouTube của tôi: cách thiết kế và tạo một Thanh Led phân tích quang phổ Python 10 rất thông minh

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.