Frekanslar arasında sorunsuz geçiş yapabilen bir sinüs dalgası jeneratörü nasıl oluşturulur


27

Ses için basit bir sinüs dalgası jeneratörü yazabiliyorum, ancak bir frekanstan diğerine düzgün bir şekilde geçebilmesini istiyorum. Eğer sadece bir frekans oluşturmayı bırakıp hemen diğerine geçersem, sinyalde bir kesilme olur ve bir "klik" duyulur.

Benim sorum şu ki, herhangi bir tıklama yapmadan, 250Hz'de başlayan ve sonra da 300Hz'e geçiş yapan bir dalga üretmek için iyi bir algoritma. Algoritma isteğe bağlı bir kayma / portamento zamanı içeriyorsa, o zaman çok daha iyi.

Aşırı örnekleme ve ardından düşük geçiş filtresi gibi birkaç olası yaklaşım düşünebilirim, ya da bir dalgalı elek kullanarak, ancak bunun standart bir mücadele yöntemi olmasının yeterince yaygın bir sorun olduğuna eminim.


2
Neden geçiş dönemi boyunca doğrusal frekans geçişini kullanmadınız? Örneğin, t0 sırasındaki f0 frekansından t1 sırasındaki f1 frekansına, o zaman neden sadece bir f (t) = f0 * (1-q) + f1 * q geçiş frekansı eklememelisiniz, burada q = (t -t0) / (t1-t0), sonra A (t) = sin (2 * Pi * f (t) * t) sinyalini üretin?
mbaitoff

Yanıtlar:


24

Geçmişte kullandığım bir yaklaşım, bir dalga formu arama tablosunda bir indeks olarak kullanılan bir faz akümülatörünü muhafaza etmektir. Akümülatöre her numune aralığında bir faz delta değeri eklenir:

phase_index += phase_delta

Frekansı değiştirmek için, her numunedeki faz akümülatörüne eklenen faz deltasını değiştirirsiniz;

phase_delta = N * f / Fs

nerede:

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

Bu, örneğin frekans değişiklikleri, FM, vs. için phase_delta'yı dinamik olarak değiştirseniz bile, çıkış dalga formunun sürekli olduğunu garanti eder.

Frekanstaki (portamento) daha yumuşak değişiklikler için, faz_delta değerini eski değeri ile yeni değeri arasında, yalnızca anında değiştirmek yerine, uygun sayıda örnek aralığının üzerinde yükseltebilirsiniz.

Not, phase_indexve phase_deltaher ikisi de, bir tamsayı ve kesirli bileşeni bu nokta veya sabit kayan nokta olması gerekir, yani. Phase_index (modulo tabla büyüklüğü) tamsayı kısmı, LUT dalga formunun bir indeksi olarak kullanılır ve fraksiyonel kısım isteğe bağlı olarak daha yüksek kaliteli çıktı için ve / veya daha küçük LUT büyüklüğü için bitişik LUT değerleri arasındaki enterpolasyon için kullanılabilir.


teşekkürler, cevabın LUTS içerebileceğini bekliyordum. 1 Hz'de bir dalga formu içeren bir LUT ile gitmeyi düşünüyordum (örn. Fs girişleri). AÜD'ün optimal boyutunu yöneten bir kural vardır mı?

4
Bu, çeşitli faktörlere bağlıdır: Ne aradığınız SNR, saf sinüs dalgası mı yoksa daha karmaşık bir dalga formu mu, bitişik LUT girişleri arasında enterpolasyon yapmayı mı planlıyorsunuz, yoksa sadece kesiliyor mu, vb. Tek bir kadranlı tabloya sahip ve indeksleme aritmetiğini kullan ve kendin yap işareti oluştur Şahsen ben 1024 puan (NB: 2 ^ N modulo indeksleme için iyidir) ile dört kadranlı bir tablo ile başlayacağım, çünkü bu çok basit ve örneğin 16 bit "tüketici" sesi için iyi sonuçlar vermeli.
Paul R

1
İyi cevap Paul. Bir süre önce gönderilmiş olan konuda da benzer bir soru var; daha fazla bilgi her zaman yardımcı olur.
Jason R,

4
Bu yaklaşıma bakmanın başka bir yolu, voltaj kontrollü bir osilatörün (VCO) öykünmesidir. Bir VCO'nun çıkış frekansı giriş voltajına bağlıdır (genellikle giriş voltajının doğrusal bir işlevidir), ancak giriş voltajı anında değişse bile çıkış sinyali sürekli faza sahiptir . Çıkış burada olan sürekli bir zaman fonksiyonu, çıkış frekansı fazın türevi iken ve ye , burada frekansıdır.
sin(ϕ(t))=sin(0tω0+kx(τ)dτ)
ϕ(t)
ω0+kx(t)
ω0
Dilip Sarwate

1
Aynı problemi yaşadım, biriktirici fikri için teşekkürler (yaklaşık hesaplamalar yüzünden işe yaramayan doğrudan hesaplama kullanıyordum): jsfiddle.net/sebpiq/p3ND5/12
sebpiq

12

Sinüs dalgası yaratmanın en iyi yollarından biri, yinelemeli güncellemeli karmaşık bir fazör kullanmaktır. yani

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

