Я пишу пропрограмму на python, которая может приближать временные ряды по грехам. Программа использует DFT для поиска волн sin, после чего выбирает грешные волны с наибольшими амплитудами.Аппроксимация волнами sin с использованием DFT на python. Что не так?
Вот мой код:
__author__ = 'FATVVS'
import math
# Wave - (amplitude,frequency,phase)
# This class was created to sort sin waves:
# - by anplitude(set freq_sort=False)
# - by frequency (set freq_sort=True)
class Wave:
#flag for choosing sort mode:
# False-sort by amplitude
# True-by frequency
freq_sort = False
def __init__(self, amp, freq, phase):
self.freq = freq #frequency
self.amp = amp #amplitude
self.phase = phase
def __lt__(self, other):
if self.freq_sort:
return self.freq < other.freq
else:
return self.amp < other.amp
def __gt__(self, other):
if self.freq_sort:
return self.freq > other.freq
else:
return self.amp > other.amp
def __le__(self, other):
if self.freq_sort:
return self.freq <= other.freq
else:
return self.amp <= other.amp
def __ge__(self, other):
if self.freq_sort:
return self.freq >= other.freq
else:
return self.amp >= other.amp
def __str__(self):
s = "(amp=" + str(self.amp) + ",frq=" + str(self.freq) + ",phase=" + str(self.phase) + ")"
return s
def __repr__(self):
return self.__str__()
#Discrete Fourier Transform
def dft(series: list):
n = len(series)
m = int(n/2)
real = [0 for _ in range(n)]
imag = [0 for _ in range(n)]
amplitude = []
phase = []
angle_const = 2 * math.pi/n
for w in range(m):
a = w * angle_const
for t in range(n):
real[w] += series[t] * math.cos(a * t)
imag[w] += series[t] * math.sin(a * t)
amplitude.append(math.sqrt(real[w] * real[w] + imag[w] * imag[w])/n)
phase.append(math.atan(imag[w]/real[w]))
return amplitude, phase
#extract waves from time series
# series - time series
# num - number of waves
def get_waves(series: list, num):
amp, phase = dft(series)
m = len(amp)
waves = []
for i in range(m):
waves.append(Wave(amp[i], 2 * math.pi * i/m, phase[i]))
waves.sort()
waves.reverse()
waves = waves[0:num]#extract best waves
print("the program found the next %s sin waves:"%(num))
print(waves)#print best waves
return waves
#approximation by sin waves
#series - time series
#num- number of sin waves
def sin_waves_appr(series: list, num):
n = len(series)
freq = get_waves(series, num)
m = len(freq)
model = []
for i in range(n):
summ = 0
for j in range(m): #sum by sin waves
summ += freq[j].amp * math.sin(freq[j].freq * i + freq[j].phase)
model.append(summ)
return model
if __name__ == '__main__':
import matplotlib.pyplot as plt
N = 500 # length of time series
num = 2 # number of sin wawes, that we want to find
#y - generate time series
y = [2 * math.sin(0.05 * t + 0.5) + 0.5 * math.sin(0.2 * t + 1.5) for t in range(N)]
model = sin_waves_appr(y, num) #generate approximation model
## ------------------plotting-----------------
plt.figure(1)
# plotting of time series and his approximation model
plt.subplot(211)
h_signal, = plt.plot(y, label='source timeseries')
h_model, = plt.plot(model, label='model', linestyle='--')
plt.legend(handles=[h_signal, h_model])
plt.grid()
# plotting of spectre
amp, _ = dft(y)
xaxis = [2*math.pi*i/N for i in range(len(amp))]
plt.subplot(212)
h_freq, = plt.plot(xaxis, amp, label='spectre')
plt.legend(handles=[h_freq])
plt.grid()
plt.show()
Но у меня есть странный результат:
В программе я создал временную ряд из двух волн греха:
y = [2 * math.sin(0.05 * t + 0.5) + 0.5 * math.sin(0.2 * t + 1.5) for t in range(N)]
И моя программа обнаружила неправильные параметры волн sin:
программа нашла следующие 2 грех волны: [(АМФ = 0,9998029885151699, FRQ = 0,10053096491487339, фаза = 1,1411803525843616), (АМФ = 0.24800925225626422, Frq = 0.40212385965949354, фаза = 0,346757128184013)]
Я suppuse , что моя проблема - неправильное масштабирование волновых параметров, но я не уверен. Есть два места, где программа масштабируется. Первое место создания волн:
for i in range(m):
waves.append(Wave(amp[i], 2 * math.pi * i/m, phase[i]))
И второе место sclaling по оси х:
xaxis = [2*math.pi*i/N for i in range(len(amp))]
Но мой, может быть неправильным. Я пытался изменить масштабирование много раз, и он не решил мою проблему.
Что может быть неправильным с кодом?
Вам нужно использовать 'atan2' вместо' atan'. Есть, вероятно, и другие проблемы, но я не определил их с первого взгляда. – Nayuki
Я думаю, что здесь есть ошибка масштабирования. Единственное, что выделяется, это то, что вы рисуете спектр, используя создание xaxis с помощью '[2 * math.pi * i/N для i в диапазоне (len (amp))], но' N' - это длина временного ряда, а не длины амплитуд. Это, по крайней мере, устраняет некоторые несоответствия между графиком и результатами. – jszakmeister