<jupyter_start><jupyter_text>11 in-situ TPAThe in-situ Transfer Path Analysis (TPA) is a method where equivalent forces can be determined by means of in-situ characterisation. First step is to measure FRFs  $\textbf{Y}_{42}$ on the passive system and the second to measure response $\textbf{u}_4$ (indicator sensors) with active source. Equivalent forces can then be calculated as:$\textbf{f}_{\text{eq}} = (\textbf{Y}_{42})^{-1} \textbf{u}_4.$<jupyter_code>import pyFBS

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
%matplotlib inline
from matplotlib.colors import LogNorm
from matplotlib import cm<jupyter_output><empty_output><jupyter_text>Example DatasestsLoad the required predefined datasets:<jupyter_code>pyFBS.download_lab_testbench()
pos_xlsx = r"./lab_testbench/Measurements/TPA_synt.xlsx"

stl_dir_A = r"./lab_testbench/STL/A.stl"
stl_dir_B = r"./lab_testbench/STL/B.stl"
stl_dir_AB = r"./lab_testbench/STL/AB.stl"

df_acc_AB = pd.read_excel(pos_xlsx, sheet_name='Sensors_AB')
df_chn_AB = pd.read_excel(pos_xlsx, sheet_name='Channels_AB')
df_imp_AB = pd.read_excel(pos_xlsx, sheet_name='Impacts_AB')<jupyter_output><empty_output><jupyter_text>3D viewOpen 3D viewer in the background.<jupyter_code>view3D = pyFBS.view3D()<jupyter_output><empty_output><jupyter_text>Display AB structure and sensors, channels and impacts.<jupyter_code>view3D.plot.add_text("AB structure", position='upper_left', font_size=10, color="k", font="times", name="AB_structure");

_ = view3D.add_stl(stl_dir_B,name = "B");
_ = view3D.add_stl(stl_dir_A,color = "#83afd2",name = "A");

view3D.show_acc(df_acc_AB)
view3D.show_imp(df_imp_AB)
view3D.show_chn(df_chn_AB)<jupyter_output><empty_output><jupyter_text>Numerical modelLoad the corresponding .full and .ress file from the example datasets. For more information on .full and .ress files refer to the *03_FRF_synthetization.ipynb* example<jupyter_code>full_file_AB = r"./lab_testbench/FEM/AB.full"
ress_file_AB = r"./lab_testbench/FEM/AB.rst"<jupyter_output><empty_output><jupyter_text>Create an MK model for each component:<jupyter_code>MK_AB = pyFBS.MK_model(ress_file_AB,full_file_AB,no_modes = 100,allow_pickle= True,recalculate = False)<jupyter_output>C:\Users\tomaz.bregar\Anaconda3\lib\site-packages\pyvista\core\pointset.py:610: UserWarning: VTK 9 no longer accepts an offset array
  warnings.warn('VTK 9 no longer accepts an offset array')<jupyter_text>Update locations of channels and impacts to snap to the nearest FE node.<jupyter_code>df_chn_AB_up = MK_AB.update_locations_df(df_chn_AB)
df_imp_AB_up = MK_AB.update_locations_df(df_imp_AB)<jupyter_output><empty_output><jupyter_text>Perform the FRF sythetization for each component based on the updated locations.<jupyter_code>MK_AB.FRF_synth(df_chn_AB_up,df_imp_AB_up,f_start = 0,f_end = 10000,f_resolution = 1,modal_damping = 0.003,frf_type = "receptance")

freq = MK_AB.freq
FRF = MK_AB.FRF<jupyter_output><empty_output><jupyter_text>Virtual point transformationPrepare the reduction matrices for the VPT.<jupyter_code>df_vp = pd.read_excel(pos_xlsx, sheet_name='VP_Channels')
df_vpref = pd.read_excel(pos_xlsx, sheet_name='VP_RefChannels')

vpt_AB = pyFBS.VPT(df_chn_AB_up,df_imp_AB_up,df_vp,df_vpref)<jupyter_output><empty_output><jupyter_text>Application of the in-situ TPA To simplify the measurement of the $\textbf{Y}_{42}$ the VPT can be applied on the interface excitation to transform forces at the interface into virtual DoFs (from $\textbf{Y}_{\text{uf}}$ to $\textbf{Y}_{\text{um}}$). Therefore, the interface is loaded with three forces ($F_x$, $F_y$, $F_z$) and ($M_x$, $M_y$, $M_z$)<jupyter_code>Y_um = FRF @ vpt_AB.Tf<jupyter_output><empty_output><jupyter_text>Select operational DoFs $\textbf{u}_4$ and indicator DoFs $\textbf{u}_3$<jupyter_code>select_op = 10

