0

I have a task to simulate a sequence of rectangular pulses. As a result, I wrote Python code, but the end results are not encouraging.

#!/bin/python

import numpy as np
from numpy.fft import fft
import matplotlib.pyplot as plt

A = np.random.randint(1, 6) # random amplitude (from 1 to 5)
tilda = 0.5 # pulse duration
SR = 1000 # sampling rate
t = np.linspace(0, 3, SR) # time range from 0 to 2 seconds

n_pulses = 3 # number of pulses
t_i = 0.5 # interval between pulses
pulse1_start = 0.25 # the beginning of the first pulse

rect_pulses = np.zeros_like(t)
for i in range(n_pulses):
    pulse_start = pulse1_start + i * (tilda + t_i)
    pulse_end = pulse_start + tilda
    rect_pulses = np.where((t >= pulse_start) & (t <= pulse_end), A, rect_pulses)

FFT = fft(rect_pulses) # magnitude of FFT
FFT_n = FFT / len(FFT)  # normalization
f_ax = np.linspace(0, (SR), len(FFT)) # frequency axis 
half_fft = len(FFT) // 2 # half the length of the FFT
f_half = f_ax[:half_fft] # frequencies up to f_ax / 2
FFT_half = np.abs(FFT_n[:half_fft]) # FFT module up to f_ax/2
FFT_half *= 2 # doubling the magnitude 

plt.figure(figsize=(10, 10))
plt.subplot(2, 1, 1)
plt.plot(t, rect_pulses, linewidth=1.7)
plt.title('Rect. Pulse', fontsize=21)
plt.xlabel('t', fontsize=21, fontweight='bold')
plt.ylabel('x(t)', fontsize=21, fontweight='bold')
plt.grid()
plt.subplot(2, 1, 2)
plt.plot(f_half, FFT_half, 'r-', linewidth=1.7)
plt.title('FFT of Rect. Pulse', fontsize=21)
plt.xlabel('$f$', fontsize=21, fontweight='bold')
plt.ylabel('S($f$)', fontsize=21, fontweight='bold')
plt.xlim([0,40])
plt.grid()

plt.tight_layout()
plt.show()

Rect.pulse and FFT

As you can see in the picture, the sequence turned out to be acceptable. But the spectrum didn't work out. Increasing the sampling rate doesn't help me at all. What is wrong with my code that causes such an incorrect FFT to be built?

4
  • "But the spectrum didn't work out" - You have non-zero values for values that look reasonable (3, 3*3, 3*5, 3*7 and so on) and that decrease in a way that looks reasonable as well. You joined the points, so you get a line instead of just a few points. What exactly did you expect to be different? Commented Mar 18 at 18:16
  • @ThierryLathuille I did not expect to see such a weakly sampled spectrum (as it seems to me). I was trying to increase the sampling rate SR to see how the shape of the spectrum would change. I expected that the peaks of the spectrum would be slightly rounded, due to the additional values on the sides of the values of the extremes. But it doesn't change. Is that how it should be? Commented Mar 18 at 18:39
  • In the future, don't remove your shebang or imports. Commented Mar 18 at 21:17
  • 1
    There is nothing wrong with the code. It is your expectations of what the FFT does that is wrong. If you feed it that starting shape in real space you will get the FFT in frequency space required to create it on whatever sampling grid you used to represent it. If you want higher resolution in frequency space either pad with zeroes (oversampling in the FFT jargon) or provide a much longer sample of the waveform 30 or 300 cycles to zoom in by 10x or 100x in frequency space. Question is probably better suited to signal processing than here. Commented Mar 19 at 9:10

1 Answer 1

2

Your discrete Fourier transform is defined as

enter image description here

If your f(t) function repeats 3 times in the sequence then you can rewrite this as (neglecting the small difference between N and a multiple of 3!):

enter image description here

Now, if m is a multiple of 3 then that last bracketed term is equal to 3, so this Fourier coefficient is (usually) non-zero. If m is not a multiple of 3 then it is 0 (write it out, or sum a geometric series).

Hence, with 3 repeats you would expect only the 0, 3, 6, 9, 12, 15, … frequency components to be non-zero.

But, you will say that the 6, 12, 18, … components are zero. However, this is a feature of your particular pulses. In the code below I have adapted the shape of your pulses a bit. Then you get non-zero contributions precisely when m = 0, 3, 6, 9, …

import numpy as np
import matplotlib.pyplot as plt
from numpy.fft import fft

A = 3                                                      # amplitude
SR = 1000                                                  # sample size
t = np.linspace( 0, 3, SR, endpoint=False )                # time range from 0 to 3 seconds

n_pulses = 3                                               # number of pulses
tilda = 0.5                                                # pulse duration
t_i = 0.5                                                  # interval between pulses
pulse1_start = 0.25                                        # the beginning of the first pulse

rect_pulses = np.zeros_like( t )
for i in range( n_pulses ):
    pulse_start = pulse1_start + i * ( tilda + t_i )
    pulse_end = pulse_start + tilda
    rect_pulses = np.where( ( t >= pulse_start ) & ( t <= pulse_end ), A - 2.5 * ( t - pulse_start ), rect_pulses )

FFT = fft( rect_pulses )                                   # magnitude of FFT
FFT_n = FFT / len(FFT)                                     # normalization
f_ax = np.linspace( 0, SR, len( FFT ), endpoint=False )    # frequency axis
half_fft = len(FFT) // 2                                   # half the length of the FFT
f_half = f_ax[:half_fft]                                   # frequencies up to f_ax / 2
FFT_half = np.abs(FFT_n[:half_fft])                        # FFT module up to f_ax/2
FFT_half *= 2 # doubling the magnitude 

plt.figure(figsize=(10, 10))
plt.subplot(2, 1, 1)
plt.plot(t, rect_pulses, linewidth=1.7)
plt.title('Pulses', fontsize=21)
plt.xlabel('t', fontsize=21, fontweight='bold')
plt.ylabel('x(t)', fontsize=21, fontweight='bold')
plt.grid()
plt.subplot(2, 1, 2)
plt.plot(f_half, FFT_half, 'r-', linewidth=1.7)
plt.title('FFT of Pulses', fontsize=21)
plt.xlabel('$f$', fontsize=21, fontweight='bold')
plt.ylabel('S($f$)', fontsize=21, fontweight='bold')
plt.xlim([0,40])
plt.grid()

plt.tight_layout()
plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.