2012-03-09 16 views
5

Biraz sıra dışı bir sorunum var, ancak FFT'yi yeniden kodlamaktan kaçınmaya çalışıyorum. GeneldeGenel programlama: Log FFT VEYA yüksek hassasiyetli evrişim (python)

, bunu bilmek istiyorum: Ben tip float için uygulanan bir algoritma var, ama varsa operasyonların belirli seti de tanımladığımız için (örneğin karmaşık sayılar, tanımlanan her yerde işe yarar mıydı +, *, ...), bu algoritmayı bu işlemleri destekleyen başka bir türde kullanmanın en iyi yolu nedir? Pratikte bu zordur, çünkü genel olarak sayısal algoritmalar, genel olarak değil hız için yazılır. Özellikle

:
Ben çok yüksek dinamik aralığı ile değerlerle çalışıyorum ve bu yüzden günlük alanda toplama olanağı istiyorum (çoğunlukla Yetersizlik durumu önlemek için).

x = [1,2,3,4,5] 
fft_x = [ log(x_val) for x_val in fft(x) ] 

Hatta bu önemli boşalmasına neden olur:

Ne istediğim bazı serilerinin FFT günlüğüdür. Ne istiyorum vb Bunun nasıl Benim düşünce bu ilkel işlemleri tanımlayan basit LogFloat sınıfını uygulamaktı

(günlük değerlerini saklamak ve + yerine * ve logaddexp yerine + kullanmaktır ancak günlük alanında çalışır). Ardından, kayıtlı değerlerimi kullanmasına izin vererek FFT kodunu çalıştırabilirim.

x_log_float = [ LogFloat.from_float(x_val) for x_val in x ] 
fft_x_log_float = fft(x_log_float) 

Bu kesinlikle ben FFT yeniden uygulamak durumunda yapılan (ve basitçe yapılabilir:

class LogFloat: 
    def __init__(self, sign, log_val): 
     assert(float(sign) in (-1, 1)) 
     self.sign = int(sign) 
     self.log_val = log_val 
    @staticmethod 
    def from_float(fval): 
     return LogFloat(sign(fval), log(abs(fval))) 
    def __imul__(self, lf): 
     self.sign *= lf.sign 
     self.log_val += lf.log_val 
     return self 
    def __idiv__(self, lf): 
     self.sign *= lf.sign 
     self.log_val -= lf.log_val 
     return self 
    def __iadd__(self, lf): 
     if self.sign == lf.sign: 
      self.log_val = logaddexp(self.log_val, lf.log_val) 
     else: 
      # subtract the smaller magnitude from the larger 
      if self.log_val > lf.log_val: 
       self.log_val = log_sub(self.log_val, lf.log_val) 
      else: 
       self.log_val = log_sub(lf.log_val, self.log_val) 
       self.sign *= -1 
     return self 
    def __isub__(self, lf): 
     self.__iadd__(LogFloat(-1 * lf.sign, lf.log_val)) 
     return self 
    def __pow__(self, lf): 
     # note: there may be a way to do this without exponentiating 
     # if the exponent is 0, always return 1 
#  print self, '**', lf 
     if lf.log_val == -float('inf'): 
      return LogFloat.from_float(1.0) 
     lf_value = lf.sign * math.exp(lf.log_val) 
     if self.sign == -1: 
      # note: in this case, lf_value must be an integer 
      return LogFloat(self.sign**int(lf_value), self.log_val * lf_value) 
     return LogFloat(self.sign, self.log_val * lf_value) 
    def __mul__(self, lf): 
     temp = LogFloat(self.sign, self.log_val) 
     temp *= lf 
     return temp 
    def __div__(self, lf): 
     temp = LogFloat(self.sign, self.log_val) 
     temp /= lf 
     return temp 
    def __add__(self, lf): 
     temp = LogFloat(self.sign, self.log_val) 
     temp += lf 
     return temp 
    def __sub__(self, lf): 
     temp = LogFloat(self.sign, self.log_val) 
     temp -= lf 
     return temp 
    def __str__(self): 
     result = str(self.sign * math.exp(self.log_val)) + '(' 
     if self.sign == -1: 
      result += '-' 
     result += 'e^' + str(self.log_val) + ')' 
     return result 
    def __neg__(self): 
     return LogFloat(-self.sign, self.log_val) 
    def __radd__(self, val): 
     # for sum 
     if val == 0: 
      return self 
     return self + val 

Sonra fikri LogFloat s listesini oluşturur ve daha sonra FFT kullanmak olacaktır LogFloat'u, daha önce float kullanıyorum nerede kullanın, ama tavsiye isteyeceğimi düşündüm. Bu oldukça yinelenen bir sorundur: Günlük uzayda çalışmak istediğim bir stok algoritmam var (ve sadece bir kaç işlem kullanır. ',' - ',' ','/', vb).

Bu, genel işlevlerin şablonlarla yazılmasını hatırlatır, böylece geri dönüş argümanları, parametreler vb. Aynı türden oluşturulur. Örneğin, eğer bir FFT şamandıra yapabilirseniz, karmaşık değerlerde kolayca yapabilmelisiniz (sadece karmaşık değerler için gerekli işlemleri sağlayan bir sınıf kullanarak).

