├── .gitignore ├── adaptive_hopf.py ├── com_CPG.py ├── com_CPG_2.py ├── com_adaptive_hopf.py ├── coupled_hopf.py ├── matlab_code ├── adhopf.m ├── com_CPG.m ├── com_CPG1.m └── com_adhopf.m └── plots ├── com_adaptive_osc_exp_1.png ├── com_cpg_plot.png ├── com_cpg_plot_omega.png └── com_cpg_plot_z.png /.gitignore: -------------------------------------------------------------------------------- 1 | :*.pdf 2 | *.pdf 3 | *.dex 4 | 5 | # Version control 6 | vcs.xml 7 | 8 | # lint 9 | lint/intermediates/ 10 | lint/generated/ 11 | lint/outputs/ 12 | lint/tmp/ 13 | # lint/reports/ 14 | venv/ 15 | .env 16 | 17 | *.pyc 18 | __pycache__/ 19 | -------------------------------------------------------------------------------- /adaptive_hopf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from tqdm import tqdm 5 | import pandas as pd 6 | 7 | n = 1000000 8 | dt = 0.001 9 | t = np.arange(0,n+1)*dt 10 | 11 | class Adaptive_Hopf_Oscillator(): 12 | def __init__(self, 13 | gamma = 2, 14 | phi = np.random.random(), 15 | n = 1000000, 16 | dt = 0.001, 17 | mu = 1, 18 | eps = 0.9, 19 | omega_0 = 40, 20 | F = np.sin(2*np.pi*30*t)[:-1]): 21 | self.n = n 22 | self.dt = dt 23 | self.mu = mu 24 | self.eps = eps 25 | self.gamma = gamma 26 | self.omega = omega_0 27 | self.x = 1 28 | self.y = 0 29 | 30 | self.Aomega = np.zeros(self.n) 31 | self.Ax = np.zeros(self.n) 32 | self.Ay = np.zeros(self.n) 33 | self.Aphi = np.zeros(self.n) 34 | self.t = np.arange(0,n)*self.dt 35 | self.F = F 36 | 37 | def dx(self, x, y, i, omega): 38 | dx = self.dt*((self.mu - (x**2 + y**2))*x*self.gamma - omega*y + self.eps*self.F[i]) 39 | return dx 40 | 41 | def dy(self, y, x, i, omega): 42 | dy = self.dt*((self.mu - (x**2 + y**2))*y*self.gamma + omega*x) 43 | return dy 44 | 45 | def domega(self, x, y, i): 46 | domega = self.dt*((-1)*self.eps*self.F[i]*y/np.sqrt(x**2 + y**2)) 47 | return domega 48 | 49 | def phase(self, x, y): 50 | phase = np.arctan(y/x) 51 | return phase 52 | 53 | def train(self): 54 | for i in tqdm(range(0, self.n)): 55 | self.Aphi[i] = self.phase(self.x, self.y) 56 | self.Ax[i] = self.x 57 | self.Ay[i] = self.y 58 | self.Aomega[i] = self.omega 59 | self.x = self.x + self.dx(self.x, self.y, i, self.omega) 60 | self.y = self.y + self.dy(self.y, self.x, i, self.omega) 61 | self.omega = self.omega + self.domega(self.x, self.y, i) 62 | 63 | def plot(self): 64 | fig, axes = plt.subplots(1,2) 65 | axes[0].plot(self.t, self.Aomega) 66 | axes[1].plot(self.t, self.F) 67 | plt.show() 68 | 69 | def main(self): 70 | self.train() 71 | self.plot() 72 | #----------Initialization for trajectory in figure 1-----------# 73 | F = np.sin(2*np.pi*30*t) 74 | num = int(1/(15*dt)) 75 | print(num) 76 | k = 0 77 | for i in range(n): 78 | if i%num>=num/4 or F[i]<0.0: 79 | F[i] = F[i]*0.001 80 | fig, axes = plt.subplots(1,1) 81 | axes.plot(t[:100], F[:100]) 82 | axes.set_title('teaching signal') 83 | fig.savefig('../plots/teaching_signal_exp_2_hopf.png') 84 | hopf_osc = Adaptive_Hopf_Oscillator(F=F) 85 | #--------------------------------------------------------------# 86 | print(hopf_osc.Aomega) 87 | print(hopf_osc.Aphi) 88 | hopf_osc.train() 89 | print(hopf_osc.Aomega) 90 | print(hopf_osc.Aphi) 91 | fig, axes = plt.subplots(1, 4) 92 | axes[0].plot(hopf_osc.t[-1000:], hopf_osc.Ax[-1000:]) 93 | axes[1].plot(hopf_osc.t[-1000:], hopf_osc.Ay[-1000:]) 94 | axes[2].plot(hopf_osc.t[-1000:], hopf_osc.Aomega[-1000:]) 95 | axes[3].plot(hopf_osc.t[-1000:], hopf_osc.Aphi[-1000:]) 96 | plt.show() 97 | fig.savefig('../plots/learned_hopf_exp_2.png') 98 | -------------------------------------------------------------------------------- /com_CPG.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import matplotlib.pyplot as plt 4 | from tqdm import tqdm 5 | 6 | class com_CPG(): 7 | def __init__(self, 8 | n = 1000000, 9 | dt = 0.001, 10 | mu = 1, 11 | eps = 0.5, 12 | etaalp = 0.5, 13 | num = 4,): 14 | self.n = n 15 | self.dt = dt 16 | self.mu = mu 17 | self.eps = eps 18 | self.etaalp = etaalp 19 | self.num = num 20 | self.omega = np.random.random(self.num)*20 # shape (num,) 21 | self.z = np.exp(1j*np.random.random(self.num)*2*np.pi) # shape (num,) 22 | self.alpha = np.random.random(self.num) #shape (num,) 23 | self.F = np.zeros(self.n) 24 | self.Aomega = np.zeros((self.num, self.n)) # shape (num, n) 25 | self.Az = np.zeros((self.num, self.n), dtype = np.complex128) 26 | self.Aalpha = np.zeros((self.num, self.n)) # shape (num, n) 27 | self.Ar = np.zeros((self.num, self.n)) # shape (num, n) 28 | self.Aph = np.zeros((self.num, self.n)) # shape (num, n) 29 | self.t = np.arange(0,n)*self.dt # shape (n,) 30 | self.st = np.zeros(self.n) # shape (n,) 31 | self.et = np.zeros(self.n) # shape (n,) 32 | omega_input = [5, 10, 15, 20] 33 | I_max = [1.1, 0.8, 1.5, 0.7] 34 | phase = [np.pi/3, np.pi/4, np.pi/2, np.pi/5] 35 | for i in range(4): 36 | self.F = self.F + I_max[i]*np.sin(omega_input[i]*self.t + phase[i]) 37 | 38 | def train(self): 39 | for i in tqdm(range(self.n)): 40 | self.Ar[:, i] = np.abs(self.z) 41 | self.Aph[:, i] = self.phase(self.z) 42 | self.Az[:, i] = self.z 43 | self.Aomega[:, i] = self.omega 44 | self.Aalpha[:, i] = self.alpha 45 | self.st[i] = np.sum(self.alpha*self.z.real) 46 | self.et[i] = self.F[i] - self.st[i] 47 | #print(self.dz(self.z, i, self.omega)) 48 | self.z = self.z + self.dz(self.z, i, self.omega) 49 | #print(self.domega(self.z, i)) 50 | self.omega = self.omega + self.domega(self.z, i) 51 | #print(self.dalpha(self.z, i)) 52 | self.alpha = self.alpha + self.dalpha(self.z, i) 53 | 54 | def dz(self, z, i, omega): 55 | return self.dt*((self.mu - np.abs(z)**2)*z + 1j*omega*z + self.eps*self.et[i]) 56 | 57 | def domega(self, z, i): 58 | return self.dt*((-1)*self.eps*self.et[i]*z.imag/np.abs(z)) 59 | 60 | def dalpha(self, z, i): 61 | return self.dt*(self.etaalp*z.real*self.et[i]) 62 | 63 | def phase(self, z): 64 | imag = z.imag 65 | real = z.real 66 | phase = np.arctan(imag/real) 67 | return phase 68 | 69 | CPG = com_CPG() 70 | CPG.train() 71 | print(CPG.Aomega) 72 | fig, axes = plt.subplots(2,2) 73 | axes[0, 0].plot(CPG.t, CPG.Aomega[0]) 74 | axes[0, 0].set_title('neuron 1') 75 | axes[0, 1].plot(CPG.t, CPG.Aomega[1]) 76 | axes[0, 1].set_title('neuron 2') 77 | axes[1, 0].plot(CPG.t, CPG.Aomega[2]) 78 | axes[1, 0].set_title('neuron 3') 79 | axes[1, 1].plot(CPG.t, CPG.Aomega[3]) 80 | axes[1, 1].set_title('neuron 4') 81 | fig.savefig('com_cpg_plot_omega.png') 82 | fig1, axes1 = plt.subplots(2,2) 83 | axes1[0, 0].plot(CPG.t[-1000:], CPG.Az[0, -1000:].real) 84 | axes1[0, 0].set_title('neuron 1') 85 | axes1[0, 1].plot(CPG.t[-1000:], CPG.Az[1, -1000:].real) 86 | axes1[0, 1].set_title('neuron 2') 87 | axes1[1, 0].plot(CPG.t[-1000:], CPG.Az[2, -1000:].real) 88 | axes1[1, 0].set_title('neuron 3') 89 | axes1[1, 1].plot(CPG.t[-1000:], CPG.Az[3,-1000: ].real) 90 | axes1[1, 1].set_title('neuron 4') 91 | fig1.savefig('com_cpg_plot_z.png') 92 | #plt.show() 93 | -------------------------------------------------------------------------------- /com_CPG_2.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import matplotlib.pyplot as plt 4 | from tqdm import tqdm 5 | 6 | class com_CPG(): 7 | def __init__(self, 8 | n = 1000000, 9 | dt = 0.001, 10 | mu = 1, 11 | eps = 0.9, 12 | etaalp = 0.5, 13 | num = 4,): 14 | self.n = n 15 | self.dt = dt 16 | self.mu = mu 17 | self.eps = eps 18 | self.etaalp = etaalp 19 | self.num = num 20 | self.omega = np.random.random(self.num)*20 # shape (num,) 21 | self.z = np.exp(1j*np.random.random(self.num)*2*np.pi) # shape (num,) 22 | self.alpha = np.random.random(self.num) #shape (num,) 23 | self.F = np.zeros(self.n) # shape (n,) 24 | self.Aomega = np.zeros((self.num, self.n), dtype = np.complex128) # shape (num, n) 25 | self.Az = np.zeros((self.num, self.n), dtype = np.complex128) 26 | self.Aalpha = np.zeros((self.num, self.n), dtype = np.complex128) # shape (num, n) 27 | self.Ar = np.zeros((self.num, self.n)) # shape (num, n) 28 | self.Aph = np.zeros((self.num, self.n)) # shape (num, n) 29 | self.t = np.arange(0,n)*self.dt # shape (n,) 30 | self.st = np.zeros(self.n, dtype = np.complex128) # shape (n,) 31 | self.et = np.zeros(self.n, dtype = np.complex128) # shape (n,) 32 | omega_input = [5, 10, 15, 20] 33 | I_max = [1.1, 0.8, 1.5, 0.7] 34 | phase = [np.pi/3, np.pi/4, np.pi/2, np.pi/5] 35 | for i in range(4): 36 | self.F = self.F + I_max[i]*np.exp(1j*(omega_input[i]*self.t + phase[i])) 37 | self.Freal = self.F.real 38 | 39 | def simulate(self): 40 | for i in tqdm(range(self.n)): 41 | self.Ar[:, i] = np.abs(self.z) 42 | self.Aph[:, i] = self.phase(self.z) 43 | self.Az[:, i] = self.z 44 | self.Aomega[:, i] = self.omega 45 | self.Aalpha[:, i] = self.alpha 46 | self.st[i] = np.sum(self.alpha*self.z.real) 47 | self.et[i] = self.Freal[i] - self.st[i] 48 | #print(self.dz(self.z, i, self.omega)) 49 | self.z = self.z + self.dz(self.z, i, self.omega) 50 | #print(self.domega(self.z, i)) 51 | self.omega = self.omega + self.domega(self.z, i) 52 | #print(self.dalpha(self.z, i)) 53 | self.alpha = self.alpha + self.dalpha(self.z, i) 54 | 55 | def dz(self, z, i, omega): 56 | return self.dt*((self.mu - np.abs(z)**2)*z + 1j*omega*z + self.eps*self.et[i]) 57 | 58 | def domega(self, z, i): 59 | return self.dt*((-1)*self.eps*self.et[i]*z.imag/np.abs(z)) 60 | 61 | def dalpha(self, z, i): 62 | return self.dt*(self.etaalp*z.real*self.et[i]) 63 | 64 | def phase(self, z): 65 | imag = z.imag 66 | real = z.real 67 | phase = np.arctan(imag/real) 68 | return phase 69 | 70 | CPG = com_CPG() 71 | CPG.simulate() 72 | print(CPG.Aomega) 73 | fig, axes = plt.subplots(2,2) 74 | axes[0, 0].plot(CPG.t, CPG.Aomega[0]) 75 | axes[0, 0].set_title('neuron 1') 76 | axes[0, 1].plot(CPG.t, CPG.Aomega[1]) 77 | axes[0, 1].set_title('neuron 2') 78 | axes[1, 0].plot(CPG.t, CPG.Aomega[2]) 79 | axes[1, 0].set_title('neuron 3') 80 | axes[1, 1].plot(CPG.t, CPG.Aomega[3]) 81 | axes[1, 1].set_title('neuron 4') 82 | plt.show() 83 | -------------------------------------------------------------------------------- /com_adaptive_hopf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from tqdm import tqdm 5 | import pandas as pd 6 | 7 | n = 1000000 8 | dt = 0.001 9 | t = np.arange(0,n+1)*dt 10 | 11 | class Adaptive_Hopf_Oscillator(): 12 | def __init__(self, 13 | phi = np.random.random(), 14 | n = 1000000, 15 | dt = 0.001, 16 | mu = 1, 17 | eps = 0.9, 18 | omega_0 = 40, 19 | F = 2*np.exp(1j*30*t)[:-1]): 20 | self.n = n 21 | self.dt = dt 22 | self.mu = mu 23 | self.eps = eps 24 | self.omega = omega_0 25 | self.z = np.exp(2j*np.random.random()*np.pi) # This is the initialization of the ocillator 26 | self.Aomega = np.zeros(self.n) # This is the initialization of the frequency of the oscillator 27 | self.Az = np.zeros(self.n, dtype = np.complex128) 28 | self.Aph = np.zeros( self.n) 29 | self.Ar = np.zeros(self.n) 30 | self.t = np.arange(0,self.n)*self.dt 31 | self.F = 2*np.exp(1j*30*self.t) 32 | 33 | def dz(self, z, i, omega): 34 | return self.dt*((self.mu - np.abs(z)**2)*z + 1j*omega*z + self.eps*self.F[i].imag) 35 | 36 | def domega(self, z, i): 37 | return self.dt*((-1)*self.eps*self.F[i].imag*z.imag/np.abs(z)) 38 | 39 | def phase(self, z): 40 | real = z.real 41 | imag= z.imag 42 | phase = np.arctan(imag/real) 43 | return phase 44 | 45 | def train(self): 46 | for i in tqdm(range(0, self.n)): 47 | self.Aph[i] = self.phase(self.z) 48 | self.Az[i] = self.z 49 | self.Aomega[i] = self.omega 50 | self.Ar[i] = np.abs(self.z) 51 | self.z = self.z + self.dz(self.z, i, self.omega) 52 | self.omega = self.omega + self.domega(self.z, i) 53 | 54 | def plot(self): 55 | fig, axes = plt.subplots(1,3) 56 | axes[0].plot(self.t, self.Aomega) 57 | axes[0].set_title('Frequency Plot against time') 58 | axes[1].plot(self.t, self.Aph) 59 | axes[1].set_title('Phase plot against time') 60 | axes[2].plot(self.t, self.Ar) 61 | axes[2].set_title('Magnitude Plot against time') 62 | plt.show() 63 | 64 | def main(self): 65 | self.train() 66 | self.plot() 67 | 68 | F = 2*np.exp(1j*30*t) 69 | num = int(1/(15*dt)) 70 | print(num) 71 | k = 0 72 | for i in range(n): 73 | if i%num>=num/4 or F[i]<0.0: 74 | F[i] = F[i]*0.001 75 | fig, axes = plt.subplots(1,1) 76 | axes.plot(t[:100], F[:100]) 77 | axes.set_title('teaching signal') 78 | fig.savefig('../plots/teaching_signal_exp_1_hopf.png') 79 | hopf_osc = Adaptive_Hopf_Oscillator(F=F) 80 | print(hopf_osc.Aomega) 81 | print(hopf_osc.Ar) 82 | hopf_osc.main() 83 | print(hopf_osc.Aomega) 84 | print(hopf_osc.Ar) 85 | fig, axes = plt.subplots(1,3) 86 | axes[0].plot(hopf_osc.t, hopf_osc.F.real) 87 | axes[1].plot(hopf_osc.t, hopf_osc.F.imag) 88 | axes[2].plot(hopf_osc.Aomega) 89 | plt.show() 90 | plt.savefig('com_adaptive_osc_exp_1.png') 91 | -------------------------------------------------------------------------------- /coupled_hopf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from tqdm import tqdm 5 | 6 | n = 1000000 7 | dt = 0.001 8 | t = np.arange(0, n+1)*dt 9 | 10 | class Hopf(object): 11 | def __init__(self, 12 | v, 13 | offset, 14 | omega_sw # controls the speed of the robot, also swing frequency 15 | mu, 16 | beta, # duty factor 17 | l, 18 | a): 19 | self.mu = mu 20 | self.omega_sw = omega_sw 21 | self.x = 0.0 22 | self.y = 0.0 23 | self.omega = 0.0 24 | self.l = l 25 | self.beta = beta 26 | self.offset = offset 27 | 28 | def r(self): 29 | return np.sqrt((self.x-self.offset)**2+self.z**2) 30 | 31 | def dx(self): 32 | return self.alpha*(self.mu*self.v - (self.r())**2)*(self.x-self.offset)-self.omega()*self.l*self.y 33 | 34 | def dy(self): 35 | return self.alpha*(self.mu*self.v - (self.r())**2)*self.y-self.omega()*self.l*(self.x-self.offset) 36 | 37 | def omega(self): 38 | return ((1/self.beta - 2)*self.omega_sw)/(np.exp(-self.a*self.y)+1)+self.omega_sw/(np.exp(self.a*self.z)+1) 39 | 40 | def set_x(self, x): 41 | self.x = x 42 | 43 | def set_omega(self, omega): 44 | self.omega = omega 45 | 46 | def set_y(self, y): 47 | self.y = y 48 | 49 | def set_v(self, v): 50 | self.v = v 51 | 52 | def set_mu(self, mu): 53 | self.mu = mu 54 | 55 | def set_omega_sw(self, omega_sw): 56 | self.omega_sw = omega_sw 57 | 58 | def set_l(self, l): 59 | self.l = l 60 | 61 | def set_offset(self): 62 | self.offset = offset 63 | 64 | def rotation_matrix(self, theta, l): 65 | """ 66 | theta is the relative phase between the two oscillator for which the rotation matrix has to be calculated 67 | """ 68 | R = [[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]] 69 | return l*np.array(R) 70 | 71 | class Knee(object): 72 | def __init__(self, 73 | b, 74 | a, 75 | theta_sw, 76 | theta_st): 77 | self.b = b 78 | self.a = a 79 | self.v = 0.0 80 | self.z = 0.0 81 | self.theta_st = theta_st 82 | self.theta_sw = theta_sw 83 | 84 | def dz(self): 85 | return self.v 86 | 87 | def dv(self, y): 88 | return -(self.b**2)*(self.z-self.g(y))/4 - self.b*self.v 89 | 90 | def g(self, y): 91 | return self.theta_st/(np.exp(-self.a*y)+1) + self.theta_sw/(np.exp(self.a*y)+1) 92 | 93 | def set_z(self, z): 94 | self.z = z 95 | 96 | def set_v(self, v): 97 | self.v = v 98 | 99 | def set_theta_st(self, theta): 100 | self.theta_st = theta 101 | 102 | def set_theta_sw(self, theta): 103 | self.theta_sw = theta 104 | 105 | def set_a(self, a): 106 | self.a = a 107 | 108 | def set_b(self, b): 109 | self.b = b 110 | 111 | class CPG(object): 112 | def __init__(self, 113 | K_mat, 114 | v, 115 | offset, 116 | omega_sw # controls the speed of the robot, also swing frequency 117 | mu, 118 | beta, # duty factor 119 | l, 120 | K_mat, 121 | a, 122 | b, 123 | theta_st, 124 | theta_sw, 125 | num = 4, 126 | dt = 0.001, 127 | n = 1000000): 128 | self.num = num 129 | self.dt = dt 130 | self.n = n 131 | self.K_mat = K_mat 132 | self.osc = [] 133 | self.knee = [] 134 | for i in range(self.num): 135 | self.osc.append(Hopf(v = v[i], 136 | offset = offset[i], 137 | omega_sw = omega_sw[i], 138 | mu = mu[i], 139 | beta = beta[i], 140 | l = l[i], 141 | a = a[i])) 142 | self.knee.append(Knee(b = b[i], 143 | a = a[i], 144 | theta_sw = theta_sw[i], 145 | theta_st = theta_st[i])) 146 | 147 | self.t = np.arange((self.n))*self.dt 148 | self.Ax = np.zeros((self.n, self.num)) 149 | self.Ay = np.zeros((self.n, self.num)) 150 | self.Az = np.zeros((self.n, self.num)) 151 | self.Av = np.zeros((self.n, self.num)) 152 | self.Aomega = np.zeros((self.n, self.num)) 153 | self.Ag = np.zeros((self.n, self.num)) 154 | self.x = np.zeros((self.num)) 155 | self.y = np.zeros((self.num)) 156 | self.z = np.zeros((self.num)) 157 | self.v = np.zeros((self.num)) 158 | self.omega = np.zeros((self.num)) 159 | self.g = np.zeros((self.num)) 160 | 161 | def simulate(self): 162 | for i in range(self.n): 163 | self.Ax[i, :] = self.x 164 | self.Ay[i, :] = self.y 165 | self.Az[i, :] = self.z 166 | self.Av[i, :] = self.v 167 | self.Aomega[i, :] = self.omega 168 | self.Ag[i, :] = self.g 169 | for i in range(self.num): 170 | self.x[i] += (self.osc[i].dx() + )*self.dt 171 | self.y[i] += self.osc[i].dy()*self.dt 172 | self.omega[i] = self.osc[i].omega() 173 | self.osc[i].set_x(self.x) 174 | self.osc[i].set_y(self.y) 175 | self.osc[i].set_omega(self.omega) 176 | self.z = self.knee[i] 177 | -------------------------------------------------------------------------------- /matlab_code/adhopf.m: -------------------------------------------------------------------------------- 1 | % complex adaptive Hopf 2 | 3 | clear all 4 | niter = 1000000; 5 | dt = 0.01; 6 | mu = 1; 7 | eps = 0.9; 8 | omgos = 40; 9 | omgip = 30; 10 | x = 1; 11 | y = 0; 12 | amp_max = 1; 13 | 14 | omgosarr = zeros(1,niter); 15 | xarr = zeros(1,niter); 16 | yarr = zeros(1,niter); 17 | t = (0:1:niter-1)*dt; 18 | inp_arr = amp_max*sin(omgip*t); 19 | 20 | for k = 1:niter 21 | k 22 | xarr(k) = x; 23 | yarr(k) = y; 24 | omgosarr(k) = omgos; 25 | dx =dt*((mu - (x^2+y^2))*x - omgos*y + eps*inp_arr(k)); 26 | dy =dt*((mu - (x^2+y^2))*y + omgos*x); 27 | domg = dt*((-1)*eps*inp_arr(k)*y/sqrt(x^2+y^2)); 28 | x = x + dx; 29 | y = y + dy; 30 | omgos = omgos + domg; 31 | 32 | end 33 | 34 | plot(omgosarr) -------------------------------------------------------------------------------- /matlab_code/com_CPG.m: -------------------------------------------------------------------------------- 1 | % complex adaptive Hopf 2 | 3 | clear all 4 | niter = 1000000; 5 | dt = 0.001; 6 | t = (0:1:niter-1)*dt; 7 | mu = 1; 8 | eps = 0.9; 9 | etaalp = 0.5; 10 | 11 | nos = 4; 12 | omgos = rand(nos,1)*20; 13 | z = exp(1i*rand(nos,1)*2*pi); 14 | alpha = rand(nos,1); 15 | 16 | % Pteach signal construction 17 | pteach = zeros(1,niter); 18 | omgip = zeros(1,4); 19 | I_max = zeros(1,4); 20 | ipph = zeros(1,4); 21 | omgip(1) = 5; 22 | omgip(2) = 10; 23 | omgip(3) = 15; 24 | omgip(4) = 20; 25 | I_max(1) = 1.1; 26 | I_max(2) = 0.8; 27 | I_max(3) = 1.5; 28 | I_max(4) = 0.7; 29 | ipph(1) = pi/3; 30 | ipph(2) = pi/4; 31 | ipph(3) = pi/2; 32 | ipph(4) = pi/5; 33 | for j = 1:nos 34 | pteach = pteach + I_max(j)*sin(omgip(j)*t+ipph(j)); 35 | end 36 | St = zeros(1,niter); 37 | et = zeros(1,niter); 38 | 39 | omgosarr = zeros(nos,niter); 40 | alphaarr = zeros(nos,niter); 41 | zarr = zeros(nos,niter); 42 | rarr = zeros(nos,niter); 43 | angarr = zeros(nos,niter); 44 | dz = zeros(nos,1); 45 | domg = zeros(nos,1); 46 | dalpha = zeros(nos,1); 47 | 48 | for i = 1:niter 49 | i 50 | rarr(:,i) = abs(z); 51 | angarr(:,i) = angle(z); 52 | zarr(:,i) = z; 53 | omgosarr(:,i) = omgos; 54 | alphaarr(:,i) = alpha; 55 | 56 | St(i) = alpha'*real(z); 57 | et(i) = pteach(i) - St(i); 58 | 59 | for j = 1:nos 60 | dz(j) =dt*((mu - abs(z(j))^2)*z(j) + 1i*omgos(j)*z(j) + eps*et(i)); 61 | domg(j) = dt*((-1)*eps*et(i)*imag(z(j))/abs(z(j))); 62 | dalpha(j) = dt*(etaalp*real(z(j))*et(i)); 63 | end 64 | 65 | z = z + dz; 66 | omgos = omgos + domg; 67 | alpha = alpha + dalpha; 68 | end 69 | 70 | 71 | figure(5) 72 | for j=1:nos 73 | angarr(j,:) = unwrap(angarr(j,:))-omgosarr(j,:).*t; 74 | plot(t,angarr(j,:)); 75 | hold on 76 | end 77 | legend('os1','os2','os3','os4') 78 | ylabel('angle(z)-omega*t') 79 | xlabel('time') 80 | 81 | figure(1) 82 | for j = 1:nos 83 | plot(t,omgosarr(j,:)) 84 | hold on 85 | end 86 | legend('os1','os2','os3','os4') 87 | ylabel('omega') 88 | xlabel('time') 89 | 90 | 91 | figure(2) 92 | for j = 1:nos 93 | plot(t,rarr(j,:)) 94 | hold on 95 | end 96 | legend('os1','os2','os3','os4') 97 | ylabel('abs(z)/r') 98 | xlabel('time') 99 | 100 | figure(3) 101 | for j = 1:nos 102 | plot(t,alphaarr(j,:)) 103 | hold on 104 | end 105 | legend('os1','os2','os3','os4') 106 | ylabel('alpha') 107 | xlabel('time') 108 | 109 | figure(4) 110 | for j = 1:nos 111 | plot(t,angarr(j,:)) 112 | hold on 113 | end 114 | legend('os1','os2','os3','os4') 115 | ylabel('angle(z)') 116 | xlabel('time') -------------------------------------------------------------------------------- /matlab_code/com_CPG1.m: -------------------------------------------------------------------------------- 1 | % complex adaptive Hopf 2 | 3 | clear all 4 | niter = 2000000; 5 | dt = 0.001; 6 | t = (0:1:niter-1)*dt; 7 | mu = 1; 8 | eps = 0.9; 9 | etaalp = 0.5; 10 | 11 | nos = 4; 12 | omgos = rand(nos,1)*20; 13 | z = exp(1i*rand(nos,1)*2*pi); 14 | alpha = rand(nos,1); 15 | 16 | % Pteach signal construction 17 | pteach = zeros(1,niter); 18 | omgip = zeros(1,4); 19 | I_max = zeros(1,4); 20 | ipph = zeros(1,4); 21 | omgip(1) = 5; 22 | omgip(2) = 10; 23 | omgip(3) = 15; 24 | omgip(4) = 20; 25 | I_max(1) = 1.1; 26 | I_max(2) = 0.8; 27 | I_max(3) = 1.5; 28 | I_max(4) = 0.7; 29 | ipph(1) = pi/3; 30 | ipph(2) = pi/4; 31 | ipph(3) = pi/2; 32 | ipph(4) = pi/5; 33 | for j = 1:nos 34 | pteach = pteach + I_max(j)*exp(1i*(omgip(j)*t+ipph(j))); 35 | end 36 | pteach1 = real(pteach); 37 | St = zeros(1,niter); 38 | et = zeros(1,niter); 39 | 40 | omgosarr = zeros(nos,niter); 41 | alphaarr = zeros(nos,niter); 42 | zarr = zeros(nos,niter); 43 | rarr = zeros(nos,niter); 44 | angarr = zeros(nos,niter); 45 | dz = zeros(nos,1); 46 | domg = zeros(nos,1); 47 | dalpha = zeros(nos,1); 48 | 49 | for i = 1:niter 50 | i 51 | rarr(:,i) = abs(z); 52 | angarr(:,i) = angle(z); 53 | zarr(:,i) = z; 54 | omgosarr(:,i) = omgos; 55 | alphaarr(:,i) = alpha; 56 | 57 | St(i) = alpha'*real(z); 58 | et(i) = pteach1(i) - St(i); 59 | 60 | for j = 1:nos 61 | dz(j) =dt*((mu - abs(z(j))^2)*z(j) + 1i*omgos(j)*z(j) + eps*et(i)); 62 | domg(j) = dt*((-1)*eps*et(i)*imag(z(j))/abs(z(j))); 63 | dalpha(j) = dt*(etaalp*real(z(j))*et(i)); 64 | end 65 | 66 | z = z + dz; 67 | omgos = omgos + domg; 68 | alpha = alpha + dalpha; 69 | end 70 | 71 | 72 | figure(5) 73 | for j=1:nos 74 | angarr(j,:) = unwrap(angarr(j,:))-omgosarr(j,:).*t; 75 | plot(t,angarr(j,:)); 76 | hold on 77 | end 78 | legend('os1','os2','os3','os4') 79 | ylabel('angle(z)-omega*t') 80 | xlabel('time') 81 | 82 | figure(1) 83 | for j = 1:nos 84 | plot(t,omgosarr(j,:)) 85 | hold on 86 | end 87 | legend('os1','os2','os3','os4') 88 | ylabel('omega') 89 | xlabel('time') 90 | 91 | 92 | figure(2) 93 | for j = 1:nos 94 | plot(t,rarr(j,:)) 95 | hold on 96 | end 97 | legend('os1','os2','os3','os4') 98 | ylabel('abs(z)/r') 99 | xlabel('time') 100 | 101 | figure(3) 102 | for j = 1:nos 103 | plot(t,alphaarr(j,:)) 104 | hold on 105 | end 106 | legend('os1','os2','os3','os4') 107 | ylabel('alpha') 108 | xlabel('time') 109 | 110 | % figure(4) 111 | % for j = 1:nos 112 | % plot(t,angarr(j,:)) 113 | % hold on 114 | % end 115 | % legend('os1','os2','os3','os4') 116 | % ylabel('angle(z)') 117 | % 118 | % xlabel('time') -------------------------------------------------------------------------------- /matlab_code/com_adhopf.m: -------------------------------------------------------------------------------- 1 | % complex adaptive Hopf 2 | 3 | clear all 4 | niter = 1000000; 5 | dt = 0.001; 6 | mu = 1; 7 | eps = 0.9; 8 | omgos = 40; 9 | omgip = 30; 10 | amp_max = 1; 11 | z = exp(1i*rand*2*pi); 12 | 13 | omgosarr = zeros(1,niter); 14 | zarr = zeros(1,niter); 15 | rarr = zeros(1,niter); 16 | phiarr = zeros(1,niter); 17 | t = (0:1:niter-1)*dt; 18 | inp_arr = amp_max*exp(1i*omgip*t); 19 | for k = 1:niter 20 | k 21 | phiarr(k) = angle(z); 22 | rarr(k) = abs(z); 23 | zarr(k) = z; 24 | omgosarr(k) = omgos; 25 | dz = dt*((mu - abs(z)^2)*z + 1i*omgos*z + eps*imag(inp_arr(k))); 26 | domg = dt*((-1)*eps*imag(inp_arr(k))*imag(z)/abs(z)); 27 | z = z + dz; 28 | 29 | omgos = omgos + domg; 30 | 31 | end 32 | 33 | plot(omgosarr) 34 | figure(2) 35 | plot(rarr) 36 | figure(3) 37 | plot(phiarr) 38 | -------------------------------------------------------------------------------- /plots/com_adaptive_osc_exp_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shandilya1998/adaptive-hopf-oscillator/d193868b44ce3460c048d7631fc7bdb4e15eedb9/plots/com_adaptive_osc_exp_1.png -------------------------------------------------------------------------------- /plots/com_cpg_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shandilya1998/adaptive-hopf-oscillator/d193868b44ce3460c048d7631fc7bdb4e15eedb9/plots/com_cpg_plot.png -------------------------------------------------------------------------------- /plots/com_cpg_plot_omega.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shandilya1998/adaptive-hopf-oscillator/d193868b44ce3460c048d7631fc7bdb4e15eedb9/plots/com_cpg_plot_omega.png -------------------------------------------------------------------------------- /plots/com_cpg_plot_z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shandilya1998/adaptive-hopf-oscillator/d193868b44ce3460c048d7631fc7bdb4e15eedb9/plots/com_cpg_plot_z.png --------------------------------------------------------------------------------