Dada una ecuación de cómo vibra una cuerda
$c^2\cdot \frac{{\partial }^2u\left(x,t\right)}{\partial x^2}=\frac{{\partial }^2u(x,t)}{\partial t^2}$
Aplicando un cambio de variable y resolviendo un problema de contorno y una ecuación diferencial, se puede obtener la solución de la ecuación de onda [Véase TFG]
La solución de la ecuación de onda es: $u(x,t)=\sum_{n=1}^{\infty} \sin\left(\sqrt{\lambda_n} x\right)\left(A_n\cos\left(c\sqrt{\lambda_n} t\right) +B_n\sin\left(c\sqrt{\lambda_n} t\right)\right)$ donde
Sabemos, además que se generan las relaciones:
Una clase WaveEquation es creada para modelar la ecuación de onda.
Lo más importante para la creación de un modelo básico de cualquier cuerda es la inicialización de las variables:
ya que $c=f_1\cdot 2L$ deja definida el valor $c$ de la cuerda.
weq = WEQ(fundamentalFreq=Symbol("f_1"),x=x,t=t,n=n,L=Symbol("L"))
display(weq)
De ahora en adelante, definimos una cuerda con frecuencia fundamental $f_1=440\ Hz$ (la frecuencia de la nota La o A4 en la notación franco-belga) y longitud $L=3.3\ dm$ que equivale a la longitud de una cuerda de violín normal.
freq = 440
L = Rational(33,10)
violin = WEQ(fundamentalFreq=freq,x=x,t=t,n=n,L=L)
harp = WEQ(fundamentalFreq=freq,x=x,t=t,n=n,L=L)
piano = WEQ(fundamentalFreq=freq,x=x,t=t,n=n,L=5)
display(violin)
Sabemos que al tocar un instrumento de cuerda pulsada de manera simple lo que hacemos con el dedo es estirar la cuerda en un punto y soltará, por lo que no existirá ninguna velocidad inicial, pero si posición inicial, esto es, posición de la cuerda justo cuando la hemos estirado, como en el ejemplo de la imagen.
Con esto en mente, procedemos a definir las variables de posición inicial de la cuerda y velocidad inicial como:
l = 0.6*harp.L # plucked position
h = 0.06 # plucked height
posInicialHarp = Piecewise(
(h/l *x,And(0<=x,x<=l)),
(h*(harp.L-x)/(harp.L-l),And(l<=x,x<=harp.L))
)
velocidadInicialHarp = 0
plotPrintCondiciones(harp,posInicialHarp,velocidadInicialHarp)
A diferencia de la guitarra, los instrumentos de cuerda frotada dependen del arco, que se moverá a una velocidad (asumiéremos que es constante) y la posición inicial será 0, ya que parte de reposo la cuerda, pero lo que no es $0$ es la velocidad inicial de cada punto pues es movida/impuesta por el arco.
Veamos un ejemplo visual
A pesar de que no se observe la velocidad inicial en la imagen, el efecto que tiene el arco sobre la cuerda sí se observa y con esto podemos definir las variables de posición inicial de la cuerda y velocidad inicial como:
v = 1
p = 0.11
s = 3
posInicialViolin = 0
velocidadInicialViolin = Piecewise(
(((v*x)/(s-p/2)),And(0<=x,x<=s-p/2)),
((v*(s-p/2))/(s-p/2),And(s-p/2<=x,x<=s+p/2)),
((v*(violin.L-x))/(violin.L-(s+p/2)),And(s+p/2<=x,x<=violin.L))
)
plotPrintCondiciones(violin,posInicialViolin,velocidadInicialViolin)
A diferencia de la guitarra o un violin, los instrumentos de cuerda percutida dependen de un martillo, que golpeara la cuerda a una velocidad (asumiéremos que es constante) y la posición inicial será 0, ya que parte de reposo la cuerda, pero lo que no es $0$ es la velocidad inicial de cada punto pues es determinada por la accion del martillo.
Veamos un ejemplo visual
A pesar de que no se observe la velocidad inicial en la imagen, el efecto que tiene el martillo sobre la cuerda sí se observa y con esto podemos definir las variables de posición inicial de la cuerda y velocidad inicial como:
l = 0.075*piano.L # Tamaño Martillo
x0 = 0.72*piano.L # Posición Martillo
epsi = 0.005 # Pequeña propagacion del martillo
v = 3 # Velocidad del martillo
posInicialPiano = 0
velocidadInicialPiano = Piecewise(
(0,And(0<=x,x<=(x0-l/2-epsi))),
((v*(x-x0+l/2+epsi))/epsi,And((x0-l/2-epsi)<=x,x<=(x0-l/2))),
(v,And((x0-l/2)<=x,x<=(x0+l/2))),
((v*(x0+l/2+epsi-x))/epsi,And((x0+l/2)<=x,x<=(x0+l/2+epsi))),
(0,And((x0+l/2+epsi)<=x,x<=piano.L))
)
plotPrintCondiciones(piano,posInicialPiano,velocidadInicialPiano)
Puesto que existen variables desconocidas imponiendo las condiciones las obtendremos, aquí entra en juego las series de Fourier y la completitud de la solución que hemos obtenido:
$A_n = \frac{2}{L}\int_a^b \psi(x,0) \sin({\frac{n\pi}{L}x}) dx$
$B_n = \frac{2}{n\pi c} \int_a^b \left(\frac{\partial \psi}{\partial t}(x,0)\right) \sin({\frac{n\pi}{L}x}) dx$
Hagamos la integral con nuestro modelo
An = harp.findAn(posInicialHarp)
Bn = harp.findBn(velocidadInicialHarp)
showAnBn(An,Bn)
harp.setAmplitudes(An,Bn)
display(harp)
An = violin.findAn(posInicialViolin)
Bn = violin.findBn(velocidadInicialViolin)
showAnBn(An,Bn)
violin.setAmplitudes(An,Bn)
display(violin)
An = piano.findAn(posInicialPiano)
Bn = piano.findBn(velocidadInicialPiano)
showAnBn(An,Bn)
piano.setAmplitudes(An,Bn)
display(piano)
Las herramientas de programación nos ayudan a visualizar y entender de otro modo la abstracción matemática.
Fijado un valor $c$, los autovalores $\lambda_n$ nos dan las sucesivas frecuencias de vibración de la cuerda, es decir, las frecuencias a las que resuena la cuerda.
Las frecuencias a su vez se tratan de lo que se conoce como modos normales de la cuerda, se suelen llamar también frecuencias naturales y se tratan de frecuencias a las que la cuerda vibrara al ser perturbada.
for i in range(1,normalMode+1):
print(violin.f_n.evalf(subs={n:i}))
440.000000000000 880.000000000000 1320.00000000000 1760.00000000000 2200.00000000000 2640.00000000000
En el mundo musical, estas frecuencias naturales son lo que se conocen como Armónicos y tienen un sonido muy característico, pues cambian el timbre del instrumento.
Sabemos que $\psi_n(x,t) = \sin\left(\sqrt{\lambda_n} x\right)\left(A_n\cos\left(c\sqrt{\lambda_n} t\right) +B_n\sin\left(c\sqrt{\lambda_n} t\right)\right)$
Usando las relaciones del principio nos permite simplificar obteniendo $\left(A_n{\mathrm{cos} \left(2\pi f_n t\right)\ }+B_n{\mathrm{sin} \left( 2\pi f_n t\right)\ }\right)\mathrm{\ sin}\left(\frac{2\pi f_n}{c} x\right)$
Es decir, se trata de una ecuación en un modo normal dado por $n$, y nos representa la posición de la cuerda en el instante $t$, veamos un ejemplo:
filename = f'./Graficas/normalMode_{normalMode}_{"Slow" if slowed else "Normal"}.gif'
ani = violin.plotNormalMode_Animated(normalMode,slow=slowed)
#ani.save(filename)
plt.close()
displayGif(filename)

