БПФ — фильтрация — обратное БПФ — оставшееся смещение

Я делаю следующее: выполняю БПФ / вырезаю каждую частоту выше 100 Гц в результатах БПФ / выполняю обратное БПФ.

Это работает хорошо... если исходный набор данных не имеет смещения! Если он имеет смещение, величина выходного результата повреждена.

Примеры:

Без смещения

Со смещением (и шумом)

Я даже не уверен, что могу делать то, что делаю, с математической точки зрения. Все, что я могу заметить, это то, что со смещением основная частота в два раза превышает исходную ???!!!

Есть ли у вас идеи, почему смещение изменено?

Код:

def FFT(data,time_step):
    """ 
    Perform FFT on raw data and return result of FFT (yf) and frequency axis (xf).

    """
    """
    #Test code for the manual frequency magnitude plot
    import numpy as np
    import matplotlib.pyplot as plt

    #Generate sinus waves
    x = np.linspace(0,2*np.pi,50000)   #You need enough points to be able to capture information (Shannon theorem)
    data = np.sin(x*2*np.pi*50) + 0.5*np.sin(x*2*np.pi*200)

    time_step = (x[-1]-x[0])/x.size

    list_data = FFT(data,time_step)

    x = list_data[0]
    y = list_data[1]    

    plt.figure()
    plt.xlim(0,300)
    plt.plot(x,np.abs(y)/max(np.abs(y)),'k-+')

    """    

    N_points = data.size    

    #FFT
    yf_original=np.fft.fft(data*time_step) #*dt really necessary? Better for units, probably

    #Post-pro
    #We keep only the positive part
    yf=yf_original[0:N_points/2]

    #fundamental frequency
    f1=1/(N_points*time_step)

    #Generate the frequency axis - n*f1
    xf=np.linspace(0,N_points/2*f1,N_points/2)


    return [xf, yf, yf_original]



def Inverse_FFT(data,time_step,freq_cut):

    list_data = FFT(data,time_step)

    N_points = data.size    

    #FFT data
    x = list_data[0]
    yf_full = list_data[2]

    #Look where the frequency is above freq_cut
    index = np.where(x > freq_cut)
    x_new_halfpos = x[0:index[0][0]-1]  #Contains N_points/2

    yf_new = np.concatenate((yf_full[0:index[0][0]-1], yf_full[N_points/2 +1:index[0][0]-1])) 

    #Apply inverse-fft
    y_complex = np.fft.ifft(yf_new)

    #Calculate new time_step ??!!
    N_points_new = x_new_halfpos.size *2
    f1 = x_new_halfpos[1]
    time_step_new = 1/(N_points_new*f1)

    #Create back the x-axis for plotting. The original data were distributed every time_step. Now, it is every time_step_new
    """ WARNING - It assumes that the new x_new axis is equally distributed - True ?!? """
    x_new = np.linspace(0,N_points_new*time_step_new,N_points_new/2)


    y_new = y_complex.real  / time_step_new

    return [x_new,y_new]

Пример кода сгенерированных примеров:

import numpy as np
import matplotlib.pyplot as plt

#Generate sinus waves
x = np.linspace(0,2*np.pi,50000)   #You need enough points to be able to capture information (Shannon theorem)
data = np.sin(x*2*np.pi*5) + 0.5*np.sin(x*2*np.pi*20) + 0.2*np.random.normal(x)

plt.figure()
plt.xlim(0,np.pi/4)
plt.plot(x,data)

time_step = (x[-1]-x[0])/x.size

list_data = FFT(data,time_step)

x = list_data[0]
y = list_data[1]    

plt.figure()
plt.xlim(0,30)
plt.xlabel("Frequency [Hz]")
plt.ylabel("Normalized magnitude")
plt.plot(x,np.abs(y)/max(np.abs(y)),'k-+')

#Anti-FFT
data_new = Inverse_FFT(data,time_step,100)

x_new = data_new[0]
y_new = data_new[1]
time_step_new = (x_new[-1]-x_new[0])/x_new.size

plt.figure()
plt.xlim(0,np.pi/4)
plt.plot(x_new,y_new)

