pythonsignal-processingsagediscretization

desired frequency in discrete fourier transform gets shifted by the factor of increasing sample duration


I have written a python script to compute DFT of a simple sin wave having frequency 3. I have taken the following consideration for taking sample of the sin wave

sin function for test = sin( 2 * pi * 3 * t )

sample_rate = 15

time interval = 1/sample_rate = 1/15 = ~ 0.07 second

sample_duration = 1 second (for test1) and 2 seconds (for test 2)

sample_size = sample_rate * sample_duration = 15*2 = 30 samples

I run the same code for sample_duration both 1 and 2 seconds. When sample duration is 1 second, the graph produce shows the presence of frequency=3 present in the sin wave,which is correct.

frequency peak at 3

But if I change the sample duration to 2 second, the graph peaks at frequency= 6, which does not present in the sin wave.But it is a factor of 2 increase of the original frequency (3*2) = 6.

frequency peak at 6

And if 3 second is taken as sample duration, graph peaks at 9 second.

I was thinking that taking more sample for longer duration will produce finer result, but that is clearly not the case here.

code :

from sage.all import *
import matplotlib.pyplot as plt
import numpy as np

t = var('t')

sample_rate = 15 # will take 100 sample each second
interval = 1 / sample_rate # time interval between each reading
sample_duration = 1 # take sample over a duration of 1 second
sample_size_N = sample_rate*sample_duration #count number of touples in r array, len(r) will give sample size/ total number of sample taken over a specific duration

func = sin(3*2*pi*t)

time_segment_arr = []
signal_sample_arr= []

# take reading each time interval over sample_duration period 
for time_segment in np.arange(0,sample_duration,interval):
    
    # give discrete value of the signal over specific time interval
    discrete_signal_value = func(t = time_segment)
    # push time value into array
    time_segment_arr.append(time_segment) 
    # push signal amplitude into array
    signal_sample_arr.append(N(discrete_signal_value)) 
    
def construct_discrete_transform_func():
    s = ''
    k = var('k')
    for n in range(0,sample_size_N,1):
        s = s+ '+'+str((signal_sample_arr[n])* e^(-(i*2*pi*k*n)/sample_size_N))
    return  s[1:] #omit the forward + sign

dft_func = construct_discrete_transform_func()

def calculate_frequency_value(dft_func,freq_val):
    k = var('k') 
    
    # SR converts string to sage_symbolic_ring expression & fast_callable() allows   to pass variable value to that expression
    ff = fast_callable(SR(dft_func), vars=[k])
    return ff(freq_val)

freq_arr = []
amplitude_arr = []
#compute frequency strength per per frequency 
for l in np.arange(0,sample_size_N,1):
    freq_value = calculate_frequency_value(dft_func,l) 
    freq_arr.append(l)
    amplitude_arr.append(N(abs(freq_value)))

Solution

  • your Frequency axis is wrong, the lowest frequency on the DFT axis should be 1/N which can be translated to time domain to be 1/T, that is when the total time is 2 seconds, the first point after zero will be at 0.5 Hz not 1 Hz

    the longest sine wave a DFT can represent (the lowest frquency) is a sine wave that does 1 cycle over the entire duration. (k = 1), you can get 1/T from

    enter image description here

    substituting t = n * Ts. (where Ts is the sample interval) then Ts = T/N where T is the total time

    enter image description here

    which results in f = k / T and the lowest frequency k = 1 translates to f = 1 / T

    this is just a plotting error, in the not-shown plotting code.