diff --git a/tools/plots.py b/tools/plots.py index 5d747018e36b9ee5cc92487fcbb8e5cbe600c5c5..d852b1cfafddbbadbecde703865dc839b4dc2d8f 100644 --- a/tools/plots.py +++ b/tools/plots.py @@ -4,6 +4,7 @@ from typing import List, Any, Dict, Tuple import re from .processing import * +from .utils import from_class_to_text # %% def PlotFilter (filter: np.ndarray, sampling_rate: int = 1000): @@ -184,4 +185,228 @@ def Spectrogram_plot ( if save: savefig("Spectrogram\\" + name) - return f, extent \ No newline at end of file + return f, extent + +def plot_unique_position(data:pd.DataFrame, axis:plt.Axes, byvariable:str, Motor:int) -> plt.Axes: + """plots on secondary axis a unique motor position run when multiple runs are present in the dataframe in argument + the runs are differenciated with the 'byvariable' value + + Args: + data (pd.DataFrame): data containing the Position _A{Motor} column + axis (plt.Axes): axis to duplicate + byvariable (str): common column in the dataframe, differenciating the runs + Motor (int): Motor's position to plot + + Returns: + plt.Axes: new axis with ploted position + """ + ax2 = axis.twinx() + position_df = data.loc[data[byvariable] == data.iloc[0][byvariable]] # look for the data with condition 'byvariable' == (first value found of byvariable) + lin = sns.lineplot(data=position_df, x='Sample_time',y=f'Position_A{Motor}', color='grey', alpha = 0.1, ax=ax2,label=f'Axis {Motor} position',legend=False) + ax2.set_ylabel(f'Motor {Motor} angle (°)') + return lin + +def check_arguments(plot_type:str, variable:str, byvariable:str): + """ Checks that the variables to plot are suited for ploting + """ + if plot_type not in ['Lineplot', 'Boxplot']: + print('Bad plot type argument') + return False + if variable not in ['Current', 'Temperature', 'Position_Error']: + print('Bad variable argument') + return False + if byvariable not in ['Class', 'Speed']: + print('Bad by variable argument') + return False + return True + +def plot_all_axis(DB, variable:str, byvariable:str, byvalues:List, MovingMotor:int, Speed:int = 50, Class:int = 0, plot_type:str = 'Lineplot', doposition:bool = False, saving:bool = False): + """Plots variable's data from the Dataframe on each robot axis (6 subplots), differenciating the data by 'byvariable' column's name. + Create a 'Lineplot' or a 'Boxplot', depending on the argument plot + Which motor's data to plot is defined by the arg Motor, same with Speed. + Choose to plot the motor's position on a secondary axis, figure saving and showing with the boolean arguments + + Args: + data (pd.DataFrame): Pandas dataframe containing the data + variable (str): Variable to plot + byvariable (str): Variable that discriminates the data + Motor (int): Motor number + Speed (int): Motor speed + plot_type (str, optional): 'Lineplot' or 'Boxplot' : format of the data plot. Defaults to 'Lineplot' + doposition (bool, optional): motor's position plot. Defaults to False. + saving (bool, optional): figure saving. Defaults to False. + """ + if not check_arguments(plot_type, variable, byvariable): + return + + columns = [byvariable,'Sample_time',f'Position_A{MovingMotor}',*[f'{variable}_A{j}'for j in range(1,7,1)]] + dataframe = pd.DataFrame() # Data gathering + rms = [] + for v in byvalues: + if byvariable == 'Speed': + df = DB.robot(2).by_class(Class).by_speed(v).by_moving_motor(MovingMotor).select_column(*columns).run() + df['Speed'] = df.Speed.astype('category') + df['Sample_time'] -= df['Sample_time'].min() # limits data to 2-3 iterations + dataframe = pd.concat([dataframe, df[0:500]]) + if byvariable == 'Class': + df = DB.robot(2).by_class(v).by_speed(Speed).by_moving_motor(MovingMotor).run() + df['Class'] = df.Class.astype('category') + df['Sample_time'] -= df['Sample_time'].min() + dataframe = pd.concat([dataframe, df[300:900]]) # limits data to 2-3 iterations + rms.append(np.sqrt(np.mean(df[f'{variable}_A{MovingMotor}']**2))) + print(f'Motor {MovingMotor} runs rms :',rms) + + fig = plt.figure(figsize=(3*6,2*4)) # Data plot + for i in range(1,7,1): + axis = plt.subplot(2,3,i) + if(plot_type=='Boxplot'): + sns.boxplot(data=dataframe, y=f'{variable}_A{i}', hue=byvariable, ax=axis) + if(plot_type=='Lineplot'): + lin1 = sns.lineplot(data= dataframe, x='Sample_time', y=f'{variable}_A{i}', hue=byvariable, ax=axis, alpha=0.6) + if doposition : + lin2 = plot_unique_position(dataframe, axis, byvariable, MovingMotor) + axis.legend(fontsize=8, loc='upper right', handles=lin1.get_lines()+lin2.get_lines()) + else: + axis.legend(fontsize=8, loc='upper right') + axis.set_title(f'Motor {i}') + + + if byvariable == 'Speed': + fig.suptitle(f"{plot_type} of {variable} by {byvariable} for Axis {MovingMotor} moving loaded with {from_class_to_text(Class)}") + if byvariable == 'Class': + fig.suptitle(f"{plot_type} of {variable} by {byvariable} for Axis {MovingMotor} moving at {Speed}% Speed") + + fig.tight_layout() + + if saving: + figures = Path(f"figures/{variable} by motor by {byvariable}") + if not figures.exists(): + figures.mkdir(parents=True) + fig.savefig(f"figures/{variable} by motor by {byvariable}/{plot_type}_of_{variable}_by{byvariable}_Axis{MovingMotor}.png") + + return fig + + +def plot_moving_axes(DB, variable:str, byvariable:str, byvalues:List, Speed:int = 50, Class:int = 0, plot_type:str = 'Lineplot', doposition:bool = False, saving:bool = False): + """Plots the current of the motor responsible of axis movement for the axes moving (ex : A1 moving - current Motor 1, A2 moving - current Motor 2,...) + differenciating the data by 'byvariable' column's name. + Create a 'Lineplot' or a 'Boxplot', depending on the argument plot + Which motor's data to plot is defined by the arg Motor, same with Speed. + Choose to plot the motor's position on a secondary axis, figure saving and showing with the boolean arguments + + Args: + data (pd.DataFrame): Pandas dataframe containing the data + variable (str): Variable to plot + byvariable (str): Variable that discriminates the data + Motor (int): Motor number + Speed (int): Motor speed + plot_type (str, optional): 'Lineplot' or 'Boxplot' : format of the data plot. Defaults to 'Lineplot' + doposition (bool, optional): motor's position plot. Defaults to False. + saving (bool, optional): figure saving. Defaults to False. + """ + + if not check_arguments(plot_type, variable, byvariable): + return + + fig = plt.figure(figsize=(3*6,2*4)) + for Motor in range (1,7,1): + dataframe = pd.DataFrame() # Data gathering + columns = [byvariable,'Sample_time',f'{variable}_A{Motor}',f'Position_A{Motor}'] + rms = [] + for v in byvalues: + if byvariable == 'Speed': + df = DB.robot(2).by_class(Class).by_speed(v).by_moving_motor(Motor).select_column(*columns).run() + df['Speed'] = df.Speed.astype('category') + df['Sample_time'] -= df['Sample_time'].min() + dataframe = pd.concat([dataframe, df[0:500]]) # limits data to 2-3 iterations + if byvariable == 'Class': + df = DB.robot(2).by_class(v).by_speed(Speed).by_moving_motor(Motor).select_column(*columns).run() + df['Class'] = df.Class.astype('category') + df['Sample_time'] -= df['Sample_time'].min() + dataframe = pd.concat([dataframe, df[300:900]]) + rms.append(np.sqrt(np.mean(df[f'{variable}_A{Motor}']**2))) # limits data to 2-3 iterations + print(f'Motor {Motor} runs rms :',rms) + + axis = plt.subplot(2,3,Motor) + if(plot_type=='Boxplot'): + sns.boxplot(data=dataframe, y=f'{variable}_A{Motor}', hue=byvariable, ax=axis) + if(plot_type=='Lineplot'): + lin1 = sns.lineplot(data= dataframe, x='Sample_time', y=f'{variable}_A{Motor}', hue=byvariable, ax=axis, alpha=0.6) + lin1.set_ylabel(f'{variable}_A{Motor}, Axis {Motor} moving') + if doposition : + lin2 = plot_unique_position(dataframe, axis, byvariable, Motor) + axis.legend(fontsize=8, loc='upper right', handles=lin1.get_lines()+lin2.get_lines()) + else: + axis.legend(fontsize=8, loc='upper right') + axis.set_title(f'Motor {Motor}') + + + if byvariable == 'Speed': + fig.suptitle(f"{plot_type} of {variable} by {byvariable} loaded with {from_class_to_text(Class)}") + if byvariable == 'Class': + fig.suptitle(f"{plot_type} of {variable} by {byvariable} moving at {Speed}% Speed") + + fig.tight_layout() + + if saving: + figures = Path(f"figures/{variable} by moving motors by {byvariable}") + if not figures.exists(): + figures.mkdir(parents=True) + fig.savefig(f"{figures}/{plot_type}_of_{variable}_by{byvariable}{str(byvalues)}_allAxes.png") + + return fig + +def plot_grouped_load(DB, variable:str, Classes:List[List], Motor:int, Speed:int, doposition:bool = False, saving:bool = False) -> plt.Figure: + + """Plots variable's data from the DataBase, grouping the curves by load classes. + Each list in Classes will create a subplot, with the curves of the classes + Which motor's data to plot is defined by the arg Motor, same with Speed. + Choose to plot the motor's position on a secondary axis and figure saving with the boolean arguments + + Args: + DB (_type_): Database containing the data + variable (str): Column of the database to plot + Classes (List[List]): List of list of loads classes. + Motor (int): Motor number + Speed (int): Motor speed + doposition (bool, optional): motor's position plot. Defaults to False. + saving (bool, optional): figure saving. Defaults to False. + + Returns: + plt.Figure: created figure + """ + columns = ['Class','Sample_time',f'Position_A{Motor}',*[f'{variable}_A{j}'for j in range(1,7,1)]] + fig = plt.figure(figsize=(len(Classes)*5,4)) + + for i, cla in enumerate(Classes): + axis = plt.subplot(1,len(Classes),i+1) + dataframe = pd.DataFrame() + rms = [] + for c in cla: + # Data gathering from the database + df = DB.robot(2).by_class(c).by_speed(Speed).by_moving_motor(Motor).select_column(*columns).run() + df['Sample_time'] -= df['Sample_time'].min() + df['Class'] = df.Class.astype('category') + dataframe = pd.concat([dataframe, df[300:900]]) # limits data to 2-3 iterations + rms.append(np.sqrt(np.mean(df[f'{variable}_A{Motor}']**2))) + print(f'Motor {Motor} runs rms :',rms) + + lin1 = sns.lineplot(data=dataframe,x='Sample_time', y=f'{variable}_A{Motor}', hue='Class', ax=axis, alpha=0.6) # data plot + + if doposition: + lin2 = plot_unique_position(dataframe, axis, 'Class', Motor) + axis.legend(fontsize=8, loc='upper right', handles=lin1.get_lines()+lin2.get_lines()) + else: + axis.legend(fontsize=8, loc='upper right') + axis.legend(fontsize=8, loc='upper right', handles=lin1.get_lines()+lin2.get_lines()) + + fig.suptitle(f'{variable} of Motor {Motor} running at {Speed}% speed grouped by load') + fig.tight_layout() + + if saving: + figures = Path(f"figures/{variable} by motor by grouped Load") + if not figures.exists(): + figures.mkdir(parents=True) + fig.savefig(f"figures/{variable} by motor by grouped Load/{variable}_A{Motor}_by_grouped_load.png") + + return fig diff --git a/tools/processing.py b/tools/processing.py index 346ce9b5bbb5d19012db881ab6126805060a349e..db854c3a61724dd002f23d0cb64e2d21451e0b66 100644 --- a/tools/processing.py +++ b/tools/processing.py @@ -381,3 +381,10 @@ def Spectrogram ( return Sx, SFT +def Density_spectrum (time: pd.Series | np.ndarray, signal: pd.Series | np.ndarray): + signal = signal - signal.mean() + b,a = scs.butter(7,0.99, btype='low', analog=False) + signal = scs.filtfilt(b,a,signal) + x,y = autocorrelation(time, signal) + signal_windowed = moving_window(y, 1) + return FFT(signal_windowed ,(time[1]-time[0])*1000, 32*len(signal_windowed) ) diff --git a/variable_by.py b/variable_by.py new file mode 100644 index 0000000000000000000000000000000000000000..3c6687a92db0a86ade38eefafac9df5c42f23714 --- /dev/null +++ b/variable_by.py @@ -0,0 +1,39 @@ +#%% Imports and variables +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import seaborn as sns +import scipy.signal as scs +from pathlib import Path + +from tools.database import Database +from tools.utils import from_class_to_text +from tools.plots import plot_all_axis, plot_grouped_load, plot_moving_axes + +DB = Database(f"D:\VSB\Programs\DB\Robot2-LoadTest.sqlite") + +# %% plot motor 1 current with position in background +""" plt.figure(figsize=(9,6)) +df = DB.robot(2).by_class(0).by_speed(70).by_moving_motor(1).run() +df['Sample_time'] -= df['Sample_time'].min() +plt.plot(df['Sample_time'],df['Current_A1']) +plt.ylabel('Current (A)') +plt.xlabel('Time (s)') +ax2 = plt.twinx() +ax2.plot(df['Sample_time'],df['Position_A1'],color='orange',alpha=0.3) +plt.ylabel('Motor position (°)') + +plt.title('Motor 1 current (A) in time (s) moving at 70% speed ') +plt.show() +""" +# %% Curent plot by speed +""" fig1 = plot_all_axis(DB,'Lineplot','Current','Speed',[40,50,60,70,80],Motor=1) +plt.show() """ + +# %% Weight analysis +fig1 = plot_all_axis(DB,'Current','Class',[0,2],MovingMotor=1, saving=True) +fig2 = plot_grouped_load(DB, 'Current', [[0,2],[4,6],[8,10],[12,14]], 1, 60, doposition=True, saving=True) +fig3 = plot_moving_axes(DB,'Current','Class',[0,2], doposition=True,saving=True) +plt.show() + +# %%