2

I have two codes for an FFT but I need to merge them, because they seems to be working well in some parts. Let me explain. First code:

fft1 = (Bx[51:-14])
fft2 = (By[1:-14])

# NS antena FFT - red
FFTdata = np.sqrt(fft1*fft1)**1
samples = FFTdata.size

# WE antena FFT - blue
FFTdata2 = np.sqrt(fft2*fft2)**1
samples2 = FFTdata2.size

# Adjusting FFT variables
duration = 300 # in seconds
Fs = float(samples)/duration # sampling frequency (sample/sec)
delta_t = 1.0/Fs
t = np.arange(0, samples, 1)*delta_t
FFTdata_freq = np.abs(np.fft.rfft(FFTdata))**1
FFTdata2_freq2 = np.abs(np.fft.rfft(FFTdata2))**1
freq = np.fft.rfftfreq(samples, d=delta_t)
freq2 = np.fft.rfftfreq(samples2, d=delta_t)

# Printing data
plt.semilogy(freq, FFTdata_freq, color='r')
plt.semilogy(freq2, FFTdata2_freq2, color='b')
plt.xticks([0,20,40,60,80,100,120,140,160,180,200,220,240,260,280,300, 
320,340,360,380,400,420,440])

Second code:

# Number of samplepoints
N = 600
# sample spacing
T = 300.0 / 266336.0
x = np.linspace(0.0, N*T, N)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)
plt.plot(xf, 2.0/N * np.abs(yf[0:N/2]))

And now the problem. I have two codes for FFT, but I do not know how to make them work. Well first code shows my data correctly, on the chart you have upper draw, but the scale is wrong, I need that upper chart situated where the bottom draw is placed. I do not know how to do this. Any ideas? fft1 and fft2 are data arrays. Everything happens in 300s = 300000ms.

After changing code thanks to @zck it looks like this from scipy.signal import welch

plt.subplot(212)
plt.title('Fast Fourier Transform')
plt.ylabel('Power [a.u.]')
plt.xlabel('Frequency Hz')
fft1 = (Bx[51:-14])
fft2 = (By[1:-14])

for dataset in [fft1]:
    dataset = np.asarray(dataset)
    psd = np.abs(np.fft.fft(dataset))**2.5
    freq = np.fft.fftfreq(dataset.size, float(300)/dataset.size)
    plt.semilogy(freq[freq>0], psd[freq>0]/dataset.size**2, color='r')

for dataset2 in [fft2]:
    dataset2 = np.asarray(dataset2)
    psd2 = np.abs(np.fft.fft(dataset2))**2.5
    freq2 = np.fft.fftfreq(dataset2.size, float(300)/dataset2.size)
    plt.semilogy(freq2[freq2>0], psd2[freq2>0]/dataset2.size**2, color='b')

I applied some changes. I am only missing Hamming Window, can anybody help, to make from this chart: enter image description here

That one: enter image description here

Hiddenguy
  • 547
  • 13
  • 33

1 Answers1

2

From the quick look it appears that in the upper code snippet you're forgeting to divide by N. It's a math probelm, not a code problem.

In general, if you're after spectra/power spectra use a WOSA(=overlapped segment averaging) method that applies window functions and averages if the sample size allows it. The welch method is included in scipy.signals, you should explore the scipy.signal library as it is extremely convenient in signal analysis.

For your datasets following code should work:

from scipy.signal import welch

plt.figure()
for dataset in [Bx, By]:
    dataset = np.asarray(dataset)
    freq, psd = welch(dataset, fs=dataset.size/300, return_onesided=True)
    plt.semilogy(freq, psd/2)

Note the psd is divided by 2 for return_onesided, if False division by 2 is not required. Hope this helps to produce good looking graphs. Above plots the power spectral density. Pass an argument scaling='spectrum' in case you want power spectra instead of power spectral density.

You can also pass arguments for window functions, the default is hanning but it includes most common windows like blackman, hamming, boxcart etc.

You can find more about this at https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.signal.welch.html

zck
  • 311
  • 1
  • 3
  • I applied your changes to my question. Well you can see how it looks. You almost helped me with my problem. Your code set correct position of my chart, but it changed its appearance. What I need now is to replace this light blue and orange tiny lines with my previous dark red and blue chart. – Hiddenguy Dec 02 '17 at 15:57
  • 1
    The light blue and orange line IS the blue and red line. The reason it is not jumping is because the data has been split into overlapped segments and fft computed from these segments. If you want your data to be nonaveraged output as blue and red line, just include this in the loop: `psd2=np.abs(np.fft.fft(dataset))**2` then `freq2=np.fft.fftfreq(dataset.size, 300/dataset.size)` and `plt.semilogy(freq2, psd2)`. I am not sure what you are doing in the upper code part, as I said before, it is math/fourier transform understanding problem, not code problem – zck Dec 02 '17 at 16:25
  • I tried to implement that, but received that: Traceback (most recent call last): File "C:/Users/PycharmProjects/iotest.py", line 60, in freq2=np.fft.fftfreq(dataset.size, 300/dataset.size) File "C:\Python27\lib\site-packages\numpy\fft\helper.py", line 168, in fftfreq val = 1.0 / (n * d) ZeroDivisionError: float division by zero – Hiddenguy Dec 02 '17 at 16:29
  • 1
    Since it is ZeroDivisionError and you have it coming from `fftfreq val= 1.0/(n*d)` where `n=dataset.size` and `d=300/dataset.size` the error is in dataset variable. Make sure the previous code snippets are in the for loop I gave, or set `Bx=dataset` separately before executing the lines. – zck Dec 02 '17 at 16:40
  • I have added Bx=dataset but it didn't change anything. I'll show the whole code so you may point out where I do the wrong thing. I am new to python, so thank you for your patience. Code will appear in my question. – Hiddenguy Dec 02 '17 at 16:51
  • 1
    add four spaces in front of `psd2..`, `freq2..` and `plt.semilogy..` to include them in the for loop. right now they are outside – zck Dec 02 '17 at 16:58
  • Ok got it, but look what appeared. See Question. – Hiddenguy Dec 02 '17 at 17:01
  • And there appeared a symmetry in the chart, which I do not need. And scale again went to 10**5. The tiny green and tiny blue are on the correct 10**-1 – Hiddenguy Dec 02 '17 at 17:08
  • 1
    Now it is just basic array usage and some math. Don't forget to divide by N^2: `plt.semilogy(freq2[freq2>0], psd2[freq2>0]/dataset.size**2)` – zck Dec 02 '17 at 17:41
  • I don't get it. What divide by N2? What is that N2? Look at code I have uploaded. I left only that what you have sent. Which means, look for my Question and from "Next changes:" there is only thing I left in my code. – Hiddenguy Dec 02 '17 at 17:47
  • @ zck We are almost done. Thank you. So: 1. How to edit that plot, I would like it to look like I'll add another picture. – Hiddenguy Dec 02 '17 at 18:00
  • I chave changed the code in for loop, I have exchanged (Bx, By) to (fft1, fft2) I'll send a photo. Right now I just need to know how to delete line blue and green + how to make hamming window, like in picture which I have uploaded. – Hiddenguy Dec 02 '17 at 18:24
  • I have added some new info in the question and some photos. I think you will be able to help me with that. – Hiddenguy Dec 02 '17 at 18:30
  • So are you still eager to help with last part of code which is Hamming Window? Please see the description. – Hiddenguy Dec 02 '17 at 18:46