In [6]:
import numpy as np
import scipy as sp
from numpy.linalg import inv
def vectorpan(xys,xyls,simplices):
g=np.zeros(xyls.shape[1])
for n in range(0,simplices.shape[0]):
na=simplices[n,0]
nb=simplices[n,1]
M=np.array([xyls[:,na],xyls[:,nb]]).T
gnm=np.dot(inv(M),xys)
if np.sum(gnm<-1e-3)==0:
g[na]=gnm[0]
g[nb]=gnm[1]
break
return g
def r_vector(g,xyls):
thx=xyls[0,:]
thy=xyls[1,:]
rx=np.dot(thx,g).T
ry=np.dot(thy,g).T
normalizer=sum(g,0)
rx/=normalizer
ry/=normalizer
return np.array([rx,ry])
from scipy.spatial import ConvexHull
import math
L=5
phils=np.arange(0,L)*2*np.pi/L
xyls=np.array([np.cos(phils),np.sin(phils)])
phis=0
xys=np.array([np.cos(phis),np.sin(phis)])
qh=ConvexHull(xyls.T)
def get_panning_gains(xys,xyls,simplices,pantype):
if (pantype == 'MDAP') or (pantype == 'MDIP'):
alpha=np.arccos(np.dot(xyls[:,0],xyls[:,1]))
R=np.array([np.cos(alpha/2), -np.sin(alpha/2), np.sin(alpha/2), np.cos(alpha/2)]).reshape(2,2)
xys2=np.dot(R,xys)
xys3=np.dot(R.T,xys)
g=vectorpan(xys,xyls,simplices)+vectorpan(xys2,xyls,simplices)+vectorpan(xys3,xyls,simplices)
if pantype == 'MDIP':
g=np.abs(g)
g=np.sqrt(g)
g/=np.sqrt(np.sum(g**2))
elif pantype == 'VBAP':
g=vectorpan(xys,xyls,simplices)
else:
g=np.sqrt(np.abs(vectorpan(xys,xyls,simplices)))
return g
from bokeh.plotting import figure, output_file, show
from bokeh.io import push_notebook, output_notebook
import ipywidgets as widgets
import time, threading
L_widget = widgets.IntSlider(min=4, max=12, step=1,value=L,description="L")
phis_widget= widgets.FloatSlider(min=-180.0,max=180.0,step=1.0,value=0.0,description="phi")
pantype_widget= widgets.SelectionSlider(options=['VBAP','VBIP','MDAP','MDIP'],value='VBAP',description="weight")
animate_widget=widgets.Checkbox(value=False,description="anim")
L=L_widget.value;
phils=np.mod((2*np.pi*np.arange(0,L))/L+np.pi,2*np.pi)-np.pi
xys=np.array([np.cos(phis),np.sin(phis)])
qh=ConvexHull(xyls.T)
simplices=qh.simplices
phis=phis_widget.value*np.pi/180.0
xys=np.array([np.cos(phis),np.sin(phis)])
pantype=pantype_widget.value
gls=get_panning_gains(xys,xyls,simplices,pantype)
output_notebook()
p = figure(title="2D VBAP, VBIP, MDAP, and MDIP Panning",plot_width=600, plot_height=270, x_range=(-180,180), y_range=(-.4,1.1))
ll=p.circle(phils*180/np.pi, gls , line_width=3, color="red")
pp=p.line(np.array([phis, phis])*180/np.pi, np.array([0, 1]), color="black")
rE=r_vector(gls**2,xyls)
dirE=np.arctan2(rE[1],rE[0])*180/np.pi;
lenE=np.sqrt(np.sum(rE**2))
prE=p.line(np.array([1, 1])*dirE, np.array([0, 1])*lenE, color="red",line_width=3,legend="rE")
rV=r_vector(gls,xyls)
dirV=np.arctan2(rV[1],rV[0])*180/np.pi;
lenV=np.sqrt(np.sum(rV**2))
prV=p.line(np.array([1, 1])*dirV, np.array([0, 1])*lenV, color="green",line_width=3,legend="rV")
show(p,notebook_handle=True)
def update_plot(xys,xyls,simplices,pantype):
pp.data_source.data['x']=np.mod(np.array([1, 1])*np.arctan2(xys[1],xys[0])*180/np.pi+180,360)-180
gls=get_panning_gains(xys,xyls,simplices,pantype)
ll.data_source.data['y']=gls
ll.data_source.data['x']=np.arctan2(xyls[1,:],xyls[0,:])*180/np.pi
rE=r_vector(gls**2,xyls)
dirE=np.arctan2(rE[1],rE[0])*180/np.pi;
lenE=np.sqrt(np.sum(rE**2))
prE.data_source.data['x']=np.array([1, 1])*dirE
prE.data_source.data['y']=np.array([0, 1])*lenE
rV=r_vector(gls,xyls)
dirV=np.arctan2(rV[1],rV[0])*180/np.pi;
lenV=np.sqrt(np.sum(rV**2))
prV.data_source.data['x']=np.array([1, 1])*dirV
prV.data_source.data['y']=np.array([0, 1])*lenV
push_notebook()
def on_value_change(change):
global simplices
phis=phis_widget.value*np.pi/180.0
xys=np.array([np.cos(phis),np.sin(phis)])
pantype=pantype_widget.value
L=L_widget.value
phils=np.mod((2*np.pi*np.arange(0,L))/L+np.pi,2*np.pi)-np.pi
xyls=np.array([np.cos(phils),np.sin(phils)])
if change.owner == L_widget:
qh=ConvexHull(xyls.T)
simplices=qh.simplices
update_plot(xys,xyls,simplices,pantype)
#widgets.jslink((play,'value'),(phis_widget,'value'))
#interactive(update_plot, L=L_widget, phis=phis_widget, weight=weights_widget)
phis_widget.observe(on_value_change,names='value')
L_widget.observe(on_value_change,names='value')
pantype_widget.observe(on_value_change,names='value')
def animate_plot(change):
if animate_widget.value:
phis=phis_widget.value
phis=np.mod(phis+3+180,360)-180
phis_widget.value=phis
threading.Timer(0.001, animate_plot,[1]).start()
animate_widget.observe(animate_plot,names='value')
widgets.HBox([phis_widget,L_widget,pantype_widget,animate_widget])