piccal/elbow.py

88 lines
2.2 KiB
Python

##| Copyright: (C) 2019-2020 Kevin Larke <contact AT larke DOT org>
##| 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=5 ):
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 )