def get_measured_receptance(show=False): freq, H = get_measured_accelerance(show=False) omega = 2 * np.pi * freq H = convert_frf(H, omega, inputFRFtype='a', outputFRFtype='d') if show: plt.semilogy(freq, np.abs(H[:, :])) plt.show() return freq, H
def get_measured_receptance(show=False): freq, H = get_measured_accelerance(show=False) omega = 2*np.pi*freq H = convert_frf(H, omega, inputFRFtype = 'a', outputFRFtype = 'd') if show: plt.semilogy(freq,np.abs(H[:,:])) plt.show() return freq, H
def _get_fft(self): """Calculates the fft ndarray of the most recent measurement data :return: """ # define FRF - related variables (only for the first measurement) if self.curr_meas == 0: if self.fft_len is None: self.fft_len = self.samples self.w_axis = 2 * np.pi * np.fft.rfftfreq(self.fft_len, 1. / self.sampling_freq) self.Exc = np.fft.rfft(self.exc, self.fft_len) self.Resp = np.fft.rfft(self.resp, self.fft_len) if self.resp_type != 'e': # if not strain # convert response to 'a' type self.Resp = fft_tools.convert_frf(self.Resp, self.w_axis, input_frf_type=self.resp_type, output_frf_type='a') # correct delay if self.resp_delay != 0.: self.Exc = fft_tools.correct_time_delay(self.Exc, self.w_axis, self.resp_delay)
def ewins(freq, H, nf='None', residues=False, type='d', o_fr=0): """ Arguments: - freq - frequency vector - H - a row or a column of FRF matrix - o_fr - list of optionally chosen frequencies in Hz. If it is not set, optional points are set automatically and are near the natural frequencies (10 points higher than natural frequencies) - nf - natural frequencies [Hz] -ref - index of reference node - residues - if 1 residues of lower and higher residues are taken into account - if 0 residues of lower and higher residues are not taken into account - type - type of FRF function: -'d'- receptance -'v'- mobility -'a'- accelerance """ om = freq * 2 * np.pi H2 = convert_frf(H, om, type, outputFRFtype = 'a') # converts FRF to accalerance if nf != 'None': ind = (np.round(nf / (freq[2] - freq[1]))) ind = np.array(ind, dtype=int) if ind == 'None': print ('***ERROR***Natural frequencies are not defined') quit() #determination of N points which are chosen optionally if o_fr == 0 and residues == True: ind_opt = np.zeros((len(ind) + 2), dtype='int') ind_opt[0] = 20 ind_opt[1:-1] = ind + 20 ind_opt[-1] = len(freq) - 20 if o_fr == 0 and residues == False: ind_opt = np.zeros((len(ind)), dtype='int') ind_opt = ind + 10 if o_fr != 0: ind_opt = (np.round(o_fr / (freq[2] - freq[1]))) ind_opt = np.array(ind_opt, dtype=int) #matrix of modal damping mi = np.zeros((len(ind), len(H2[0, :]))) Real = np.real(H2[:, 0]) #self.Imag=np.imag(self.FRF[:,0]) R = np.zeros((len(ind_opt), len(ind_opt))) A_ref = np.zeros((len(ind_opt), len(H2[0, :]))) #modal constant of FRF FI = np.zeros((len(ind_opt), len(H2[0, :])), dtype=complex) #mass normalized modal #vector R[:, 0] = np.ones(len(ind_opt)) for jj in range (0, len(ind_opt)): R[jj, -1] = -(om[ind_opt[jj]]) ** 2 if residues == True: R[jj, 1:-1] = (om[ind_opt[jj]]) ** 2 / ((om[ind[:]]) ** 2 - (om[ind_opt[jj]]) ** 2) if residues == False: R[jj, :] = (om[ind_opt[jj]]) ** 2 / ((om[ind[:]]) ** 2 - (om[ind_opt[jj]]) ** 2) R = np.linalg.inv(R) for j in range (0, len(H2[:, 0])): Re_pt = np.real(H2[j, ind_opt]) Re_pt = np.matrix(Re_pt) C = np.dot(R, Re_pt.transpose()) #modal constant of one FRF A_ref[:, j] = -C.flatten() #modal constant of all FRFs if residues == True: mi[:, j] = np.abs(C[1:-1].transpose()) / (np.abs(H2[j, ind[:]])) #modal damping if residues == False: mi[:, j] = np.abs(C[:].transpose()) / (np.abs(H2[j, ind[:]])) #modal damping # for kk in range(0, len(ind_opt)): # FI[kk, :] = -A_ref[kk, :] / np.sqrt(np.abs(A_ref[kk, refPT])) #calculation of # #normalized modal vector if residues == True: #return FI[1:-1, :], mi return A_ref, mi if residues == False: return A_ref, mi
def reconstruction(freq, nfreq, A, d, damping='hysteretic', type='a', residues=False, LR=0, UR=0): """generates a FRF from modal parameters. There is option to consider the upper and lower residues (Ewins, D.J. and Gleeson, P. T.: A method for modal identification of lightly damped structures) #TODO: check the correctness of the viscous damping reconstruction Arguments: A - Modal constants of the considering FRF. nfreq - natural frequencies in Hz c - damping loss factor or damping ratio damp - type of damping: -'hysteretic' -'viscous' LR - lower residue UR - upper residue residues - if 'True' the residues of lower and higher residues are taken into account. The lower and upper residues are first and last component of A, respectively. type - type of FRF function: -'d'- receptance -'v'- mobility -'a'- accelerance """ A = np.array(A, dtype='complex') d=np.array(d) om = np.array(2 * np.pi * freq) nom = np.array(2 * np.pi * nfreq) #in the case of single mode the 1D arrays have to be created if A.shape==(): A_=A; d_=d ; nom_=nom A=np.zeros((1),dtype='complex'); d=np.zeros(1) ; nom=np.zeros(1) A[0]=A_ ; d[0]=d_ nom[0]=nom_ if residues: LR = np.array(LR) UR = np.array(UR) H = np.zeros(len(freq), dtype=complex) if damping == 'hysteretic': #calculation of a FRF for i in range(0, len(freq)): for k in range(0, len(nom)): H[i] = H[i] + A[k] / (nom[k] ** 2 - om[i] ** 2 + d[k] * 1j * nom[k] ** 2) if residues: for i in range(1, len(freq)): H[i] = H[i] + LR / om[i] ** 2 - UR if damping == 'viscous': H = np.zeros(len(freq), dtype=complex) for i in range(0, len(freq)): for k in range(0, len(nom)): H[i]=H[i]+ A[k] / (nom[k] ** 2 - om[i] ** 2 + 2.j * om[i] * nom[k] * d[k]) H = convert_frf(H, om, 'd' ,type) return H