list_data_new = FFT(y_new,time_step_new)

x_newfft = list_data_new[0]
y_newfft = list_data_new[1]    

plt.figure()
plt.xlim(0,30)
plt.xlabel("Frequency [Hz]")
plt.ylabel("Normalized magnitude")
plt.plot(x_newfft,np.abs(y_newfft)/max(np.abs(y_newfft)),'k-+')

Спасибо !

С уважением,

РЕДАКТИРОВАТЬ: Исправлена ​​функция:

def Anti_FFT(data,time_step,freq_cut):

    list_data = FFT(data,time_step)

    N_points = data.size    

    #FFT data
    x = list_data[0]
    yf_full = list_data[2]

    #Look where the frequency is above freq_cut
    index = np.where(x > freq_cut)
    x_new_halfpos = x[0:index[0][0]-1]  #Contains N_points/2

    #Fill with zeros
    yf_new = yf_full
    yf_new[index[0][0]:N_points/2 +1]=0
    yf_new[N_points/2 +1 :-index[0][0]]=0 #The negative part is symmetric. The last term is the 1st term of the positive part

    #Apply anti-fft
    y_complex = np.fft.ifft(yf_new)

    #Calculate the """new""" x_axis
    x_new = np.linspace(0,N_points*time_step,N_points)

    #Divide by the time_step to get the right units
    y_new = y_complex.real / time_step

    return [x_new,y_new]

person Lmecano    schedule 05.06.2015    source источник
comment
Что вы имеете в виду под смещением?   -  person Oliver Charlesworth    schedule 05.06.2015
comment
Среднее значение, представленное основной частотой. Без шума: среднее значение равно 0 => нет основной частоты => нет смещения // с шумом: среднее значение равно !=0 => основная частота существует => смещение // пример на моих реальных данных, синяя кривая : оригинал / красная кривая: изменено: fr.tinypic.com/r/5f2743/8   -  person Lmecano    schedule 05.06.2015
comment
Похоже, вам не хватает нулевой вставки в yf_new между двумя конкатенированными частями (того же размера, что и исходная последовательность). В этой системе нет Python для проверки исправления. Кстати, поскольку вы имеете дело с реальными данными, может быть проще использовать rfft.   -  person SleuthEye    schedule 05.06.2015
comment
Хорошая точка зрения. Это позволяет быть последовательным и иметь одинаковое количество точек между входом и выходом. Я заменил: yf_new = np.concatenate((yf_full[0:index[0][0]-1], yf_full[N_points/2 +1:index[0][0]-1])) на #Fill with zeros yf_new = yf_full yf_new[index[0][0]:N_points/2 +1]=0 yf_new[N_points/2 +1 + index[0][0]:]=0 К сожалению, это не решает проблему смещения :/ Спасибо   -  person Lmecano    schedule 05.06.2015
comment
Разве последняя часть не должна быть чем-то вроде yf_new[N_points/2+1:-index[0][0]) = 0, учитывая, что верхняя половина спектра является симметрией (т. е. выборки, которые вы хотите сохранить, находятся в обратном порядке в конце массива)?   -  person SleuthEye    schedule 05.06.2015
comment
Блин ! Я не знал, что это симметрично! Проблема решена, работает даже с шумом. И даже с моими данными! Большое Вам спасибо :)   -  person Lmecano    schedule 05.06.2015


Ответы (1)


ДПФ (f), назовем его F, последовательности f из N (четных) вещественных значений обладает следующими свойствами:

F (0) (смещение постоянного тока) - действительное число.

F(N/2) — действительное число, амплитуда частоты Найквиста. Для i в [1..N/2-1] это тот случай, когда F[N/2+i]* = F[N/2-i], где '*' означает комплексно-сопряженное число.

Ваши манипуляции с F должны сохранять эти свойства.

К вашему сведению, существуют специальные процедуры для входных данных с действительным значением, которые используют эту симметрию для вычисления БПФ и iFFT почти в два раза быстрее, чем их обычные аналоги для сложных данных.

person Jive Dadson    schedule 24.12.2016