def draw_impz(self): """ (Re-)calculate h[n] and draw the figure """ log = self.chkLog.isChecked() stim = str(self.cmbStimulus.currentText()) periodic_sig = stim in {"Sine", "Rect", "Saw"} self.lblLogBottom.setVisible(log) self.ledLogBottom.setVisible(log) self.lbldB.setVisible(log) self.lblFreq.setVisible(periodic_sig) self.ledFreq.setVisible(periodic_sig) self.lblFreqUnit.setVisible(periodic_sig) self.lblFreqUnit.setText(rt_label(fb.fil[0]['freq_specs_unit'])) self.load_dict() self.bb = np.asarray(fb.fil[0]['ba'][0]) self.aa = np.asarray(fb.fil[0]['ba'][1]) if min(len(self.aa), len(self.bb)) < 2: logger.error('No proper filter coefficients: len(a), len(b) < 2 !') return sos = np.asarray(fb.fil[0]['sos']) self.f_S = fb.fil[0]['f_S'] N = self.calc_n_points(abs(int(self.ledNPoints.text()))) t = np.linspace(0, N / self.f_S, N, endpoint=False) # calculate h[n] if stim == "Pulse": x = np.zeros(N) x[0] = 1.0 # create dirac impulse as input signal title_str = r'Impulse Response' H_str = r'$h[n]$' elif stim == "Step": x = np.ones(N) # create step function title_str = r'Step Response' H_str = r'$h_{\epsilon}[n]$' elif stim == "StepErr": x = np.ones(N) # create step function title_str = r'Settling Error' H_str = r'$h_{\epsilon, \infty} - h_{\epsilon}[n]$' elif stim in {"Sine", "Rect"}: x = np.sin(2 * np.pi * t * float(self.ledFreq.text())) if stim == "Sine": title_str = r'Transient Response to Sine Signal' H_str = r'$y_{\sin}[n]$' else: x = np.sign(x) title_str = r'Transient Response to Rect. Signal' H_str = r'$y_{rect}[n]$' elif stim == "Saw": x = sig.sawtooth(t * (float(self.ledFreq.text()) * 2 * np.pi)) title_str = r'Transient Response to Sawtooth Signal' H_str = r'$y_{saw}[n]$' elif stim == "RandN": x = np.random.randn(N) title_str = r'Transient Response to Gaussian Noise' H_str = r'$y_{gauss}[n]$' elif stim == "RandU": x = np.random.rand(N) - 0.5 title_str = r'Transient Response to Uniform Noise' H_str = r'$y_{uni}[n]$' else: logger.error('Unknown stimulus "{0}"'.format(stim)) return if len(sos) > 0: # has second order sections h = sig.sosfilt(sos, x) dc = sig.freqz(self.bb, self.aa, [0]) else: # no second order sections for current filter h = sig.lfilter(self.bb, self.aa, x) dc = sig.freqz(self.bb, self.aa, [0]) if stim == "StepErr": h = h - abs(dc[1]) # subtract DC value from response self.cmplx = np.any(np.iscomplex(h)) if self.cmplx: h_i = h.imag h = h.real H_i_str = r'$\Im\{$' + H_str + '$\}$' H_str = r'$\Re\{$' + H_str + '$\}$' if log: bottom = float(self.ledLogBottom.text()) H_str = r'$|$ ' + H_str + '$|$ in dB' h = np.maximum(20 * np.log10(abs(h)), bottom) if self.cmplx: h_i = np.maximum(20 * np.log10(abs(h_i)), bottom) H_i_str = r'$\log$ ' + H_i_str + ' in dB' else: bottom = 0 self._init_axes() #================ Main Plotting Routine ========================= [ml, sl, bl] = self.ax_r.stem(t, h, bottom=bottom, markerfmt='o', label='$h[n]$') stem_fmt = params['mpl_stimuli'] if self.chkPltStim.isChecked(): [ms, ss, bs] = self.ax_r.stem(t, x, bottom=bottom, label='Stim.', **stem_fmt) ms.set_mfc(stem_fmt['mfc']) ms.set_mec(stem_fmt['mec']) ms.set_ms(stem_fmt['ms']) ms.set_alpha(stem_fmt['alpha']) for stem in ss: stem.set_linewidth(stem_fmt['lw']) stem.set_color(stem_fmt['mec']) stem.set_alpha(stem_fmt['alpha']) bs.set_visible(False) # invisible bottomline expand_lim(self.ax_r, 0.02) self.ax_r.set_title(title_str) if self.cmplx: [ml_i, sl_i, bl_i] = self.ax_i.stem(t, h_i, bottom=bottom, markerfmt='d', label='$h_i[n]$') self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) # self.ax_r.get_xaxis().set_ticklabels([]) # removes both xticklabels # plt.setp(ax_r.get_xticklabels(), visible=False) # is shorter but imports matplotlib, set property directly instead: [label.set_visible(False) for label in self.ax_r.get_xticklabels()] self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $') else: self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_r.set_ylabel(H_str + r'$\rightarrow $') if self.ACTIVE_3D: # not implemented / tested yet # plotting the stems for i in range(len(t)): self.ax3d.plot([t[i], t[i]], [h[i], h[i]], [0, h_i[i]], '-', linewidth=2, alpha=.5) # plotting a circle on the top of each stem self.ax3d.plot(t, h, h_i, 'o', markersize=8, markerfacecolor='none', label='$h[n]$') self.ax3d.set_xlabel('x') self.ax3d.set_ylabel('y') self.ax3d.set_zlabel('z') self.redraw()
def draw_impz(self): """ (Re-)calculate h[n] and draw the figure """ log = self.chkLog.isChecked() stim = str(self.cmbStimulus.currentText()) periodic_sig = stim in {"Sine","Rect", "Saw"} self.lblLogBottom.setVisible(log) self.ledLogBottom.setVisible(log) self.lbldB.setVisible(log) self.lblFreq.setVisible(periodic_sig) self.ledFreq.setVisible(periodic_sig) self.lblFreqUnit.setVisible(periodic_sig) # self.lblFreqUnit.setVisible(fb.fil[0]['freq_specs_unit'] == 'f_S') self.lblFreqUnit.setText(rt_label(fb.fil[0]['freq_specs_unit'])) self.load_entry() self.bb = np.asarray(fb.fil[0]['ba'][0]) self.aa = np.asarray(fb.fil[0]['ba'][1]) sos = np.asarray(fb.fil[0]['sos']) self.f_S = fb.fil[0]['f_S'] N = self.calc_n_points(abs(int(self.ledNPoints.text()))) t = np.linspace(0, N/self.f_S, N, endpoint=False) # calculate h[n] if stim == "Pulse": x = np.zeros(N) x[0] =1.0 # create dirac impulse as input signal title_str = r'Impulse Response' H_str = r'$h[n]$' elif stim == "Step": x = np.ones(N) # create step function title_str = r'Step Response' H_str = r'$h_{\epsilon}[n]$' elif stim == "StepErr": x = np.ones(N) # create step function title_str = r'Settling Error' H_str = r'$H(0) - h_{\epsilon}[n]$' elif stim in {"Sine", "Rect"}: x = np.sin(2 * np.pi * t * float(self.ledFreq.text())) if stim == "Sine": title_str = r'Response to Sine Signal' H_str = r'$h_{\sin}[n]$' else: x = np.sign(x) title_str = r'Response to Rect. Signal' H_str = r'$h_{rect}[n]$' else: x = sig.sawtooth(t * (float(self.ledFreq.text())* 2*np.pi)) title_str = r'Response to Sawtooth Signal' H_str = r'$h_{saw}[n]$' if not np.any(sos): # no second order sections for current filter h = sig.lfilter(self.bb, self.aa, x) dc = sig.freqz(self.bb, self.aa, [0]) else: # print(sos) h = sig.sosfilt(sos, x) dc = sig.freqz(self.bb, self.aa, [0]) if stim == "StepErr": h = h - abs(dc[1]) # subtract DC value from response self.cmplx = np.any(np.iscomplex(h)) if self.cmplx: h_i = h.imag h = h.real H_i_str = r'$\Im\{$' + H_str + '$\}$' H_str = r'$\Re\{$' + H_str + '$\}$' if log: bottom = float(self.ledLogBottom.text()) H_str = r'$|$ ' + H_str + '$|$ in dB' h = np.maximum(20 * np.log10(abs(h)), bottom) if self.cmplx: h_i = np.maximum(20 * np.log10(abs(h_i)), bottom) H_i_str = r'$\log$ ' + H_i_str + ' in dB' else: bottom = 0 self._init_axes() #================ Main Plotting Routine ========================= [ml, sl, bl] = self.ax_r.stem(t, h, bottom=bottom, markerfmt='bo', linefmt='r') if self.chkPltStim.isChecked(): [ms, ss, bs] = self.ax_r.stem(t, x, bottom=bottom, markerfmt='k*', linefmt='0.5') for stem in ss: stem.set_linewidth(0.5) bs.set_visible(False) # invisible bottomline expand_lim(self.ax_r, 0.02) self.ax_r.set_title(title_str) if self.cmplx: [ml_i, sl_i, bl_i] = self.ax_i.stem(t, h_i, bottom=bottom, markerfmt='rd', linefmt='b') self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) # self.ax_r.get_xaxis().set_ticklabels([]) # removes both xticklabels # plt.setp(ax_r.get_xticklabels(), visible=False) # is shorter but imports matplotlib, set property directly instead: [label.set_visible(False) for label in self.ax_r.get_xticklabels()] self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $') else: self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_r.set_ylabel(H_str + r'$\rightarrow $') if self.ACTIVE_3D: # not implemented / tested yet # plotting the stems for i in range(len(t)): self.ax3d.plot([t[i], t[i]], [h[i], h[i]], [0, h_i[i]], '-', linewidth=2, color='b', alpha=.5) # plotting a circle on the top of each stem self.ax3d.plot(t, h, h_i, 'o', markersize=8, markerfacecolor='none', color='b', label='ib') self.ax3d.set_xlabel('x') self.ax3d.set_ylabel('y') self.ax3d.set_zlabel('z') self.mplwidget.redraw()
def draw_impz_time(self): """ (Re-)draw the time domain mplwidget """ if self.y is None: # safety net for empty responses for ax in self.mplwidget_t.fig.get_axes(): # remove all axes self.mplwidget_t.fig.delaxes(ax) return mkfmt_i = 'd' self._init_axes_time() scale_i = scale_o = 1 fx_min = -1. fx_max = 1. fx_title = "" if self.fx_sim: # fixpoint simulation enabled -> scale stimulus and response WI = WO = 1 try: logger.info("hdl_dict = {0}".format(self.hdl_dict)) WI = self.hdl_dict['QI']['W'] WO = self.hdl_dict['QO']['W'] except AttributeError as e: logger.error("Attribute error: {0}".format(e)) except TypeError as e: logger.error("Type error: 'hdl_dict'={0},\n{1}".format(self.hdl_dict, e)) except ValueError as e: logger.error("Value error: {0}".format(e)) if self.ui.chk_fx_scale.isChecked(): scale_i = 1 << WI-1 fx_min = - (1 << WO-1) fx_max = (1 << WO-1) - 1 else: scale_o = 1. / (1 << WO-1) fx_min = -1 fx_max = 1 - scale_o logger.info("scale I:{0} O:{1}".format(scale_i, scale_o)) if self.ui.chk_log_time.isChecked(): # log. scale for stimulus / response time domain H_str = '$|$' + self.H_str + '$|$ in dBV' x = np.maximum(20 * np.log10(abs(self.x * scale_i)), self.bottom_t) y = np.maximum(20 * np.log10(abs(self.y_r * scale_o)), self.bottom_t) win = np.maximum(20 * np.log10(abs(self.ui.win)), self.bottom_t) if self.cmplx: y_i = np.maximum(20 * np.log10(abs(self.y_i)), self.bottom_t) H_i_str = r'$|\Im\{$' + self.H_str + '$\}|$' + ' in dBV' H_str = r'$|\Re\{$' + self.H_str + '$\}|$' + ' in dBV' fx_min = 20*np.log10(abs(fx_min)) fx_max = fx_min else: x = self.x * scale_i y = self.y_r * scale_o win = self.ui.win if self.cmplx: y_i = self.y_i * scale_o if self.cmplx: H_i_str = r'$\Im\{$' + self.H_str + '$\}$ in V' H_str = r'$\Re\{$' + self.H_str + '$\}$ in V' else: H_str = self.H_str + ' in V' if self.ui.chk_fx_range.isChecked() and self.fx_sim: self.ax_r.axhline(fx_max,0, 1, color='k', linestyle='--') self.ax_r.axhline(fx_min,0, 1, color='k', linestyle='--') # --------------- Stimulus plot ---------------------------------- plot_stim_dict = self.fmt_plot_stim.copy() plot_stim_fnc = self.plot_fnc(self.plt_time_stim, self.ax_r, plot_stim_dict, self.bottom_t) plot_stim_fnc(self.t[self.ui.N_start:], x[self.ui.N_start:], label='$x[n]$', **plot_stim_dict) # Add plot markers, this is way faster than normal stem plotting if self.ui.chk_mrk_time_stim.isChecked() and self.plt_time_stim not in {"dots","none"}: self.ax_r.scatter(self.t[self.ui.N_start:], x[self.ui.N_start:], **self.fmt_mkr_stim) # --------------- Response plot ---------------------------------- plot_resp_dict = self.fmt_plot_resp.copy() plot_resp_fnc = self.plot_fnc(self.plt_time_resp, self.ax_r, plot_resp_dict, self.bottom_t) plot_resp_fnc(self.t[self.ui.N_start:], y[self.ui.N_start:], label='$y[n]$', **plot_resp_dict) # Add plot markers, this is way faster than normal stem plotting if self.ui.chk_mrk_time_resp.isChecked() and self.plt_time_resp not in {"dots","none"}: self.ax_r.scatter(self.t[self.ui.N_start:], y[self.ui.N_start:], **self.fmt_mkr_resp) # --------------- Window plot ---------------------------------- if self.ui.chk_win_time.isChecked(): self.ax_r.plot(self.t[self.ui.N_start:], win, c="gray", label=self.ui.window_type) self.ax_r.legend(loc='best', fontsize = 'small', fancybox=True, framealpha=0.5) # --------------- Complex response ---------------------------------- if self.cmplx and self.plt_time_resp != "none": #plot_resp_dict = self.fmt_plot_resp.copy() plot_resp_fnc = self.plot_fnc(self.plt_time_resp, self.ax_i, plot_resp_dict, self.bottom_t) plot_resp_fnc(self.t[self.ui.N_start:], y_i[self.ui.N_start:], label='$y_i[n]$', **plot_resp_dict) # Add plot markers, this is way faster than normal stem plotting if self.ui.chk_mrk_time_resp.isChecked() and self.plt_time_resp not in {"dots","none"}: self.ax_i.scatter(self.t[self.ui.N_start:], y_i[self.ui.N_start:], marker=mkfmt_i, **self.fmt_mkr_resp) # [ml_i, sl_i, bl_i] = self.ax_i.stem(self.t[self.ui.N_start:], y_i[self.ui.N_start:], # bottom=self.bottom_t, markerfmt=mkfmt_i, label = '$y_i[n]$') # self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) # self.ax_r.get_xaxis().set_ticklabels([]) # removes both xticklabels # plt.setp(ax_r.get_xticklabels(), visible=False) # is shorter but imports matplotlib, set property directly instead: [label.set_visible(False) for label in self.ax_r.get_xticklabels()] self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $') self.ax_i.legend(loc='best', fontsize = 'small', fancybox=True, framealpha=0.5) else: self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_r.set_title(fx_title + self.title_str) self.ax_r.set_xlim([self.t[self.ui.N_start],self.t[self.ui.N_end-1]]) expand_lim(self.ax_r, 0.02) if self.ACTIVE_3D: # not implemented / tested yet # plotting the stems for i in range(self.ui.N_start, self.ui.N_end): self.ax3d.plot([self.t[i], self.t[i]], [y[i], y[i]], [0, y_i[i]], '-', linewidth=2, alpha=.5) # plotting a circle on the top of each stem self.ax3d.plot(self.t[self.ui.N_start:], y[self.ui.N_start:], y_i[self.ui.N_start:], 'o', markersize=8, markerfacecolor='none', label='$y[n]$') self.ax3d.set_xlabel('x') self.ax3d.set_ylabel('y') self.ax3d.set_zlabel('z') self.redraw() # redraw currently active mplwidget
def draw_impz_time(self): """ (Re-)draw the time domain mplwidget """ if self.y is None: # safety net for empty responses for ax in self.mplwidget_t.fig.get_axes(): # remove all axes self.mplwidget_t.fig.delaxes(ax) return mkfmt_i = 'd' self._init_axes_time() scale_i = scale_o = 1 fx_min = -1. fx_max = 1. fx_title = "" if self.fx_sim: # fixpoint simulation enabled -> scale stimulus and response WI = WO = 1 try: logger.info("hdl_dict = {0}".format(self.hdl_dict)) WI = self.hdl_dict['QI']['W'] WO = self.hdl_dict['QO']['W'] except AttributeError as e: logger.error("Attribute error: {0}".format(e)) except TypeError as e: logger.error("Type error: 'hdl_dict'={0},\n{1}".format( self.hdl_dict, e)) except ValueError as e: logger.error("Value error: {0}".format(e)) if self.ui.chk_fx_scale.isChecked(): scale_i = 1 << WI - 1 fx_min = -(1 << WO - 1) fx_max = (1 << WO - 1) - 1 else: scale_o = 1. / (1 << WO - 1) fx_min = -1 fx_max = 1 - scale_o logger.info("scale I:{0} O:{1}".format(scale_i, scale_o)) if self.ui.chk_log_time.isChecked( ): # log. scale for stimulus / response time domain H_str = '$|$' + self.H_str + '$|$ in dBV' x = np.maximum(20 * np.log10(abs(self.x * scale_i)), self.bottom_t) y = np.maximum(20 * np.log10(abs(self.y_r * scale_o)), self.bottom_t) win = np.maximum(20 * np.log10(abs(self.ui.win)), self.bottom_t) if self.cmplx: y_i = np.maximum(20 * np.log10(abs(self.y_i)), self.bottom_t) H_i_str = r'$|\Im\{$' + self.H_str + '$\}|$' + ' in dBV' H_str = r'$|\Re\{$' + self.H_str + '$\}|$' + ' in dBV' fx_min = 20 * np.log10(abs(fx_min)) fx_max = fx_min else: x = self.x * scale_i y = self.y_r * scale_o win = self.ui.win if self.cmplx: y_i = self.y_i * scale_o if self.cmplx: H_i_str = r'$\Im\{$' + self.H_str + '$\}$ in V' H_str = r'$\Re\{$' + self.H_str + '$\}$ in V' else: H_str = self.H_str + ' in V' if self.ui.chk_fx_range.isChecked() and self.fx_sim: self.ax_r.axhline(fx_max, 0, 1, color='k', linestyle='--') self.ax_r.axhline(fx_min, 0, 1, color='k', linestyle='--') # --------------- Stimulus plot ---------------------------------- plot_stim_dict = self.fmt_plot_stim.copy() plot_stim_fnc = self.plot_fnc(self.plt_time_stim, self.ax_r, plot_stim_dict, self.bottom_t) plot_stim_fnc(self.t[self.ui.N_start:], x[self.ui.N_start:], label='$x[n]$', **plot_stim_dict) # Add plot markers, this is way faster than normal stem plotting if self.ui.chk_mrk_time_stim.isChecked( ) and self.plt_time_stim not in {"dots", "none"}: self.ax_r.scatter(self.t[self.ui.N_start:], x[self.ui.N_start:], **self.fmt_mkr_stim) # --------------- Response plot ---------------------------------- plot_resp_dict = self.fmt_plot_resp.copy() plot_resp_fnc = self.plot_fnc(self.plt_time_resp, self.ax_r, plot_resp_dict, self.bottom_t) plot_resp_fnc(self.t[self.ui.N_start:], y[self.ui.N_start:], label='$y[n]$', **plot_resp_dict) # Add plot markers, this is way faster than normal stem plotting if self.ui.chk_mrk_time_resp.isChecked( ) and self.plt_time_resp not in {"dots", "none"}: self.ax_r.scatter(self.t[self.ui.N_start:], y[self.ui.N_start:], **self.fmt_mkr_resp) # --------------- Window plot ---------------------------------- if self.ui.chk_win_time.isChecked(): self.ax_r.plot(self.t[self.ui.N_start:], win, c="gray", label=self.ui.window_type) self.ax_r.legend(loc='best', fontsize='small', fancybox=True, framealpha=0.5) # --------------- Complex response ---------------------------------- if self.cmplx and self.plt_time_resp != "none": #plot_resp_dict = self.fmt_plot_resp.copy() plot_resp_fnc = self.plot_fnc(self.plt_time_resp, self.ax_i, plot_resp_dict, self.bottom_t) plot_resp_fnc(self.t[self.ui.N_start:], y_i[self.ui.N_start:], label='$y_i[n]$', **plot_resp_dict) # Add plot markers, this is way faster than normal stem plotting if self.ui.chk_mrk_time_resp.isChecked( ) and self.plt_time_resp not in {"dots", "none"}: self.ax_i.scatter(self.t[self.ui.N_start:], y_i[self.ui.N_start:], marker=mkfmt_i, **self.fmt_mkr_resp) # [ml_i, sl_i, bl_i] = self.ax_i.stem(self.t[self.ui.N_start:], y_i[self.ui.N_start:], # bottom=self.bottom_t, markerfmt=mkfmt_i, label = '$y_i[n]$') # self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) # self.ax_r.get_xaxis().set_ticklabels([]) # removes both xticklabels # plt.setp(ax_r.get_xticklabels(), visible=False) # is shorter but imports matplotlib, set property directly instead: [label.set_visible(False) for label in self.ax_r.get_xticklabels()] self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $') self.ax_i.legend(loc='best', fontsize='small', fancybox=True, framealpha=0.5) else: self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_r.set_title(fx_title + self.title_str) self.ax_r.set_xlim( [self.t[self.ui.N_start], self.t[self.ui.N_end - 1]]) expand_lim(self.ax_r, 0.02) if self.ACTIVE_3D: # not implemented / tested yet # plotting the stems for i in range(self.ui.N_start, self.ui.N_end): self.ax3d.plot([self.t[i], self.t[i]], [y[i], y[i]], [0, y_i[i]], '-', linewidth=2, alpha=.5) # plotting a circle on the top of each stem self.ax3d.plot(self.t[self.ui.N_start:], y[self.ui.N_start:], y_i[self.ui.N_start:], 'o', markersize=8, markerfacecolor='none', label='$y[n]$') self.ax3d.set_xlabel('x') self.ax3d.set_ylabel('y') self.ax3d.set_zlabel('z') self.redraw() # redraw currently active mplwidget
def draw_impz(self): """ (Re-)calculate h[n] and draw the figure """ log = self.chkLog.isChecked() stim = str(self.cmbStimulus.currentText()) periodic_sig = stim in {"Cos", "Sine","Rect", "Saw"} self.lblLogBottom.setVisible(log) self.ledLogBottom.setVisible(log) self.lbldB.setVisible(log) self.lblFreq.setVisible(periodic_sig) self.ledFreq.setVisible(periodic_sig) self.lblFreqUnit.setVisible(periodic_sig) self.lblFreqUnit.setText(rt_label(fb.fil[0]['freq_specs_unit'])) self.load_dict() self.bb = np.asarray(fb.fil[0]['ba'][0]) self.aa = np.asarray(fb.fil[0]['ba'][1]) if min(len(self.aa), len(self.bb)) < 2: logger.error('No proper filter coefficients: len(a), len(b) < 2 !') return sos = np.asarray(fb.fil[0]['sos']) antiCausal = 'zpkA' in fb.fil[0] causal = not (antiCausal) self.f_S = fb.fil[0]['f_S'] N_entry = safe_eval(self.ledNPoints.text(), 0, return_type='int', sign='pos') N = self.calc_n_points(N_entry) if N_entry != 0: # automatic calculation self.ledNPoints.setText(str(N)) self.A = safe_eval(self.ledAmp.text(), self.A, return_type='float') self.ledAmp.setText(str(self.A)) t = np.linspace(0, N/self.f_S, N, endpoint=False) title_str = r'Impulse Response' # default H_str = r'$h[n]$' # default # calculate h[n] if stim == "Pulse": x = np.zeros(N) x[0] = self.A # create dirac impulse as input signal elif stim == "Step": x = self.A * np.ones(N) # create step function title_str = r'Step Response' H_str = r'$h_{\epsilon}[n]$' elif stim == "StepErr": x = self.A * np.ones(N) # create step function title_str = r'Settling Error' H_str = r'$h_{\epsilon, \infty} - h_{\epsilon}[n]$' elif stim in {"Cos"}: x = self.A * np.cos(2 * np.pi * t * float(self.ledFreq.text())) if stim == "Cos": title_str = r'Transient Response to Cosine Signal' H_str = r'$y_{\cos}[n]$' elif stim in {"Sine", "Rect"}: x = self.A * np.sin(2 * np.pi * t * float(self.ledFreq.text())) if stim == "Sine": title_str = r'Transient Response to Sine Signal' H_str = r'$y_{\sin}[n]$' else: x = self.A * np.sign(x) title_str = r'Transient Response to Rect. Signal' H_str = r'$y_{rect}[n]$' elif stim == "Saw": x = self.A * sig.sawtooth(t * (float(self.ledFreq.text())* 2*np.pi)) title_str = r'Transient Response to Sawtooth Signal' H_str = r'$y_{saw}[n]$' elif stim == "RandN": x = self.A * np.random.randn(N) title_str = r'Transient Response to Gaussian Noise' H_str = r'$y_{gauss}[n]$' elif stim == "RandU": x = self.A * (np.random.rand(N)-0.5) title_str = r'Transient Response to Uniform Noise' H_str = r'$y_{uni}[n]$' else: logger.error('Unknown stimulus "{0}"'.format(stim)) return if len(sos) > 0 and (causal): # has second order sections and is causal h = sig.sosfilt(sos, x) elif (antiCausal): h = sig.filtfilt(self.bb, self.aa, x, -1, None) else: # no second order sections or antiCausals for current filter h = sig.lfilter(self.bb, self.aa, x) dc = sig.freqz(self.bb, self.aa, [0]) if stim == "StepErr": h = h - abs(dc[1]) # subtract DC value from response h = np.real_if_close(h, tol = 1e3) # tol specified in multiples of machine eps self.cmplx = np.any(np.iscomplex(h)) if self.cmplx: h_i = h.imag h = h.real H_i_str = r'$\Im\{$' + H_str + '$\}$' H_str = r'$\Re\{$' + H_str + '$\}$' if log: self.bottom = safe_eval(self.ledLogBottom.text(), self.bottom, return_type='float') self.ledLogBottom.setText(str(self.bottom)) H_str = r'$|$ ' + H_str + '$|$ in dB' h = np.maximum(20 * np.log10(abs(h)), self.bottom) if self.cmplx: h_i = np.maximum(20 * np.log10(abs(h_i)), self.bottom) H_i_str = r'$\log$ ' + H_i_str + ' in dB' else: self.bottom = 0 self.init_axes() #================ Main Plotting Routine ========================= [ml, sl, bl] = self.ax_r.stem(t, h, bottom=self.bottom, markerfmt='o', label = '$h[n]$') stem_fmt = params['mpl_stimuli'] if self.chkPltStim.isChecked(): [ms, ss, bs] = self.ax_r.stem(t, x, bottom=self.bottom, label = 'Stim.', **stem_fmt) ms.set_mfc(stem_fmt['mfc']) ms.set_mec(stem_fmt['mec']) ms.set_ms(stem_fmt['ms']) ms.set_alpha(stem_fmt['alpha']) for stem in ss: stem.set_linewidth(stem_fmt['lw']) stem.set_color(stem_fmt['mec']) stem.set_alpha(stem_fmt['alpha']) bs.set_visible(False) # invisible bottomline expand_lim(self.ax_r, 0.02) self.ax_r.set_title(title_str) if self.cmplx: [ml_i, sl_i, bl_i] = self.ax_i.stem(t, h_i, bottom=self.bottom, markerfmt='d', label = '$h_i[n]$') self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) # self.ax_r.get_xaxis().set_ticklabels([]) # removes both xticklabels # plt.setp(ax_r.get_xticklabels(), visible=False) # is shorter but imports matplotlib, set property directly instead: [label.set_visible(False) for label in self.ax_r.get_xticklabels()] self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $') else: self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_r.set_ylabel(H_str + r'$\rightarrow $') if self.ACTIVE_3D: # not implemented / tested yet # plotting the stems for i in range(len(t)): self.ax3d.plot([t[i], t[i]], [h[i], h[i]], [0, h_i[i]], '-', linewidth=2, alpha=.5) # plotting a circle on the top of each stem self.ax3d.plot(t, h, h_i, 'o', markersize=8, markerfacecolor='none', label='$h[n]$') self.ax3d.set_xlabel('x') self.ax3d.set_ylabel('y') self.ax3d.set_zlabel('z') self.redraw()
def draw_impz(self): """ (Re-)draw the figure """ f_unit = fb.fil[0]['freq_specs_unit'] if f_unit in {"f_S", "f_Ny"}: unit_frmt = "i" # italic else: unit_frmt = None self.ui.lblFreqUnit1.setText(to_html(f_unit, frmt=unit_frmt)) self.ui.lblFreqUnit2.setText(to_html(f_unit, frmt=unit_frmt)) N_start = self.ui.N_start self.load_fs() self.init_axes() #================ Main Plotting Routine ========================= if self.ui.chkMarker.isChecked(): mkfmt_r = 'o' mkfmt_i = 'd' else: mkfmt_r = mkfmt_i = ' ' if self.cmplx: H_i_str = r'$\Im\{$' + self.H_str + '$\}$ in V' H_str = r'$\Re\{$' + self.H_str + '$\}$ in V' else: H_str = self.H_str + 'in V' if self.ui.chkLog.isChecked(): H_str = r'$|$ ' + H_str + '$|$ in dBV' y = np.maximum(20 * np.log10(abs(self.y)), self.ui.bottom) if self.cmplx: y_i = np.maximum(20 * np.log10(abs(self.y_i)), self.ui.bottom) H_i_str = r'$\log$ ' + H_i_str + ' in dBV' else: self.ui.bottom = 0 y = self.y y_i = self.y_i if self.ui.plt_time in {"Response", "Both"}: [ml, sl, bl] = self.ax_r.stem(self.t[N_start:], y[N_start:], bottom=self.ui.bottom, markerfmt=mkfmt_r, label = '$y[n]$') if self.ui.plt_time in {"Stimulus", "Both"}: stem_fmt = params['mpl_stimuli'] [ms, ss, bs] = self.ax_r.stem(self.t[N_start:], self.x[N_start:], bottom=self.ui.bottom, label = 'Stim.', **stem_fmt) ms.set_mfc(stem_fmt['mfc']) ms.set_mec(stem_fmt['mec']) ms.set_ms(stem_fmt['ms']) ms.set_alpha(stem_fmt['alpha']) for stem in ss: stem.set_linewidth(stem_fmt['lw']) stem.set_color(stem_fmt['mec']) stem.set_alpha(stem_fmt['alpha']) bs.set_visible(False) # invisible bottomline if self.cmplx and self.ui.plt_time in {"Response", "Both"}: [ml_i, sl_i, bl_i] = self.ax_i.stem(self.t[N_start:], y_i[N_start:], bottom=self.ui.bottom, markerfmt=mkfmt_i, label = '$y_i[n]$') self.ax_i.set_xlabel(fb.fil[0]['plt_tLabel']) # self.ax_r.get_xaxis().set_ticklabels([]) # removes both xticklabels # plt.setp(ax_r.get_xticklabels(), visible=False) # is shorter but imports matplotlib, set property directly instead: [label.set_visible(False) for label in self.ax_r.get_xticklabels()] self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_i.set_ylabel(H_i_str + r'$\rightarrow $') else: self.ax_r.set_xlabel(fb.fil[0]['plt_tLabel']) self.ax_r.set_ylabel(H_str + r'$\rightarrow $') self.ax_r.set_title(self.title_str) self.ax_r.set_xlim([self.t[N_start],self.t[self.ui.N_end-1]]) expand_lim(self.ax_r, 0.02) # plot frequency domain ========================================= if self.ui.plt_freq != "None": plt_response = self.ui.plt_freq in {"Response","Both"} plt_stimulus = self.ui.plt_freq in {"Stimulus","Both"} if plt_response and not plt_stimulus: XY_str = r'$|Y(\mathrm{e}^{\mathrm{j} \Omega})|$' elif not plt_response and plt_stimulus: XY_str = r'$|X(\mathrm{e}^{\mathrm{j} \Omega})|$' else: XY_str = r'$|X,Y(\mathrm{e}^{\mathrm{j} \Omega})|$' F = np.fft.fftfreq(self.ui.N, d = 1. / fb.fil[0]['f_S']) if plt_stimulus: X = self.X.copy()/np.sqrt(2) # enforce deep copy and convert to RMS self.Px = np.sum(np.square(self.X)) if fb.fil[0]['freqSpecsRangeType'] == 'half': X[1:] = 2 * X[1:] # correct for single-sided spectrum (except DC) if plt_response: Y = self.Y.copy()/np.sqrt(2) # enforce deep copy and convert to RMS self.Py = np.sum(np.square(self.Y)) if fb.fil[0]['freqSpecsRangeType'] == 'half': Y[1:] = 2 * Y[1:] # correct for single-sided spectrum (except DC) if self.ui.chkLogF.isChecked(): unit = unit_P = "dBW" unit_nenbw = "dB" nenbw = 10 * np.log10(self.ui.nenbw) if plt_stimulus: X = np.maximum(20 * np.log10(X), self.ui.bottom_f) self.Px = 10*np.log10(self.Px) if plt_response: Y = np.maximum(20 * np.log10(Y), self.ui.bottom_f) self.Py = 10*np.log10(self.Py) else: unit = "Vrms" unit_P = "W" unit_nenbw = "bins" nenbw = self.ui.nenbw XY_str = XY_str + ' in ' + unit if fb.fil[0]['freqSpecsRangeType'] == 'sym': # shift X, Y and F by f_S/2 if plt_response: Y = np.fft.fftshift(Y) if plt_stimulus: X = np.fft.fftshift(X) F = np.fft.fftshift(F) elif fb.fil[0]['freqSpecsRangeType'] == 'half': # only use the first half of X, Y and F if plt_response: Y = Y[0:self.ui.N//2] if plt_stimulus: X = X[0:self.ui.N//2] F = F[0:self.ui.N//2] else: # fb.fil[0]['freqSpecsRangeType'] == 'whole' # plot for F = 0 ... 1 F = np.fft.fftshift(F) + fb.fil[0]['f_S']/2. handles = [] labels = [] if plt_stimulus: h, = self.ax_fft.plot(F, X, color =(0.5,0.5,0.5,0.5), lw=2) handles.append(h) labels.append("$P_X$ = {0:.3g} {1}".format(self.Px, unit_P)) if plt_response: h, = self.ax_fft.plot(F, Y) handles.append(h) labels.append("$P_Y$ = {0:.3g} {1}".format(self.Py, unit_P)) labels.append("$NENBW$ = {0:.4g} {1}".format(nenbw, unit_nenbw)) labels.append("$CGAIN$ = {0:.4g}".format(self.ui.scale)) handles.append(mpl_patches.Rectangle((0, 0), 1, 1, fc="white",ec="white", lw=0)) handles.append(mpl_patches.Rectangle((0, 0), 1, 1, fc="white",ec="white", lw=0)) self.ax_fft.legend(handles, labels, loc='best', fontsize = 'small', fancybox=True, framealpha=0.5) self.ax_fft.set_xlabel(fb.fil[0]['plt_fLabel']) self.ax_fft.set_ylabel(XY_str) self.ax_fft.set_xlim(fb.fil[0]['freqSpecsRange']) if self.ui.plt_time == "None": self.ax_fft.set_title(self.title_str) # no time window, print title here if self.ui.chkLogF.isChecked(): # create second axis scaled for noise power scale self.ax_fft_noise = self.ax_fft.twinx() self.ax_fft_noise.is_twin = True corr = 10*np.log10(self.ui.N / self.ui.nenbw) mn, mx = self.ax_fft.get_ylim() self.ax_fft_noise.set_ylim(mn+corr, mx+corr) self.ax_fft_noise.set_ylabel(r'$P_N$ in dBW') if self.ACTIVE_3D: # not implemented / tested yet # plotting the stems for i in range(N_start, self.ui.N_end): self.ax3d.plot([self.t[i], self.t[i]], [y[i], y[i]], [0, y_i[i]], '-', linewidth=2, alpha=.5) # plotting a circle on the top of each stem self.ax3d.plot(self.t[N_start:], y[N_start:], y_i[N_start:], 'o', markersize=8, markerfacecolor='none', label='$y[n]$') self.ax3d.set_xlabel('x') self.ax3d.set_ylabel('y') self.ax3d.set_zlabel('z') self.redraw()