How to plot a continuous sine wave in Python?

Imas picture Imas · Apr 11, 2018 · Viewed 8k times · Source

I am trying to simulate the display of a sine wave one would generate from an oscilloscope using Python. As I am trying to merely simulate it (and not pull the data from the oscilloscope), I was wondering how I would show a continuous sine wave. I have the sample rate of the device (200MHz - 1GS/s), the frequency of my wave (1MHz), and the amplitude (1V). The data would be viewed in microseconds. I have read through various answers here on StackOverflow and have had problems with the plot having irregular waves or something of the sort. Is there a way to have this data shown like below? Oscilloscope data output I wish to simulate, for 1MHz freq, 100MS/s sample rate, amplitude of 1V.

A secondary problem is the ability to plot this wave continuously. For example, when using Matplotlib, if I zoom out it doesn't show the wave continuing past my interval. Is there a way to have the wave continually represented? I don't want to be tied down to Matplotlib, so I am looking for other solutions that continually creating (appending?) data in both directions. If this is not possible, is it possible to establish some sort of number of wavelengths in each direction?

Thank you so much!

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

Fs = 20E3
f = 1E6
sample = Fs/f
print(sample)
x = np.arange(sample)

y = 100*np.sin(2 * np.pi * f * x / Fs)

plt.plot(x, y)
plt.show()

Answer

V. L. picture V. L. · Apr 13, 2018

You could use matplotlib.animation to achieve your goal.

I took an existing example which emulates an oscilloscope and adjusted it to your needs (e.g. sine wave & plotting continously).

Regarding the continous plotting: I set up a continous variable, where you can choose if you want to plot it continously (not able to zoom) or not (able to zoom). I wasn't able to combine both functionalities in one plot yet. So just run the code once with continous = True and once with continous = False to see if it suits your needs.

But I think this could be a good start for plotting continous sine waves.

import numpy as np
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# Your Parameters
amp = 1         # 1V        (Amplitude)
f = 1000        # 1kHz      (Frequency)
fs = 200000     # 200kHz    (Sample Rate)
T = 1/f
Ts = 1/fs

# Select if you want to display the sine as a continous wave
#  True = Continous (not able to zoom in x-direction)
#  False = Non-Continous  (able to zoom)
continous  = True

x = np.arange(fs)
y = [ amp*np.sin(2*np.pi*f * (i/fs)) for i in x]


class Scope(object):
    def __init__(self, ax, maxt=2*T, dt=Ts):
        self.ax = ax
        self.dt = dt
        self.maxt = maxt
        self.tdata = [0]
        self.ydata = [0]
        self.line = Line2D(self.tdata, self.ydata)
        self.ax.add_line(self.line)
        self.ax.set_ylim(-amp, amp)
        self.ax.set_xlim(0, self.maxt)

    def update(self, y):
        lastt = self.tdata[-1]
        if continous :
            if lastt > self.tdata[0] + self.maxt:
                self.ax.set_xlim(lastt-self.maxt, lastt)

        t = self.tdata[-1] + self.dt
        self.tdata.append(t)
        self.ydata.append(y)
        self.line.set_data(self.tdata, self.ydata)
        return self.line,


def sineEmitter():
    for i in x:
        yield y[i]


fig, ax = plt.subplots()
scope = Scope(ax)

# pass a generator in "sineEmitter" to produce data for the update func
ani = animation.FuncAnimation(fig, scope.update, sineEmitter, interval=10,
                              blit=True)

plt.show()