basic python piano string state space system
This commit is contained in:
@@ -2,29 +2,76 @@
|
||||
import scipy.signal as sig
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
# simple first order step response simulation
|
||||
# www.halvorsen.blog/documents/programming/python/resources/powerpoints/State Space Models with Python.pdf
|
||||
|
||||
# simulation Parameters
|
||||
x0 = [0, 0]
|
||||
|
||||
# string pde (wave equation)
|
||||
# rho*A*d2y(x,t)/dt2 + c*dy(x,t)/dt - T*d2y(x,t)/dx2 = f(x,t)
|
||||
# where rho*A = 1 dimensional string density, c = string damping, T = string tension, y(x,t) = displacement, f(x,t) = exitation force
|
||||
|
||||
# assume fixed ends: y(0, t) = y(L, t) = 0
|
||||
|
||||
# displacement y(x,t) can be represented as the sum from n=1 to N of qn(t)*sin(n*pi*x/L) where q_n(t) is the modal coordinate of mode n (displacement is the sum of all resonating modes)
|
||||
# therefore:
|
||||
# q..n + 2*zeta_n*omega_n*q.n + omega_n2*q_n = b_n*u(t)
|
||||
# where omega_n = n*pi/L * sqrt(T/(rho*A)) for an ideal string
|
||||
# and b_n = sin(n*pi*x_h/L) but assuming the hammer strikes at midpoint, x_h = L/2 ( b_n = sin(n*pi/2) )
|
||||
|
||||
# state space representation:
|
||||
# each mode:
|
||||
#「 q_n_dot | =「 0 1 | 「 q_n | + 「 0 |* u
|
||||
# L q_n_dot_dot 」= L -omega_n^2 -2*zeta_n*omega_n 」 L q_ndot 」 L b_n 」
|
||||
# and x_dot = Ax + Bu
|
||||
# where A = diagonal matrix of A_n and B = [ 0 b_1 0 b_2 ... b_n]^T
|
||||
|
||||
# lets start with 3 nodes where the string is tuned to 440hz (we'll get to arbitrary modes evantually)
|
||||
f_1 = 440 # fundamental frequency
|
||||
def f_n(n):
|
||||
return f_1 * n
|
||||
def omega_n(n):
|
||||
return 2*math.pi*f_n(n) # a cooler option would be omega_n = c*n*omega_1*sqrt(1+B*n^2) to factor in string stiffness to its vibration mode
|
||||
|
||||
# x = [ q1, q1dot, q2, q2dot, q3, q3dot ]^T < --state vector
|
||||
omega_1 = omega_n(1)
|
||||
omega_2 = omega_n(2)
|
||||
omega_3 = omega_n(3)
|
||||
zeta_1 = 0.0001 # i guessed
|
||||
zeta_2 = 2 * zeta_1
|
||||
zeta_3 = 3 * zeta_1
|
||||
A = [
|
||||
[ 0, 1, 0, 0, 0, 0],
|
||||
[-omega_1**2, -2*zeta_1*omega_1, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 1, 0, 0],
|
||||
[ 0, 0, -omega_2**2, -2*zeta_2*omega_2, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 1],
|
||||
[ 0, 0, 0, 0, -omega_3**2, -2*zeta_3*omega_3]
|
||||
] # isnt this formatting gorgeous
|
||||
|
||||
B = [ [0], [0.707], [0], [0], [0], [-0.707] ]
|
||||
c_1 = 0.001
|
||||
c_2 = c_1 / 2
|
||||
c_3 = c_1 / 3
|
||||
C = [[-c_1*omega_1**2, -2*c_1*zeta_1*omega_1, -c_2*omega_2**2, -2*c_2*zeta_2*omega_2, -c_3*omega_3**2, -2*c_3*zeta_3*omega_3]]
|
||||
D = c_1 * 0.707 + c_2 * 0 + c_3 * (-0.707)
|
||||
|
||||
# input
|
||||
#v_h = 100 # hammer velocity
|
||||
#u = v_h * impulse(t)
|
||||
|
||||
x0 = [[0], [0], [0], [0], [0], [0]]
|
||||
start = 0
|
||||
stop = 30
|
||||
step = 1
|
||||
stop = 10
|
||||
step = 1/44100
|
||||
|
||||
t = np.arange(start,stop,step)
|
||||
K = 3
|
||||
T = 4
|
||||
|
||||
# state-space Model
|
||||
A = [[-1/T, 0], [0, 0]]
|
||||
B = [[K/T], [0]]
|
||||
C = [[1, 0]]
|
||||
D = 0
|
||||
sys = sig.StateSpace(A, B, C, D)
|
||||
|
||||
# step Response
|
||||
t, y = sig.step(sys, x0, t)
|
||||
t, y = sig.impulse(sys, T=t)
|
||||
|
||||
# plotting
|
||||
plt.plot(t, y)
|
||||
|
||||
Reference in New Issue
Block a user