Z, [n] fazör olduğu, ile radyan osilatör ve açısal frekansı olan örnek endeksi. in hem gerçek hem de hayali kısmı sinüs dalgalarıdır, 90 derece faz dışıdırlar. Hem sinüs hem de kosinüs ihtiyacınız varsa çok kullanışlıdır. Tek bir örnek hesaplaması sadece 4 kat ve 4 ek gerektiriyor ve sin () cos () veya arama tablolarını içeren her şeyden çok daha ucuz. Potansiyel problem, sayısal hassasiyet sorunları nedeniyle genliğin zamanla kaymasıdır. Ancak bunu onarmak için oldukça yalındır. Diyelim ki . birlik büyüklüğüne sahip olması gerektiğini biliyoruz.Ω=exp(jω)ωnz[n]z[n]=a+jbz[n]

aa+bb=1

Bu yüzden arada bir kontrol edebiliriz, eğer durum hala geçerliyse ve buna göre düzelirse. Tam düzeltme olacaktır

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

Yani garip bir hesaplamadır ancak o zamandan beri çok yakın birlik Sizin tahmin edebilirsiniz olan etrafında Taylor açılımı ile terimleri ve biz almakaa+bb1/xx=1

1x3x2

bu yüzden düzeltme kolaylaştırır

z[n]=z[n]3a2b22

Her birkaç yüz örnekte bu basit düzeltmeyi uygulamak, osilatörü sonsuza kadar sabit tutacaktır.

Frekansı sürekli değiştirmek için çarpanın W uygun şekilde güncellenmesi gerekir. Çarpanda sürekli olmayan bir değişiklik bile sürekli bir osilatör işlevini sürdürecektir. Frekans rampası gerekliyse güncelleme ya birkaç adıma bölünebilir ya da çarpanın kendisini güncellemek için aynı osilatör algoritmasını kullanabilirsiniz (çünkü aynı zamanda bir birlik kazanç kompleksi fazeridir).


Bu cevap için teşekkürler, bazı gerçek dünya koduna dönüşecek kadar iyi anlamak için beni biraz zaman alacak, ama denemek için ilginç bir alternatif gibi görünüyor.
Mark Heath,

2
: Ben başvuru için golang bu çözümü hayata github.com/rmichela/Acoustico/blob/...
Ryan Michela

Bu ne yazık ki, sadece sabit bir zaman tabanı kullanıyorsanız işe yarayan güzel bir çözüm. Değilse, doğru karmaşık dönüşü hesaplamak için bir günah ve cos hesaplamanız gerekir.
Cameron Tacklind

2

Gönderen bu site :

Bir frekanstan diğerine veya bir genlikten diğerine pürüzsüz bir geçiş oluşturmak için, tamamlanmamış bir sinüs dalgası ekli bir bölümle değiştirilmelidir, böylece while döngüsünün her yinelemesinden sonra ortaya çıkan dalga x ekseninde sona erer.

İşe yarayacak gibi geliyor.

(Aslında, ikisi de geçiş sırasında x ekseninde senkronize edilmişse, aşamalı bir geçiş gerekli olmadığını varsayalım.)


1
Bu, bir döngüyü tamamlamak için frekansındaki mevcut sinüzoitin ve geldiğini ve sonra frekansındaki diğer sinüzoide . Bu, fazın sürekliliğini etkin bir şekilde sürdürür ve birkaç milisaniyenin veya mikrosaniyenin istenen anahtarlama zamanı (şimdi) ve uygulanan anahtarlama zamanı (sinüzoidim bir döngüyü tamamladığında) arasında gecikme olduğu ses uygulamaları için uygun değildir. Ancak, fark diğer uygulamalarda sorun yaratabilir. Unutmayın, bir sinüsoid bir döngüde iki kere ve doğru olanı seçtiğinizden emin olun! 0 ω 1 0ω00ω10
Dilip Sarwate

2

Faz akümülatörü kullanmanın önceki önerilerine katılıyorum. Temel olarak kontrol girişi, adım başına veya saat periyodu başına (veya kesinti veya her neyse) faz ilerlemesi miktarıdır, böylece bu değerin değiştirilmesi, fazdaki bir kesinti olmadan frekansı değiştirir. Daha sonra dalga genliği, bir LUT veya sadece günah (teta) veya cos (teta) hesaplaması yoluyla birikmiş faz değerinden belirlenir.

Bu esasen Sayısal Kontrollü Osilatör (NCO) veya Doğrudan Dijital Sentezleyici (DDS) olarak bilinen şeydir. Bu terimlerle ilgili bir web taraması yapmak muhtemelen onları iyi çalışmasını sağlayan teori ve pratik hakkında bilmek istediğinizden daha fazlasını sağlayacaktır.

Ek bir akümülatör eklemek, eğer istenirse, faz avans değerindeki değişim oranını kontrol ederek, önerildiği gibi, frekanslar arasında kesintisiz geçişlere izin verebilir. Bu bazen bir Dijital Diferansiyel Analizörü veya DDA olarak adlandırılır.


Ek bilgi iyi. Seni burada gördüğüme sevindim, Eric; bir algoritma bakanı kullanabiliriz.
Jason R

1

1. dereceden, yeni frekanslı sinüzoitin başlangıç ​​aşamasını, ilk geçiş örnek noktasında önceki sinüzoit fazınınki ile aynı olacak şekilde ayarlamanız gerekir. İlk frekansı hesaplayın ve fazını ikinci frekans için kullanın.

2. seçenek, d_phase 'ı bir frekanstan diğerine birkaç örnek üzerinde rampa etmek olabilir. Bu, 1. türevin sürekliliğini temizler ve bir kayma sağlar.

Üçüncü seçenek d_phase rampa hızında bir kosinüs gibi bir yumuşatma penceresi kullanmak olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.