Şu anda olduğu gibi, tüm FFT uygulamalarının kanama hızı için yazıldığını görüyoruz ve bu yüzden çok genel olmayacak. Yani bugün itibariyle ben çok yüksek duyarlıklı helezonlar (ve N^2 çalışma zamanı istediğim için ... jenerik türleri için

bunun ne yapıyorum nedeni FFT tekrar uygulamanız gerekir gibi görünüyor son derece yavaştır). Herhangi bir tavsiye büyük takdir edilecektir.

* Not, LogFloat için trigonometrik işlevler uygulamak gerekebilir ve bu iyi olurdu.

DÜZENLEME: LogFloat değişmeli bir halka (ve LogFloat için trigonometrik fonksiyonlar uygulanmasını gerektirmez) olduğu için bu işi yapar.Bunu yapmanın en basit yolu, FFT'yi yeniden düzenlemekti, fakat @ J.F.Sebastian, FFT'yi kodlamadan kaçınan Python genel konvolüsyonunu kullanmanın bir yolunu da işaret etti (ki bu da bir DSP ders kitabını veya the Wikipedia pseudocode'u kullanarak oldukça kolaydı).

+0

Sorununuzun ne olduğundan emin değilim. Eğer fft python dilinde yazılıyorsa, o zaman yukarıdaki (idol kabiliyetli delilik) çalışmalıdır. Eğer bir c uygulamasına çağırırsa o zaman işe yaramaz, çünkü c kodu, python'un yapacağı şeyi yapmayacak c kodudur. sorusu nedir? –

+0

[genel konvolüsyon] var (http://www.math.ucla.edu/~jimc/mathnet_d/sage/reference/sage/rings/polynomial/convolution.html). "LogFloat", alt akışla başa çıkmak için en iyi yaklaşım olmayabilir. – jfs

+0

DSP ders kitaplarındaki ve öğretici web sitelerinde bulunan çok sayıda FFT, çok basit FFT kaynak kodu örnekleri sunar; genellikle yaklaşık 1 veya 2 sayfa kod. (DSP web sitemde sadece 30 ila 40 satırlık BASIC olan bir çift FFT var.) – hotpaw2

cevap

1

Ben itiraf ediyorum, tamamen senin sorudaki matematiğe ayak uydurmadım. Bununla birlikte, gerçekten de merak ettiğiniz şey, 'un, çok küçük ve büyük (mutlak değerde) sayılarla, alt akışlara ve taşmalara maruz kalmadan nasıl davranılacağına benziyorsa. Seni yanlış anlayamazsam, bence bu para birimiyle çalıştığım soruna benzer, yuvarlama nedeniyle milyar dolarlık işlemlerde pennies kaybetmemek. Durum buysa, çözümüm Python'un yerleşik ondalık matematik modülüdür. Belgeler, hem Python 2 hem de Python 3 için uygundur. Kısa versiyon, ondalık matematik, keyfi hassas bir yüzer ve sabit nokta tipi. Python modülleri, ondalık matematik için IBM/IEEE standartlarına uygundur. Python 3.3'te (şu anda alfa formundadır, fakat hiç sorun yaşamadan kullanıyorum), modül 100x hıza kadar C'ye yeniden yazılmıştır (hızlı testlerimde).

+0

Haklısın, ben aşağı akışından kaçınmaya çalışıyorum (olasılık yoğunluk fonksiyonunu hesaplamak için yoğunlukları karıştırıyorum). Şimdiye dek keyfi hassas python kütüphanesini denemek zorunda kalacağım - şimdiye kadar, her zaman havai fişek konusunda biraz emin değildim, ama hile yapsaydı çok havalı olurdu. Daha sonra bu değerleri kullanmak için bir FFT kodlamasına ihtiyacım var (float veya numpy'nin 64bit float'ı yerine). – user

+0

"Ondalık" nesneler, makine seviyesindeki 'float'lardan daha yavaştır (Python'un float'ları). Hıza duyarlıysanız ve Python 2'de takılı kalırsanız, farklı bir çözüm bulabilirim. Python 3 üzerindeyseniz veya ona geçebilirseniz, "Decimal" in C ile yazıldığı en son Python 3.3 alfa yükseltin (uygulamam hıza karşı hassastır ve 3.3'teki performanstan memnun kaldım). FFT'nin yeniden işlenmesi ile ilgili olarak - gerekli olmamalıdır. 'Ondalık' nesneleri, float'lar için drop-in değiştirmeleridir. Yay ördek yazarak! – wkschwartz

+0

Ördek yazım hakkında ne demek istediğini biliyorum. Bazı nedenlerden ötürü, çoğu fft (örneğin, numpy fft, sanırım) daha hızlı hesaplama yapmak için argümanı belirtilen bir dizi diziye dönüştürdüğünü düşündüm. Eğer numpy fft ile ördek yazabilirim biliyor musunuz? Eğer öyleyse, bu çok fazla sorun kaydeder! – user

0

Bu, daha sonra Yetersizlik önlemek için çok sayıda s göre zaman etki alanı örnekleri ölçek olabilir, ve

halinde

F (f (t)) = x (j * w)

sonra

F (sf (ler * t)) < ->X (ağırlık/s)

Şimdi kaldırmak için nihai sonucu ölçeğe nasıl çalışabilir Konvolosyon teoremi kullanılarak Ölçekleme faktörünün etkisi.

İlgili konular