##| Copyright: (C) 2019-2020 Kevin Larke ##| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. import sys,os import numpy as np import common import rms_analysis def fit_points_to_reference( usL, dbL, usRefL, dbRefL ): dbV = None yyL = [ (db,dbRefL[ usRefL.index(us)]) for i,(us,db) in enumerate(zip(usL,dbL)) if us in usRefL ] if len(yyL) < 10: print("NO FIT") else: y0L,yrL = zip(*yyL) yN = len(y0L) A = np.vstack([np.ones(yN),y0L]).T c,m = np.linalg.lstsq(A,yrL,rcond=None)[0] dbV = (np.array(dbL) * m) + c return dbV def find_elbow( usL, dbL, pointsPerLine=10 ): ppl_2 = int(pointsPerLine/2) dL = [] i = pointsPerLine # for each consecutive set of 'pointsPerLine' points in usL and dbL while i < len(usL): # find the x,y coordinates of the first 'ppl_2' coordinates x0L = np.array([ (us,1.0) for us in usL[i-pointsPerLine:i-ppl_2] ]) y0L = np.array(usL[i-pointsPerLine:i-ppl_2]) # find the x,y coordinates of the second 'ppl_2' coordinates x1L = np.array([ (us,1.0) for us in usL[i-ppl_2:i]]) y1L = np.array(dbL[i-ppl_2:i]) m0,c0 = np.linalg.lstsq(x0L,y0L,rcond=None)[0] # fit a line through the first set of points m1,c1 = np.linalg.lstsq(x1L,y1L,rcond=None)[0] # fit a line through the second set of points # store the angle between the two lines dL.append(m1-m0) i += 1 # find the max angle i = np.argmax( dL ) # return the x,y coordinate of the first data point of the second line return (usL[i+ppl_2],dbL[i+ppl_2]) def find_elbow_main( cfg, inDir, midi_pitch, takeId ): inDir = os.path.join(inDir,str(pitch),str(takeId)) analysisArgsD = cfg.analysisArgs['rmsAnalysArgs'] r = rms_analysis_main( inDir, int(midi_pitch), **analysisD ) usL = r.pkUsL dbL = r.pkDbL return find_elbow(r.pkUsL,r.pkDbL) if __name__ == "__main__": inDir = sys.argv[1] cfgFn = sys.argv[2] pitch = sys.argv[3] cfg = common.parse_yaml_cfg(cfgFn) find_elbow( cfg, inDir, pitch, 0 )