diff --git a/MLI_vectorielle.py b/MLI_vectorielle.py index ca34e97..3c3bb97 100644 --- a/MLI_vectorielle.py +++ b/MLI_vectorielle.py @@ -3,7 +3,7 @@ import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt -from matplotlib.widgets import Slider, Button +from matplotlib.widgets import Slider, Button, CheckButtons from matplotlib.axes import Axes from matplotlib.projections.polar import PolarAxes @@ -19,8 +19,8 @@ class TriPlot_TimeAxe(Axes): phasor = np.linspace(0-phase, 2*PI-phase, N_PTS).T theta = phasor[0,:] - def __init__(self, v_max, phi, fig, rect): - Axes.__init__(self, fig, rect) + def __init__(self, v_max, phi, fig, rect, *args, **kwargs): + Axes.__init__(self, fig, rect, *args, **kwargs) self.timegraph_plot = [] self.v_max = v_max self.phi = phi @@ -36,7 +36,7 @@ class TriPlot_TimeAxe(Axes): self.set_xticks([i*PI/6 for i in range(13)]) self.set_xticklabels([str(30*i)+"°" for i in range(13)]) self.set_xlabel("Phase") - self.set_ylim([-2.2*self.v_max, +2.2*self.v_max]) + self.set_ylim([-1.6*self.v_max, +1.6*self.v_max]) self.set_ylabel("Tension [V]") self.timegraph_plot.append( @@ -72,6 +72,9 @@ class TriPlot_TimeAxe(Axes): self.phi = phi return + def set_parameters(self, p): + return + class TriPlot_VectAxe(PolarAxes): """Classe d'axe vectoriel""" @@ -80,19 +83,20 @@ class TriPlot_VectAxe(PolarAxes): phasor = np.linspace(0-phase, 2*PI-phase, N_PTS).T theta = phasor[0,:] - def __init__(self, v_max, phi, fig, rect): - PolarAxes.__init__(self, fig, rect) + def __init__(self, v_max, phi, fig, rect, *args, **kwargs): + PolarAxes.__init__(self, fig, rect, *args, **kwargs) self.plot_list = [] self.arrow_list = [] self.v_max = v_max self.phi = phi self.v_ref = np.zeros(self.phasor.shape) + self.parameters = {"projection": False} return def setup(self): self.get_figure().add_axes(self) self.set_rorigin(0) - self.set_ylim(0, 2.2*self.v_max) + self.set_ylim(0, 1.6*self.v_max) theta_ticks = np.arange(0, 360, 30) theta_labels = [str(t * (t<=180) @@ -105,8 +109,20 @@ class TriPlot_VectAxe(PolarAxes): self.theta, self.v_max*np.ones(self.theta.shape), 'r' )[0] ) + for i in range(3): + self.plot_list.append( + self.plot( + [(self.phi-i*120)*PI/180, + PI*(1-np.sign(np.cos((self.phi-i*120)*PI/180)))], + [self.v_max, + self.v_max*np.abs(np.cos((self.phi-i*120)*PI/180))], + ls = ':', + visible=self.parameters["projection"] + )[0] + ) self.arrow_list = [ - self.arrow(0, 0, 0, self.v_max, + self.arrow(0, 0, + 0, self.v_max, lw=2, head_width=0.05, head_length=self.v_max/15, color="C"+str(i), length_includes_head=True, transform=( @@ -116,7 +132,26 @@ class TriPlot_VectAxe(PolarAxes): + self.transData ) ) - for i in range(3)] + for i in range(3) + ] + [ + self.arrow(0, 0, + 0, self.v_max*np.abs(np.cos((self.phi-i*120)*PI/180)), + lw=1, head_width=0.05, head_length=self.v_max/15, + color="C"+str(i), length_includes_head=True, + transform=( + mpl.transforms.Affine2D().translate( + PI*(1-np.sign( + np.cos((self.phi-i*120)*PI/180) + ) + )/2, + 0 + ) + + self.transData + ), + visible=self.parameters["projection"] + ) + for i in range(3) + ] return def refresh(self): @@ -125,13 +160,33 @@ class TriPlot_VectAxe(PolarAxes): self.theta.shape ) ) + + for i, plot in enumerate(self.plot_list[1:4]): + plot.set_visible(self.parameters.get("projection")) + plot.set_xdata( + [(self.phi-i*120)*PI/180, + PI*(1-np.sign(np.cos((self.phi-i*120)*PI/180)))/2] + ) + plot.set_ydata( + [self.v_max, + self.v_max*np.abs(np.cos((self.phi-i*120)*PI/180))] + ) - for i, arrow in enumerate(self.arrow_list): - arrow.set_data(dy=self.v_max) - arrow.set_transform( + for i in range(3): + self.arrow_list[i].set_data(dy=self.v_max) + self.arrow_list[i].set_transform( + mpl.transforms.Affine2D().translate( + (self.phi-i*120)*PI/180, 0) + + self.transData + ) + for i in range(3, 6): + self.arrow_list[i].set_visible(self.parameters["projection"]) + self.arrow_list[i].set_data( + dy=self.v_max*np.abs(np.cos((self.phi-i*120)*PI/180)) + ) + self.arrow_list[i].set_transform( mpl.transforms.Affine2D().translate( - (self.phi-i*120)*PI/180, 0 - ) + PI*(1-np.sign(np.cos((self.phi-i*120)*PI/180)))/2, 0) + self.transData ) return @@ -144,6 +199,10 @@ class TriPlot_VectAxe(PolarAxes): def set_phi(self, phi): self.phi = phi return + + def set_parameters(self, p): + self.parameters["projection"] = p.get("projection", False) + return class TriPlot: @@ -155,38 +214,47 @@ class TriPlot: def __init__(self): # Attributs scalaires - self.v_eff = 100 + self.v_eff = 220 self.v_max = np.sqrt(2)*self.v_eff self.v_ref = np.zeros(self.phasor.shape) self.phi = 30 # Attributs graphiques self.fig = plt.figure() - self.ax = [ - TriPlot_TimeAxe(self.v_max, self.phi, self.fig, [0.1, 0.2, 0.4, 0.6]), - TriPlot_VectAxe(self.v_max, self.phi, self.fig, [0.5, 0.2, 0.5, 0.6]), - plt.axes([0.01, 0.1, 0.03, 0.8]), - plt.axes([0.1, 0.01, 0.8, 0.03])] + self.timeaxe = TriPlot_TimeAxe(self.v_max, self.phi, + self.fig, [0.1, 0.2, 0.4, 0.6]) + self.vectaxe = TriPlot_VectAxe(self.v_max, self.phi, + self.fig, [0.5, 0.2, 0.5, 0.6]) + self.axes = [self.timeaxe, self.vectaxe] self.amp_slider = Slider( - ax=self.ax[2], + ax=plt.axes([0.01, 0.1, 0.03, 0.8]), label="Tension\nefficace", valmin=0, - valmax=2*self.v_eff, + valmax=1.5*self.v_eff, valinit=self.v_eff, orientation="vertical" ) self.phi_slider = Slider( - ax=self.ax[3], + ax=plt.axes([0.1, 0.01, 0.8, 0.03]), label="Phase [°]", valmin=0, valmax=360, valinit=self.phi, orientation="horizontal" ) - self.amp_slider - self.vectorgraph_plot = [] - self.vectorgraph_arrow = [] - + self.reset_button = Button( + ax=plt.axes([0.95, 0.01, 0.03, 0.03]), + label='Reset', + hovercolor='0.975' + ) + self.parameters_check = CheckButtons( + ax=plt.axes([0.9, 0.8, 0.1, 0.2]), + labels=["Projection"] + ) + + self.sliders = [self.amp_slider, self.phi_slider] + self.parameters = {} + # Tracé du graphique self.setup() self.refresh() @@ -194,42 +262,50 @@ class TriPlot: return def setup(self): - self.fig.subplots_adjust(left=0.25) - self.ax[0].setup() - self.ax[1].setup() - - self.amp_slider.on_changed(self.refresh) - self.phi_slider.on_changed(self.refresh) + for axe in self.axes: + axe.setup() + for slider in self.sliders: + slider.on_changed(self.refresh) + self.reset_button.on_clicked(self.reset) + self.parameters_check.on_clicked(self.refresh) return def refresh(self, val=None): self.set_veff(self.amp_slider.val) self.set_phi(self.phi_slider.val) - self.ax[0].refresh() - self.ax[1].refresh() + self.set_parameters(self.parameters_check.get_status()) + for axe in self.axes: + axe.refresh() + self.fig.canvas.draw() return def reset(self, event=None): - return - - def set_veff(self, v_eff): - self.set_vmax(np.sqrt(2)*v_eff) + for slider in self.sliders: + slider.reset() return def set_vmax(self, v_max): self.v_max = v_max self.v_eff = v_max/np.sqrt(2) self.v_ref = self.v_max*np.cos(self.phasor) + for axe in self.axes: + axe.set_vmax(self.v_max) + return - self.ax[0].set_vmax(self.v_max) - self.ax[1].set_vmax(self.v_max) - + def set_veff(self, v_eff): + self.set_vmax(np.sqrt(2)*v_eff) return def set_phi(self, phi): self.phi = phi - self.ax[0].set_phi(self.phi) - self.ax[1].set_phi(self.phi) + for axe in self.axes: + axe.set_phi(self.phi) + return + + def set_parameters(self, p): + self.parameters["projection"] = p[0] + for axe in self.axes: + axe.set_parameters(self.parameters) return if __name__ == '__main__':