Search code examples
pythonarraysnumpytrigonometrylinspace

Numpy Sinus Behavior for different arrays


Hello depending on the array I put into sinus I get a completely different output. test1, test3 are examples where it is not working. What's going on here?

test1 = np.sin(50.*2.*np.pi*np.arange(0., 512., dtype=np.float64))
test2 = np.sin(50.*2.*np.pi*np.linspace(0., 512., 512, endpoint=True, dtype=np.float64))
test3 = np.sin(50.*2.*np.pi*np.linspace(0., 512., 512, endpoint=False, dtype=np.float64))

plt.plot(np.arange(0, 512), test1)
plt.plot(np.arange(0, 512), test2)
plt.plot(np.arange(0, 512), test3)
plt.show()

Edit: Ok after doing some further research, here is the actual problem: Using test1 and test3 I violate the Nyquist Theorem and sample only values around zero. To resolve this issue one needs to increase either the sampling rate or decrease the frequency.


Solution

  • I think the short answer is that you expect numpy.sin to take in the angle in degrees as the argument but the documentation specifies that it takes in radians.

    It looks like the numbers are being plotted as expected. One way to visualize all three plots i.e. test1, test2 and test3 is to use subplots:

    import numpy as np
    import matplotlib.pyplot as plt
    
    test1 = np.sin(50.*2.*np.pi*np.arange(0., 512., dtype=np.float64))
    test2 = np.sin(50.*2.*np.pi*np.linspace(0., 512., 512, endpoint=True, dtype=np.float64))
    test3 = np.sin(50.*2.*np.pi*np.linspace(0., 512., 512, endpoint=False, dtype=np.float64))
    
    fig, axs = plt.subplots(3, sharex=True, sharey=True, gridspec_kw={'hspace': 0})
    
    axs[0].plot(np.arange(0, 512), test1)
    axs[1].plot(np.arange(0, 512), test2)
    axs[2].plot(np.arange(0, 512), test3)
    plt.show()
    

    When you do the following:

    print(f"Max of test1: {max(test1)}\nMin of test1: {min(test1)}")
    print(f"Max of test2: {max(test2)}\nMin of test2: {min(test2)}")
    print(f"Max of test3: {max(test3)}\nMin of test3: {min(test3)}")
    

    Output

    Max of test1: 1.4412955306804755e-11
    Min of test1: -1.2978086425591747e-11
    Max of test2: 0.9999952753720377
    Min of test2: -0.9999952753719793
    Max of test3: 1.4412955306804755e-11
    Min of test3: -1.2978086425591747e-11
    

    Possible Solution

    The issue to me looks like the y limits on the graph are between -1 to 1 which is too high to visualize test1 and test3 (legibly). If you want to look at test1 and test3 in more detail (on the graph) you can do this:

    test1 = np.sin(50.*2.*np.pi*np.arange(0., 512., dtype=np.float64))
    test2 = np.sin(50.*2.*np.pi*np.linspace(0., 512., 512, endpoint=True, dtype=np.float64))
    test3 = np.sin(50.*2.*np.pi*np.linspace(0., 512., 512, endpoint=False, dtype=np.float64))
    
    fig, axs = plt.subplots(3, sharex=True, sharey=True, gridspec_kw={'hspace': 0})
    
    axs[0].set_ylim((min(test1), max(test1)))
    axs[0].plot(np.arange(0, 512), test1)
    axs[1].plot(np.arange(0, 512), test2)
    axs[2].set_ylim((min(test1), max(test1)))
    axs[2].plot(np.arange(0, 512), test3)
    plt.show()
    

    Additional explanation

    Per the documentation of numpy.sin, the argument it takes as x is the angle in radians, not to be confused with degrees.

    Another point to note from the numpy.linspace documentation is that

    Note that the step size changes when endpoint is False.

    Here is a quick example:

    np.linspace(0., 512., 5, endpoint=True, dtype=np.float64)
    

    Output

    array([  0., 128., 256., 384., 512.])  
    

    and

    np.linspace(0., 512., 5, endpoint=False, dtype=np.float64)
    

    Output

    array([  0. , 102.4, 204.8, 307.2, 409.6])
    

    Now, if do a quick check on numpy.sin on the highest values in each array i.e. 512. and 409.6

    np.sin(409.6)
    

    Output

    0.9294631796005904
    

    and

    np.sin(512)
    

    Output

    0.07951849401287635
    

    Hence, the difference.