Cách tạo bộ tạo sóng hình sin có thể chuyển tiếp trơn tru giữa các tần số


27

Tôi có thể viết một bộ tạo sóng hình sin cơ bản cho âm thanh, nhưng tôi muốn nó có thể chuyển đổi trơn tru từ tần số này sang tần số khác. Nếu tôi chỉ dừng tạo một tần số và ngay lập tức chuyển sang tần số khác, sẽ có một sự gián đoạn trong tín hiệu và một tiếng "click" sẽ được nghe thấy.

Câu hỏi của tôi là, một thuật toán tốt để tạo ra một sóng bắt đầu ở mức nào, giả sử là 250Hz, sau đó chuyển sang 300Hz, mà không đưa ra bất kỳ nhấp chuột nào. Nếu thuật toán bao gồm thời gian trượt / portamento tùy chọn, thì càng nhiều càng tốt.

Tôi có thể nghĩ ra một vài cách tiếp cận khả thi như quá khổ theo sau là bộ lọc thông thấp hoặc có thể sử dụng bộ lọc, nhưng tôi chắc chắn đây là một vấn đề đủ phổ biến để có cách xử lý tiêu chuẩn.


2
Tại sao bạn không sử dụng chuyển đổi tần số tuyến tính trong giai đoạn chuyển tiếp. Ví dụ: bạn cần chuyển từ tần số f0 tại thời điểm t0 sang tần số F1 tại thời điểm t1, tại sao không giới thiệu tần số chuyển tiếp f (t) = f0 * (1-q) + f1 * q, trong đó q = (t -t0) / (t1-t0), sau đó tạo ra tín hiệu A (t) = sin (2 * Pi * f (t) * t)?
mbaitoff

Câu trả lời:


24

Một cách tiếp cận mà tôi đã sử dụng trong quá khứ là duy trì bộ tích lũy pha được sử dụng làm chỉ mục trong bảng tra cứu dạng sóng. Một giá trị delta pha được thêm vào bộ tích lũy ở mỗi khoảng thời gian mẫu:

phase_index += phase_delta

Để thay đổi tần số, bạn thay đổi delta pha được thêm vào bộ tích lũy pha ở mỗi mẫu, ví dụ:

phase_delta = N * f / Fs

Ở đâu:

phase_delta is the number of LUT samples to increment
freq is the desired output frequency
Fs is the sample rate

Điều này đảm bảo rằng dạng sóng đầu ra là liên tục ngay cả khi bạn thay đổi tự động phase_delta, ví dụ như thay đổi tần số, FM, v.v.

Để thay đổi tần số mượt mà hơn (portamento), bạn có thể tăng giá trị phase_delta giữa giá trị cũ và giá trị mới qua một số khoảng thời gian mẫu thích hợp thay vì chỉ thay đổi tức thời.

Lưu ý rằng phase_indexphase_deltacả hai đều có một số nguyên và một thành phần phân số, tức là chúng cần phải là dấu phẩy động hoặc điểm cố định. Phần nguyên của phase_index (kích thước bảng modulo) được sử dụng làm chỉ mục cho dạng sóng LUT và phần phân đoạn có thể được sử dụng tùy ý để nội suy giữa các giá trị LUT liền kề cho đầu ra chất lượng cao hơn và / hoặc kích thước LUT nhỏ hơn.


cảm ơn, tôi đã mong đợi rằng câu trả lời có thể liên quan đến LUT. Tôi đã nghĩ đến việc sử dụng LUT có chứa một dạng sóng ở tần số 1Hz (tức là các mục Fs). Có quy tắc ngón tay cái nào điều chỉnh kích thước tối ưu của LUT không?

4
Nó phụ thuộc vào nhiều yếu tố khác nhau: SNR mà bạn đang tìm kiếm, cho dù đó là sóng hình sin thuần túy hay dạng sóng phức tạp hơn, cho dù bạn có kế hoạch nội suy giữa các mục LUT liền kề hay chỉ cắt ngắn, v.v. Điều đó cũng phụ thuộc vào việc bạn sẽ đến có một bảng góc phần tư duy nhất và tự xử lý số học lập chỉ mục và tự đảo ngược ký hiệu hoặc có một bảng góc phần tư đầy đủ. Cá nhân tôi sẽ bắt đầu với một điểm 1024 (NB: 2 ^ N tốt cho việc lập chỉ mục modulo) bốn bảng góc phần tư không có nội suy vì điều này rất đơn giản và sẽ cho kết quả tốt cho âm thanh "người tiêu dùng" 16 bit.
Paul R

