import warnings
warnings.filterwarnings("ignore")
desired_sr = 0.5 # this is the sr we are going to merge on (in Hz/sec)
error_log = []
mergedfiles = glob.glob(os.path.join(TSmerged, 'merged_*.csv'))
for file in bbfiles:
bb_df = pd.read_csv(file)
trialid = bb_df['TrialID'][0]
print('working on ' + trialid)
# Find ID file
id_name = 'id_' + trialid
id_file = [x for x in idfiles if id_name in x]
try:
id_df = pd.read_csv(id_file[0])
except IndexError:
print('IndexError: ' + trialid + ' not found for ID')
errormessage = 'IndexError: ' + trialid + ' not found for ID'
error_log.append(errormessage)
continue
# Find MT file
mt_name = 'mt_' + trialid
mt_file = [x for x in mtfiles if mt_name in x]
try:
mt_df = pd.read_csv(mt_file[0])
# check if there are two 0 in Time, drop the first one
if mt_df['Time'][0] == 0 and mt_df['Time'][1] == 0:
mt_df = mt_df.drop(index=0).reset_index(drop=True)
except IndexError:
print('IndexError: ' + trialid + ' not found for MT')
errormessage = 'IndexError: ' + trialid + ' not found for MT'
error_log.append(errormessage)
continue
# rename Time to time
mt_df.rename(columns={'Time': 'time'}, inplace=True)
# Find ENV file
env_name = 'env_' + trialid
env_file = [x for x in envfiles if env_name in x]
try:
env_df = pd.read_csv(env_file[0])
except IndexError:
print('IndexError: ' + trialid + ' not found for ENV')
errormessage = 'IndexError: ' + trialid + ' not found for ENV'
error_log.append(errormessage)
continue
# rename trialID to TrialID
env_df.rename(columns={'trialID': 'TrialID'}, inplace=True)
# Find F0 file
f0_name = 'f0_' + trialid
f0_file = [x for x in f0files if trialid in x]
try:
f0_df = pd.read_csv(f0_file[0])
except IndexError:
print('IndexError: ' + trialid + ' not found for F0')
errormessage = 'IndexError: ' + trialid + ' not found for F0'
error_log.append(errormessage)
continue
# rename time_ms to time
f0_df.rename(columns={'time_ms': 'time'}, inplace=True)
# rename ID to TrialID
f0_df.rename(columns={'ID': 'TrialID'}, inplace=True)
# Find IK file
ik_name = 'ik_' + trialid
ik_file = [x for x in ikfiles if ik_name in x]
try:
ik_df = pd.read_csv(ik_file[0])
except IndexError:
print('IndexError: ' + trialid + ' not found for IK')
errormessage = 'IndexError: ' + trialid + ' not found for IK'
error_log.append(errormessage)
continue
# Find formant file
# take first two element
if 'rein' in trialid:
formantid = trialid.split('_')[0] + '_' + trialid.split('_')[1] + '_rein_trial_' + trialid.split('_')[3] + '_'
else:
formantid = trialid.split('_')[0] + '_' + trialid.split('_')[1] + '_trial_' + trialid.split('_')[2] + '_'
formants_file = [x for x in formants if formantid in x]
try:
formants_df = pd.read_csv(formants_file[0])
except IndexError:
print('IndexError: ' + trialid + ' not found for formants')
errormessage = 'IndexError: ' + trialid + ' not found for formants'
error_log.append(errormessage)
continue
# rename triald to TrialID
formants_df['TrialID'] = trialid
formants_df = formants_df[['time', 'f1', 'f2', 'f3', 'TrialID']]
formants_df['time'] = formants_df['time'] * 1000
# Find COG file
if 'rein' in trialid:
cogid = trialid.split('_')[0] + '_' + trialid.split('_')[1] + '_' + trialid.split('_')[3] + '_'
cogname = 'cog_' + cogid
sc_file = [x for x in scfiles if cogname in x]
else:
cogname = 'cog_' + trialid
sc_file = [x for x in scfiles if cogname in x]
try:
sc_df = pd.read_csv(sc_file[0])
except IndexError:
print('IndexError: ' + trialid + 'not found CoG')
errormessage = 'IndexError: ' + trialid + ' not found for CoG'
error_log.append(errormessage)
continue
# write error log
with open(os.path.join(TSmerged, 'error_log.txt'), 'w') as f:
for item in error_log:
f.write("%s\n" % item)
############## MERGING ########################
#### regularize sr in bb
time_new = np.arange(0, max(bb_df['time']), 1/desired_sr)
bb_interp = pd.DataFrame({'time': time_new})
# interpolate all columns in samplebb
colstoint = bb_df.columns
colstoint = [x for x in colstoint if 'time' not in x]
colstoint = [x for x in colstoint if 'TrialID' not in x]
colstoint = [x for x in colstoint if 'FileInfo' not in x]
for col in colstoint:
bb_interp[col] = bb_df[col].interpolate(method='linear', x = bb_interp['time'])
# add trialid and time
bb_interp['TrialID'] = trialid
bb_interp['FileInfo'] = bb_df['FileInfo'][0]
########### merge the bb_interp with env
# merge the two dataframes
merge1 = pd.merge(bb_interp, env_df, on=['time', 'TrialID'], how='outer')
# interpolate missing values of envelope and audio
colstoint = merge1.columns
colstoint = [x for x in colstoint if 'audio' in x or 'envelope' in x]
for col in colstoint:
merge1[col] = merge1[col].interpolate(method='linear', x = merge1['time'])
# now we can kick out all values where COPc is NaN
merge1 = merge1[~np.isnan(merge1['COPc'])]
########### merge with ID
# merge the two dataframes
merge2 = pd.merge(merge1, id_df, on=['time', 'TrialID'], how='outer')
#merge2 = merge2.sort_values(by='time').reset_index(drop=True)
# get cols of sampleid
colstoint = id_df.columns
colstoint = [x for x in colstoint if 'time' not in x]
colstoint = [x for x in colstoint if 'TrialID' not in x]
# interpolate
for col in colstoint:
merge2[col] = merge2[col].interpolate(method='linear', x = merge2['time'])
# now we can kick out all values where COPc is NaN to get sampling rate back to 500
merge2 = merge2[~np.isnan(merge2['COPc'])]
########### merge with MT
# merge the two dataframes
merge3 = pd.merge(merge2, mt_df, on=['time', 'TrialID'], how='outer')
#merge3 = merge3.sort_values(by='time').reset_index(drop=True)
# get cols of samplemt
colstoint = mt_df.columns
colstoint = [x for x in colstoint if 'time' not in x]
colstoint = [x for x in colstoint if 'TrialID' not in x]
# interpolate missing values of from mt
for col in colstoint:
merge3[col] = merge3[col].interpolate(method='linear', x = merge3['time'])
# now we can kick out all values where COPc is NaN
merge3 = merge3[~np.isnan(merge3['COPc'])]
########### merge with F0
# for interpolation, we need to again parse f0 into chunks of non-NaN values
f0_df, chunks = create_chunks(f0_df, 'f0')
# now we can merge
merge4 = pd.merge(merge3, f0_df, on=['time', 'TrialID'], how='outer')
# interpolate f0 signal, while maintaining discontinuities
merge4 = interpolate_chunks(merge4, chunks, 'f0')
# now we can drop all rows where COPc is NaN
merge4 = merge4[~np.isnan(merge4['COPc'])]
########### merge with IK
merge5 = pd.merge(merge4, ik_df, on=['time', 'TrialID'], how='outer')
# get cols of sampleik
colstoint = ik_df.columns
colstoint = [x for x in colstoint if 'time' not in x]
colstoint = [x for x in colstoint if 'TrialID' not in x]
# interpolate missing values of from ik
for col in colstoint:
merge5[col] = merge5[col].interpolate(method='linear', x = merge5['time'])
# now we can kick out all values where COPc is NaN
merge5 = merge5[~np.isnan(merge5['COPc'])]
########### merge with formants
merge6 = pd.merge(merge5, formants_df, on=['time', 'TrialID'], how='outer')
# get cols of sampleformants
colstoint = formants_df.columns
colstoint = [x for x in colstoint if 'time' not in x]
colstoint = [x for x in colstoint if 'TrialID' not in x]
# interpolate missing values of from formants - currently they do not have NaNs so we can interpolate the whole signal instead of only non-NaN chunks
for col in colstoint:
merge6[col] = merge6[col].interpolate(method='linear', x = merge6['time'])
# now we can kick out all values where COPc is NaN
merge6 = merge6[~np.isnan(merge6['COPc'])]
########### merge with CoG
merge7 = pd.merge(merge6, sc_df, on=['time', 'TrialID'], how='outer')
# get cols of samplespecCentroid
colstoint = sc_df.columns
colstoint = [x for x in colstoint if 'time' not in x]
colstoint = [x for x in colstoint if 'TrialID' not in x]
# for interpolation, we need to again parse specCentroid into chunks of non-NaN values
sc, chunks = create_chunks(sc_df, 'CoG')
# now we merge
merge8 = pd.merge(merge7, sc, on=['time', 'TrialID', 'CoG'], how='outer')
#merge8 = merge8.sort_values(by='time').reset_index(drop=True)
# interpolate CoG signal, while maintaining discontinuities
merge8 = interpolate_chunks(merge8, chunks, 'CoG')
# now we can kick out all values where COPc is NaN
merge8 = merge8[~np.isnan(merge8['COPc'])]
# this is final df
merge_final = merge8
############## FORMANT ADAPTATION ########################
# find peaks in envelope, with min=mean
peaks, _ = scipy.signal.find_peaks(merge_final['envelope_norm'], height=np.mean(merge_final['envelope_norm']))
# get widths of the peaks
widths = scipy.signal.peak_widths(merge_final['envelope_norm'], peaks, rel_height=0.95)
# peak width df with starts and ends
peak_widths = pd.DataFrame({'start': widths[2], 'end': widths[3]})
# now create a new column env_weak_width, and put 0s everywhere, and 1s in the intervals of the width
merge_final['env_peak_width'] = 0
for index, row in peak_widths.iterrows():
merge_final.loc[int(row['start']):int(row['end']), 'env_peak_width'] = 1
# now we will create formant columns, where we will keep only formants in the intervals of env_pak_width OR where f0 is not NaN
merge_final['f1_clean_f0'] = merge_final['f1']
merge_final['f2_clean_f0'] = merge_final['f2']
merge_final['f3_clean_f0'] = merge_final['f3']
# where f0 is NaN, we will put NaN - these are formants during f0 only
merge_final.loc[np.isnan(merge_final['f0']), 'f1_clean_f0'] = np.nan
merge_final.loc[np.isnan(merge_final['f0']), 'f2_clean_f0'] = np.nan
merge_final.loc[np.isnan(merge_final['f0']), 'f3_clean_f0'] = np.nan
# we will also create formants, where we will keep only those in the intervals of env_pak_width
merge_final['f1_clean_env'] = merge_final['f1']
merge_final['f2_clean_env'] = merge_final['f2']
merge_final['f3_clean_env'] = merge_final['f3']
# where env_peak_width is 0, we will put NaN - these are formants during envelope peaks only
merge_final.loc[merge_final['env_peak_width'] == 0, 'f1_clean_env'] = np.nan
merge_final.loc[merge_final['env_peak_width'] == 0, 'f2_clean_env'] = np.nan
merge_final.loc[merge_final['env_peak_width'] == 0, 'f3_clean_env'] = np.nan
## now we create formants where we copy values from clean_env and clean_f0
merge_final['f1_clean'] = merge_final['f1_clean_env']
merge_final['f2_clean'] = merge_final['f2_clean_env']
merge_final['f3_clean'] = merge_final['f3_clean_env']
# where formant is now NaN, copy values from f_clean_f0 in case there is a value
merge_final.loc[np.isnan(merge_final['f1_clean']), 'f1_clean'] = merge_final['f1_clean_f0']
merge_final.loc[np.isnan(merge_final['f2_clean']), 'f2_clean'] = merge_final['f2_clean_f0']
merge_final.loc[np.isnan(merge_final['f3_clean']), 'f3_clean'] = merge_final['f3_clean_f0']
# now calculate formant velocities (but only for the f_clean)
merge_final['f1_clean_vel'] = np.insert(np.diff(merge_final['f1_clean']), 0, 0)
merge_final['f2_clean_vel'] = np.insert(np.diff(merge_final['f2_clean']), 0, 0)
merge_final['f3_clean_vel'] = np.insert(np.diff(merge_final['f3_clean']), 0, 0)
# smooth
merge_final['f1_clean_vel'] = scipy.signal.savgol_filter(merge_final['f1_clean_vel'], 5, 3)
merge_final['f2_clean_vel'] = scipy.signal.savgol_filter(merge_final['f2_clean_vel'], 5, 3)
merge_final['f3_clean_vel'] = scipy.signal.savgol_filter(merge_final['f3_clean_vel'], 5, 3)
# multiply by sr (500) to get formant velocity in Hz/s
sr = 500
merge_final['f1_clean_vel'] = merge_final['f1_clean_vel'] * sr
merge_final['f2_clean_vel'] = merge_final['f2_clean_vel'] * sr
merge_final['f3_clean_vel'] = merge_final['f3_clean_vel'] * sr
########## POWER ####################
groups = ['lowerbody', 'leg', 'head', 'arm']
for group in groups:
# get all columns that contain group
cols = [x for x in merge_final.columns if group in x]
# get all columns that contain 'moment_sum'
torque = [x for x in cols if 'moment_sum' in x]
# but not change
torque = [x for x in torque if 'change' not in x][0]
# get all columns that contain 'angSpeed_sum'
angSpeed = [x for x in cols if 'angSpeed_sum' in x][0]
# get power which is moment * angSpeed
merge_final[group + '_power'] = merge_final[torque] * merge_final[angSpeed]
# smooth
try:
merge_final[group + '_power'] = scipy.signal.savgol_filter(merge_final[group + '_power'], 281, 1) # window 281 corresponds to 562 ms (we add +1 to have odd length of window)
except ValueError:
# if there is a ValueError, it means that the window is too large for the data, so we will use a smaller window
try:
merge_final[group + '_power'] = scipy.signal.savgol_filter(merge_final[group + '_power'], 101, 2) # window 101 corresponds to 202 ms (we add +1 to have odd length of window)
except ValueError:
merge_final[group + '_power'] = scipy.signal.savgol_filter(merge_final[group + '_power'], 51, 2)
# write to csv
merge_final.to_csv(os.path.join(TSmerged, 'merged_' + trialid + '.csv'), index=False)