Podemos observar como la cuerda se mueve o vibra a medida que el tiempo avanza, un hecho a destacar es que cada elemento entre los nodos fijos oscila con la misma frecuencia.
En vista de la ecuación, observamos que $A_n$ y $B_n$ son constantes, en función de n, que multiplican a los modos normales, es decir, se tratan de amplitudes o el "volumen" de los modos normales.
El hecho de que las amplitudes sean el "volumen" de los modos normales es lo que permite a nuestro oído detectar el timbre de la cuerda o instrumento, de ahí que un violín y una viola se oigan distintos.
Aqui se muestra un ejemplo de la amplitud de los modos normales:
harp.plotEspectro(N=normalMode)
violin.plotEspectro(N=normalMode)
piano.plotEspectro(N=normalMode)
Usando el principio de superposición de soluciones sabemos que la cuerda realmente es la suma de todos los modos normales junto a su "volumen".
$u(x,t)=\sum_{n=1}^{\infty} \psi_n(x,t)$
Veamos un ejemplo con 6 modos normales:
ani = violin.plotNormalModesCombined_Animated(slow=slowed)
plt.close()
#ani.save(f'./Graficas/normalModesCombined.gif')
displayGif(f'./Graficas/normalModesCombined.gif')

filename = f'./Graficas/HarpString.gif'
ani = harp.plotString_Animated(normalMode)
#ani.save(filename)
plt.close()
displayGif(filename)

filename = f'./Graficas/ViolinString.gif'
ani = violin.plotString_Animated(normalMode)
#ani.save(filename)
plt.close()
displayGif(filename)

filename = f'./Graficas/PianoString.gif'
ani = piano.plotString_Animated(normalMode)
#ani.save(filename)
plt.close()
displayGif(filename)