1
Câu trả lời tốt, Paul. Cũng có một câu hỏi tương tự về chủ đề đã được đăng một lúc trước; Thêm thông tin luôn luôn giúp.
Jason R

4
Một cách khác để xem xét phương pháp này là mô phỏng bộ tạo dao động điều khiển điện áp (VCO). Tần số đầu ra của VCO phụ thuộc vào điện áp đầu vào (thường là hàm tuyến tính của điện áp đầu vào) nhưng tín hiệu đầu ra có pha liên tục ngay cả khi điện áp đầu vào chuyển đổi tức thời. Đầu ra là nơi là một hàm liên tục của thời gian, trong khi tần số đầu ra là đạo hàm của pha và bằng trong đó là tần số tĩnh.
sin(ϕ(t))=sin(0tω0+kx(τ)dτ)
ϕ(t)
ω0+kx(t)
ω0
Dilip Sarwate

1
Tôi cũng gặp vấn đề tương tự, cảm ơn vì ý tưởng tích lũy (tôi đã sử dụng tính toán trực tiếp, nó không hoạt động vì xấp xỉ): jsfiddle.net/sebpiq/p3ND5/12
sebpiq

12

Một trong những cách tốt nhất để tạo ra một sóng hình sin là sử dụng một phasor phức tạp với cập nhật đệ quy. I E

z[n+1]=z[n]Ω

Trong đó z [n] là phasor, , với là tần số góc của bộ dao động tính theo radian và là chỉ số mẫu. Cả phần thực và phần ảo của đều là sóng hình sin, chúng lệch pha 90 độ. Rất thuận tiện nếu bạn cần cả sin và cos. Một phép tính mẫu duy nhất chỉ yêu cầu 4 bội số và 4 phép cộng và rẻ hơn bất kỳ thứ gì có chứa bảng sin () cos () hoặc tra cứu. Vấn đề tiềm ẩn là biên độ có thể trôi theo thời gian do các vấn đề chính xác về số. Tuy nhiên, có một cách khá thẳng về phía trước để sửa chữa điều đó. Hãy nói rằng . Chúng ta biết rằng nên có cường độ thống nhất, nghĩa là Ω=exp(jω)ωnz[n]z[n]=a+jbz[n]

aa+bb=1

Vì vậy, chúng ta có thể kiểm tra từng lần một nếu điều đó vẫn đúng và đúng. Sự điều chỉnh chính xác sẽ là

z[n]=z[n]aa+bb

Đó là một phép tính khó xử nhưng vì rất gần với sự thống nhất, bạn có thể tính gần đúng các điều khoản với mở rộng Taylor quanh và chúng tôi nhận đượcaa+bb1/xx=1

1x3x2

vì vậy việc hiệu chỉnh đơn giản hóa thành

z[n]=z[n]3a2b22

Áp dụng hiệu chỉnh đơn giản này cứ sau vài trăm mẫu sẽ giữ cho bộ dao động ổn định mãi mãi.

Để thay đổi tần số liên tục, hệ số W cần được cập nhật tương ứng. Ngay cả một sự thay đổi không liên tục trong hệ số nhân sẽ duy trì chức năng dao động liên tục. Nếu yêu cầu tăng tần số, bản cập nhật có thể được chia thành một vài bước hoặc bạn có thể sử dụng cùng một thuật toán dao động để cập nhật hệ số nhân (vì đó cũng là một phasor phức tạp đạt được sự thống nhất).


cảm ơn vì câu trả lời này, có lẽ tôi sẽ mất một chút thời gian để hiểu đủ để biến thành một số mã thế giới thực, nhưng có vẻ như là một sự thay thế thú vị để thử.
Mark Heath

