Hi,
Forgive me if this post is in the wrong place. The code uses tkinter GUI with several plots on seperate note tabs, hence Ive posted it in GUI
Ive been using Python for about 3 weeks but have coded in C++, clipper and VB for about 30 years.
I want to write some code to read in a file of vibration data with up to 16k readings, perform an fft to convert from time based data to frequency based data so I can analyse the data for problems. Please refer to my website www.efftek.co.uk for further information on vibration analysis if you need.
I found an open source example of a program doing much of what I wanted. Basically, it talks to an arduino which is connected to a 3 axis accelerometer, takes readings and displays them. The original source code and details are here https://hackaday.io/project/12109-open-s...m-analyzer
I have used this code to learn Python and have been editing it to my own needs.
I dont want all three channels displayed on one plot as the source code has so where fig1 had three subplots - ax_11, ax_12 and ax_13, I have deleted two of the sub plots so I just have ax_11. The same for fig2, fig3 and fig4 (fig3 and fig4 are my additions to the original code)
Now when I removed ax_?3 and change the subplots to be .add_subplot(2,1,?) etc, it still works OK but when I delete plots ax_?2 and change it to .add_subplot(1,1,1), I get errors. Whilst it will start up OK and display an empty plot, when I open a file with data to be displayed, I get a 'list' object has no attribute 'plot' error for line 247
Here is the full code. In order to try this out, you will need to download the data file from here datos_3can_20-12-2016__11_39_50.txt
I'd be grateful if anyone can advise why this is happening and how to cure it. Thanks, Steve.
Forgive me if this post is in the wrong place. The code uses tkinter GUI with several plots on seperate note tabs, hence Ive posted it in GUI
Ive been using Python for about 3 weeks but have coded in C++, clipper and VB for about 30 years.
I want to write some code to read in a file of vibration data with up to 16k readings, perform an fft to convert from time based data to frequency based data so I can analyse the data for problems. Please refer to my website www.efftek.co.uk for further information on vibration analysis if you need.
I found an open source example of a program doing much of what I wanted. Basically, it talks to an arduino which is connected to a 3 axis accelerometer, takes readings and displays them. The original source code and details are here https://hackaday.io/project/12109-open-s...m-analyzer
I have used this code to learn Python and have been editing it to my own needs.
I dont want all three channels displayed on one plot as the source code has so where fig1 had three subplots - ax_11, ax_12 and ax_13, I have deleted two of the sub plots so I just have ax_11. The same for fig2, fig3 and fig4 (fig3 and fig4 are my additions to the original code)
Now when I removed ax_?3 and change the subplots to be .add_subplot(2,1,?) etc, it still works OK but when I delete plots ax_?2 and change it to .add_subplot(1,1,1), I get errors. Whilst it will start up OK and display an empty plot, when I open a file with data to be displayed, I get a 'list' object has no attribute 'plot' error for line 247
Here is the full code. In order to try this out, you will need to download the data file from here datos_3can_20-12-2016__11_39_50.txt
I'd be grateful if anyone can advise why this is happening and how to cure it. Thanks, Steve.
#!/usr/bin/env python3 ¡¡¡ OK !!! # fft_spectrum_gui_3can_py3_02.py # - Added velocity and envelop (using hilbert transform) plots # 01/02/2018 - Steve Ferry. # Program fft_spectrum_gui_3can_py3_01.py # - Added a timeout control to a while loop. # 12/01/2017 # Program fft_spectrum_gui_3can.py modified: # - From Python 2.7 to Python 3.5. # - Works with AVR program adxl335_3can_01.c # 20/12/2016 # Program fft_spectrum_gui_3can.py # Program fft_spectrum_gui.py modified: # - 3 data channels (3 axes) # 15/11/2016 # Program fft_spectrum_gui.py # - Based on program frame_tab_plot_07.py # - Sample acceleration data from a ADXL335 accelerometer. # - Plot sampled data and its FFT spectrumsu # - Save data on file and open files with saved data. # - Serial communication with microcontroller.e # - Serial port selection. # - RadioButtons to select a Window function to apply. # 13/07/2016 import matplotlib import matplotlib.pyplot as plt matplotlib.use('TkAgg') from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg from matplotlib.figure import Figure from scipy import fftpack, arange, signal import numpy as np import tkinter as Tk from tkinter import filedialog from tkinter import messagebox from tkinter.scrolledtext import ScrolledText from tkinter import ttk from scipy.signal import hilbert from numpy import linalg as nl datos_a_leer = 4096 # Amount of samples to read. sample_rate = 5000 # Sampling frequency (SPS). g_scale = 3.0 / 512 # +- 3g. 10 bit ADC. max_freq = 1500 # Maximum signal frequency, X and Y axis (accelerometer). max_freq_z = 500 # Maximum signal frequency, Z axis (accelerometer). fftlen = 8192 # Samples to display FFT twflen = 2048 # twf data points to display twopi = 6.28318530717 gconst = 9806.65 g_canal_1 = [] # Global canal_1 g_canal_2 = [] # Global canal_2 g_canal_3 = [] # Global canal_3 t_timeout = 8 # Timeout time in seconds. def simpleParse(mainString, beginString, endString): posBeginString = mainString.find(beginString) + len(beginString) posEndString = mainString.find(endString) resultado = mainString[posBeginString:posEndString] return resultado def extraer_int_tag(datos_arch, tag): beginString = '<' + tag + '>' endString = '</' + tag + '>' str_parse = simpleParse(datos_arch, beginString, endString) str_canal = str_parse.split(',') canal = [] n = len(str_canal) for i in range(n): canal.append(int(str_canal[i])) return canal class Application: def __init__(self, parent): self.parent = parent self.frames() self.f_saved = True # Sampled data saved root.protocol("WM_DELETE_WINDOW", self.on_closing) def on_closing(self): if (self.f_saved == False): if messagebox.askokcancel("Quit", "Sampled data not saved. Do you wanto to quit?"): root.destroy() else: root.destroy() def frames(self): frame1 = Tk.Frame(root, bd=5, relief='raised', borderwidth=1) frame2 = Tk.Frame(root, bd=5, relief='raised', borderwidth=1) note = ttk.Notebook(frame2) self.tab1 = ttk.Frame(note) self.tab2 = ttk.Frame(note) self.tab3 = ttk.Frame(note) self.tab4 = ttk.Frame(note) note.add(self.tab1, text=" Time Waveform ") note.add(self.tab2, text=" Acceleration Spectra ") note.add(self.tab3, text=" Velocity Spectra ") note.add(self.tab4, text=" Demodulated Spectra ") # Positioning frame1.pack(side='left', fill='both', padx=5, pady=5) frame2.pack(side='right', fill='both', expand='true') boton_open = Tk.Button(frame1, text="Open file", command=self.open_file) label4 = Tk.Label(frame1, text="Select Channel") self.text_message = ScrolledText(frame1, height=10, width=20) self.chan_var = Tk.IntVar() self.chan_var.set(1) channel_button1 = Tk.Radiobutton(frame1, text="Channel 1", variable=self.chan_var, value=1, command=self.chan_sel) channel_button2 = Tk.Radiobutton(frame1, text="Channel 2", variable=self.chan_var, value=2, command=self.chan_sel) channel_button3 = Tk.Radiobutton(frame1, text="Channel 3", variable=self.chan_var, value=3, command=self.chan_sel) channel_button4 = Tk.Radiobutton(frame1, text="Channel 4", variable=self.chan_var, value=3, command=self.chan_sel) label4.grid(row=4, column=0, padx=5, pady=5) channel_button1.grid(row=5, column=0, sticky="W") channel_button2.grid(row=6, column=0, sticky="W") channel_button3.grid(row=7, column=0, sticky="W") channel_button4.grid(row=8, column=0, sticky="W") note.pack(side='top', fill='both', padx=5, pady=5) boton_open.grid(row=13, column=0, padx=5, pady=5) plt.ion() # Figure 1 fig1 = Figure(figsize=(10, 9)) fig1.suptitle('Sampled signal - Acceleration') ax_11 = fig1.add_subplot(1, 1, 1) ax_11.set_ylabel('g') ax_11.grid() # Shows grid. # Figure 2 fig2 = Figure(figsize=(10, 9)) fig2.suptitle('Acceleration Spectra') ax_21 = fig2.add_subplot(1, 1, 1) ax_21.set_ylabel('g') ax_21.set_xlim(xmin=0,xmax=max_freq) ax_21.grid() # Figure 3 fig3 = Figure(figsize=(10, 9)) fig3.suptitle('Velocity spectra') ax_31 = fig3.add_subplot(1, 1, 1) ax_31.set_ylabel('mm/sec') ax_31.set_xlim(xmin=0, xmax=max_freq) ax_31.grid() # Figure 4 fig4 = Figure(figsize=(10, 9)) fig4.suptitle('Demodulated spectra') ax_41 = fig4.add_subplot(1, 1, 1) ax_41.set_ylabel('g') ax_41.set_xlim(xmin=0, xmax=max_freq) ax_41.grid() # Canvas self.canvas1 = FigureCanvasTkAgg(fig1, master=self.tab1) self.canvas1.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.canvas2 = FigureCanvasTkAgg(fig2, master=self.tab2) self.canvas2.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.canvas3 = FigureCanvasTkAgg(fig3, master=self.tab3) self.canvas3.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.canvas4 = FigureCanvasTkAgg(fig4, master=self.tab4) self.canvas4.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.canvas1._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.canvas2._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.canvas3._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self.canvas4._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) def show_message(self, text_message, message_string): """Shows messages on a scrollable textbox""" text_message.config(state=Tk.NORMAL) # Enable to modify text_message.insert(Tk.END, message_string) text_message.config(state=Tk.DISABLED) # Disable - Read only text_message.see("end") # Show the "end" of text root.update_idletasks() # Needed to make message visible def plot(self, tab1, tab2, tab3, tab4, canal_1, canal_2, canal_3, chan_no): if chan_no == 1: twf = canal_1 elif chan_no == 2: twf = canal_2 else: twf = canal_3 num_datos = len(twf) X = range(0, num_datos, 1) # Scale the signal in g's for indice in X: twf[indice] *= g_scale # Calculates average value for each channel. avg = 0 for indice in X: avg += twf[indice] avg = avg / num_datos # print("Vdc Channel 1: {0}, Vdc Channel 2: {1}".format(vdc_canal_1, vdc_canal_2)) # Substract DC offset for indice in X: twf[indice] -= avg X1 = np.linspace(0, num_datos / 5, num=num_datos) # X axis, 5000 sps, 1/5 ms. canal_fft = twf N = len(canal_fft) # length of the signal M = int(N / 2) T = 1.0 / sample_rate y = canal_fft w = signal.hann(N, sym=False) # Hann (Hanning) window ax = np.abs(fftpack.fft(y * w) * (2 / N)) ax = ax[:int(N / 2)] xx = np.linspace(0.0, 1.0 / (2.0 * T), int(N / 2)) vx = [0] * M for i in range( 5, M): vx[i] = ((ax[i] * gconst) / (twopi * xx[i])) #calculate velocity analy = hilbert(canal_fft[::]) y = abs(analy[0:M]) sig_f = abs(np.abs(fftpack.rfft(y))) sig_n = sig_f / (nl.norm(sig_f)) hx = sig_n[0:M] hx[0] = 0 # Figure 1. twf ax_11 = self.canvas1.figure.get_axes() ax_11.clear() ax_11.plot(X1[0:twflen], twf[0:twflen]) ax_11.set_ylabel('g') ax_11.grid() # Shows grid. # Figure 2. FFT from signals. ax_21 = self.canvas2.figure.get_axes() ax_21.clear() ax_21.plot(xx, ax) ax_21.grid() ax_21.set_ylabel('g') ax_21.set_xlim(xmin=0, xmax=max_freq) ax_31 = self.canvas3.figure.get_axes() ax_31.clear() ax_31.plot(xx, vx) ax_31.grid() ax_31.set_ylabel('mm/sec') ax_31.set_xlim(xmin=0, xmax=max_freq) ax_41 = self.canvas4.figure.get_axes() ax_41.clear() ax_41.plot(xx, hx) ax_41.grid() ax_41.set_ylabel('g') ax_41.set_xlim(xmin=0, xmax=max_freq) self.canvas1.draw() self.canvas2.draw() self.canvas3.draw() self.canvas4.draw() def chan_sel(self): global g_canal_1, g_canal_2, g_canal_3 canal_1 = g_canal_1[:] # Copy list by value not by reference canal_2 = g_canal_2[:] canal_3 = g_canal_3[:] chan_no = self.chan_var.get() if (len(canal_1) != 0): # Apply only if data available self.plot(self.tab1, self.tab2, self.tab3, self.tab4, canal_1, canal_2, canal_3, chan_no) def open_file(self): """Opens dialog to select a file, reads data from file and plots the data""" ftypes = [('Text files', '*.txt'), ('All files', '*')] dlg = filedialog.Open(root, filetypes=ftypes) fl = dlg.show() if fl != '': # Open file for reading arch = open(fl, "r") datos_arch = arch.read() # Searches for every channel, delimited by L1, L2 and L3 tags. canal_1 = extraer_int_tag(datos_arch, 'L1') canal_2 = extraer_int_tag(datos_arch, 'L2') canal_3 = extraer_int_tag(datos_arch, 'L3') print("Amount of samples in channel 1: %s" % len(canal_1)) print("Amount of samples on channel 2: %s" % len(canal_2)) print("Amount of samples on channel 3: %s" % len(canal_3)) message_string = "Amount of samples \nChannel 1: {0} \n".format(len(canal_1)) message_string += "Channel 2: {0} \n".format(len(canal_2)) message_string += "Channel 3: {0} \n".format(len(canal_3)) self.show_message(self.text_message, message_string) global g_canal_1, g_canal_2, g_canal_3 # Keep a copy of the original values g_canal_1 = canal_1[:] # Copy list by value not by reference g_canal_2 = canal_2[:] g_canal_3 = canal_3[:] self.plot(self.tab1, self.tab2, self.tab3, self.tab4, canal_1, canal_2, canal_3, chan_no=1) if __name__ == '__main__': root = Tk.Tk() root.title('FFT spectrum analyser') app = Application(root) root.mainloop()