Fijando un punto de la cuerda y viendo cómo cambia según $t$ podemos ver el trazado de la onda en el tiempo.
harp.plotTimeWave(N=normalMode)
violin.plotTimeWave(N=normalMode)
piano.plotTimeWave(N=normalMode)
Comparemoslos (Normalizandolos)
violin.plotTimeWave_Compare([harp,piano],N=normalMode)
Veamos el sonido que produce nuestro modelo
audio,dataAudio = (harp.makeSound(
segundos = 5,
modosNormales = 30,
startAt=1,
normalize=True,
fadeOut=True,
filename= f"./Sonidos/Plucked_{harp.fundamentalFreq}Hz",
guitarCase=True
))
audio,dataAudio = (violin.makeSound(
segundos = 5,
modosNormales = 20,
startAt=1,
normalize=True,
fadeOut=True,
filename= f"./Sonidos/Bowed_{violin.fundamentalFreq}Hz"
))
audio,dataAudio = (piano.makeSound(
segundos = 5,
modosNormales = 20,
startAt=1,
normalize=True,
fadeOut=True,
filename= f"./Sonidos/Strucked_{piano.fundamentalFreq}Hz"
))
Partimos de un "Do" a 32 y construyamos las notas en 5 octavas distintas, moviéndonos por quintas
notas = violin.getMusicalNotes_Pythagoras(32,5)
notas.keys()
dict_keys(['Do1', 'Reb1', 'Re1', 'Mib1', 'Mi1', 'Fa1', 'Fa#1', 'Sol1', 'Lab1', 'La1', 'Sib1', 'Si1', 'Do2', 'Reb2', 'Re2', 'Mib2', 'Mi2', 'Fa2', 'Fa#2', 'Sol2', 'Lab2', 'La2', 'Sib2', 'Si2', 'Do3', 'Reb3', 'Re3', 'Mib3', 'Mi3', 'Fa3', 'Fa#3', 'Sol3', 'Lab3', 'La3', 'Sib3', 'Si3', 'Do4', 'Reb4', 'Re4', 'Mib4', 'Mi4', 'Fa4', 'Fa#4', 'Sol4', 'Lab4', 'La4', 'Sib4', 'Si4', 'Do5', 'Reb5', 'Re5', 'Mib5', 'Mi5', 'Fa5', 'Fa#5', 'Sol5', 'Lab5', 'La5', 'Sib5', 'Si5', 'Shhh'])
display(tabla_notas)
| Do | Reb | Re | Mib | Mi | Fa | Fa# | Sol | Lab | La | Sib | Si | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 32.0 | 34.171875 | 36.0 | 37.925926 | 40.5 | 42.666667 | 45.5625 | 48.0 | 51.257812 | 54.0 | 56.888889 | 60.75 |
| 2 | 64.0 | 68.343750 | 72.0 | 75.851852 | 81.0 | 85.333333 | 91.1250 | 96.0 | 102.515625 | 108.0 | 113.777778 | 121.50 |
| 3 | 128.0 | 136.687500 | 144.0 | 151.703704 | 162.0 | 170.666667 | 182.2500 | 192.0 | 205.031250 | 216.0 | 227.555556 | 243.00 |
| 4 | 256.0 | 273.375000 | 288.0 | 303.407407 | 324.0 | 341.333333 | 364.5000 | 384.0 | 410.062500 | 432.0 | 455.111111 | 486.00 |
| 5 | 512.0 | 546.750000 | 576.0 | 606.814815 | 648.0 | 682.666667 | 729.0000 | 768.0 | 820.125000 | 864.0 | 910.222222 | 972.00 |
Partitura = [
(2,["Do4","Sol4"]),
(2,["Reb4","Lab4"]),
(2,["Re4","La4"]),
(2,["Mib4","Sib4"]),
(2,["Mi4","Si4"]),
(2,["Fa4","Do5"]),
(2,["Fa#4","Reb5"]),
(2,["Sol4","Re5"]),
(1,["Lab4","Mib5"]), # Sol# - Mib
]
y_data = WEQ.makeSong(notas,Partitura,100,"Fifths_WolfInterval",normalMode=20)
instruments = [harp,violin,piano]
for instrument in instruments:
nombreInstrumento = [name for name in globals() if globals()[name] is instrument][0]
WEQ.makeSong(instrument.getMusicalNotes_Pythagoras(32,5), bachFugue, 90, f"BachFugue_{nombreInstrumento}",
normalMode=30,guitarCase="harp"==nombreInstrumento)
YouTubeVideo("oq6D5Ll1Rqw",width=800, height=480)
Ya hemos visto que este sistema de afinacion por quientas de Pitágoras está errado.
De ahí que a lo largo de la historia se hayan buscado distintas formas de afinar las notas, pero no se ha encontrado ninguna que funcione de manera "simple", es decir, con relaciones sencillas entre los números.
De ahí que se empezó a cambiar a otros sistemas de afinación con el objetivo de arreglar estos errores, es por ello que hoy en día se utiliza (en pianos sobre todo) el "Temperamento Igual" que consiste en que el semitono sea exactamente $\sqrt[12]{2}$, en definitiva, un número irracional.
La idea detrás de este número es que elevando 12 semitonos obtengamos la octava perfecta (Sí, la de Pitágoras) la 2
![]() |
Estudiante de Matemáticas e Informática de la Universidad Politécnica de Madrid"The present is theirs; the future, for which I have really worked, is mine."- Nikola Tesla
|