2
Tôi đã triển khai giải pháp này trong golang để tham khảo: github.com/rmichela/Acoustico/blob/ mẹo
Ryan Michela

Đây là một giải pháp đẹp mà thật không may, chỉ hoạt động tốt nếu sử dụng cơ sở thời gian không đổi. Nếu không, bạn cần tính toán một tội lỗi và một cos để tính toán xoay vòng phức tạp chính xác.
Cameron Tacklind

2

Từ trang web này :

Để tạo ra sự chuyển đổi suôn sẻ từ tần số này sang tần số khác hoặc biên độ khác, một sóng hình sin không hoàn chỉnh phải được sửa đổi với phần được nối để sóng kết quả sau mỗi lần lặp của vòng lặp while kết thúc tại trục x.

Âm thanh như nó nên làm việc.

(Trên thực tế, nếu cả hai đều được đồng bộ hóa tại trục x khi chuyển đổi, tôi cho rằng việc chuyển đổi dần dần là không cần thiết.)


1
Điều này nói rằng, hãy đợi hình sin hiện tại ở tần số hoàn thành một chu kỳ và đến rồi chuyển sang hình sin khác ở tần số . Điều này duy trì hiệu quả tính liên tục của pha và có khả năng sẽ ổn đối với các ứng dụng âm thanh trong đó độ trễ vài mili giây hoặc micro giây giữa thời gian chuyển đổi mong muốn (hiện tại) và thời gian chuyển đổi được thực hiện (khi sin của tôi hoàn thành một chu kỳ) là không hợp lý. Tuy nhiên, sự khác biệt có thể gây rắc rối trong các ứng dụng khác. Chỉ cần nhớ một hình sin là hai lần trong một chu kỳ và hãy chắc chắn chọn đúng! 0 ω 1 0ω00ω10
Dilip Sarwate

2

Tôi đồng ý với các đề xuất trước đây về việc sử dụng bộ tích lũy pha. Về cơ bản, đầu vào điều khiển là lượng tiến pha mỗi bước hoặc trên mỗi chu kỳ đồng hồ (hoặc mỗi ngắt hoặc bất cứ điều gì), do đó, việc thay đổi giá trị đó sẽ thay đổi tần số mà không bị gián đoạn trong pha. Biên độ sóng sau đó được xác định từ giá trị pha tích lũy thông qua LUT hoặc chỉ tính toán sin (theta) hoặc cos (theta).

Đây thực chất là những gì thường được gọi là Bộ tạo dao động điều khiển số (NCO) hoặc Bộ tổng hợp kỹ thuật số trực tiếp (DDS). Thực hiện tìm kiếm trên web về các thuật ngữ đó có thể sẽ mang lại nhiều hơn bạn muốn biết về lý thuyết và thực hành làm cho chúng hoạt động tốt.

Thêm một bộ tích lũy bổ sung có thể cho phép chuyển tiếp liền mạch giữa các tần số, như bạn đã đề xuất, nếu điều đó cũng mong muốn, bằng cách kiểm soát tốc độ thay đổi của giá trị trước pha. Điều này đôi khi được gọi là Phân tích vi sai kỹ thuật số, hoặc DDA.


Thông tin bổ sung tốt. Vui mừng khi thấy bạn xung quanh đây, Eric; chúng ta có thể sử dụng một Bộ trưởng Thuật toán.
Jason R

1

Thứ 1, bạn nên điều chỉnh pha bắt đầu của hình sin tần số mới sao cho nó giống với pha của hình sin trước đó tại điểm mẫu chuyển tiếp thứ nhất. Tính tần số thứ nhất và sử dụng pha của nó cho tần số thứ hai.

Tùy chọn thứ 2 có thể là chuyển đoạn d_phase từ tần số này sang tần số tiếp theo qua một số mẫu. Điều này sẽ làm sạch tính liên tục của đạo hàm 1 và cung cấp một sự lướt qua.

Tùy chọn thứ 3 có thể là sử dụng cửa sổ làm mịn, chẳng hạn như cosin nâng lên, trên tốc độ gia tốc d_phase.

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.