u4_op = MK_AB.FRF[:,:9,select_op:select_op+1]
u3_op = MK_AB.FRF[:,9:,select_op:select_op+1]<jupyter_output><empty_output><jupyter_text>Calculate blocked forces $\textbf{f}_{\text{eq}}$  at the interface<jupyter_code>f_eq = np.linalg.pinv(Y_um[:,:9,:6])@u4_op<jupyter_output><empty_output><jupyter_text>TPA prediction at theinterface<jupyter_code>_Y_temp = Y_um[:,9:,:6]
u3_tpa = _Y_temp@f_eq<jupyter_output><empty_output><jupyter_text>On-board validation: comparison of predicted $\textbf{u}_3^{\text{TPA}}$ and operational $\textbf{u}_3^{\text{op}}$.<jupyter_code>sel_out = 7

plt.figure(figsize = (10,5))

plt.subplot(211)
plt.semilogy(freq,np.abs(u3_tpa[:,sel_out,0]))
plt.semilogy(freq,np.abs(u3_op[:,sel_out,0]))
plt.xlim(0,2000)


plt.subplot(413)
plt.plot(freq,np.angle(u3_tpa[:,sel_out,0]))
plt.plot(freq,np.angle(u3_op[:,sel_out,0]))
plt.xlim(0,2000)<jupyter_output><empty_output><jupyter_text>Partial Transfer PathsPartial transfer path can be calculated and evaluated.<jupyter_code>sel_i = 1
u_partial = []

for j in range(6):
    gg = _Y_temp[:,sel_i:sel_i+1,j:j+1]@f_eq[:,j:j+1,0:1]
    u_partial.append(gg[:,0,0])
    
u_partial = np.asarray(u_partial).T<jupyter_output><empty_output><jupyter_text>An intuitive way to look at the contribution of each path is looking on<jupyter_code>plt.figure(figsize = (10,3))

values = np.abs(u_partial).T
plt.imshow(values,interpolation='nearest', cmap=cm.jet,norm=LogNorm(vmin=np.min(values), vmax=np.max(values)),aspect = 'auto')

plt.xlim(0,4000)

plt.yticks(range(6),["Fx","Fy","Fz","Mx","My","Mz"])
plt.xlabel("Frequency [Hz]")<jupyter_output><empty_output><jupyter_text>Auralization The predicted response or each path contribution can be evaluated by listening to synthetised time response. Within `pyFBS` auralization can be performed with ease and the response can be played within Jupyter notebook with single line of code.<jupyter_code>import IPython.display as ipd<jupyter_output><empty_output><jupyter_text>Auralization of the operational response $\textbf{u}_3^{\text{op}}$.<jupyter_code>xt,s_op = pyFBS.auralization(freq,u3_op[:,sel_out,0])
plt.figure(figsize = (6,3))
plt.plot(xt,s_op)

ipd.Audio(s_op, rate=1/(xt[1]-xt[0]))<jupyter_output><empty_output><jupyter_text>Auralization of predicted response $\textbf{u}_3^{\text{TPA}}$.<jupyter_code>xt,s_tpa = pyFBS.auralization(freq,u3_tpa[:,sel_out,0])

plt.figure(figsize = (6,3))
plt.plot(xt,s_tpa)
ipd.Audio(s_tpa, rate=1/(xt[1]-xt[0])) 

plt.xlabel("Time [s]")
plt.ylabel("Amplitude")<jupyter_output><empty_output><jupyter_text>Side-by-side comparison of operational $\textbf{u}_3^{\text{op}}$ and predicted $\textbf{u}_3^{\text{TPA}}$ response in time domain.<jupyter_code>plt.figure(figsize = (6,3))
plt.plot(xt,s_op)
plt.plot(xt,s_tpa,'--',linewidth = 1)

plt.xlim(0,.08)
plt.xlabel("Time [s]")
plt.ylabel("Amplitude");<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14238658481808655, 'fraction_numerical': 0.020362329690073365, 'mean_word_length': 8.188445667125173, 'pattern_counts': {'":': 0, '<': 80, '<?xml version=': 0, '>': 80, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '20', 'dir': 'jupyter-structured-clean-dedup', 'id': '448650', 'license': 'MIT', 'n_tokens_mistral': 2756, 'n_tokens_neox': 2655, 'n_words': 453, 'path': 'examples/11_TPA_in-situ.ipynb', 'repo_name': 'anantagrg/FBS_Substructuring', 'size': '6679'}