forked from Sasserisop/MATH201
added audio generating script
This commit is contained in:
parent
450da746bc
commit
77a42600b2
|
@ -48,7 +48,7 @@ then $f, g$ are orthogonal
|
||||||
the Fourier expansion is called an ortho normal expansion, Taylor is not orthonormal.
|
the Fourier expansion is called an ortho normal expansion, Taylor is not orthonormal.
|
||||||
#end of lec 28
|
#end of lec 28
|
||||||
#start of lec 29
|
#start of lec 29
|
||||||
Last lecture we derived how to find the coefficients in a Fourier series.
|
Last lecture we derived how to find the coefficients of a Fourier series.
|
||||||
$f(x)=\frac{a_{0}}{2}+\sum_{n=1}^\infty\left( a_{n}\cos\left( \frac{n\pi x}{L} \right) + b_{n}\sin\left( \frac{n\pi x}{L}\right) \right)$
|
$f(x)=\frac{a_{0}}{2}+\sum_{n=1}^\infty\left( a_{n}\cos\left( \frac{n\pi x}{L} \right) + b_{n}\sin\left( \frac{n\pi x}{L}\right) \right)$
|
||||||
$x \in [-L,L]$
|
$x \in [-L,L]$
|
||||||
### 1st convergence theorem:
|
### 1st convergence theorem:
|
||||||
|
@ -174,4 +174,41 @@ then:
|
||||||
$$\bar{f}(x)=\frac{2}{\pi}+\frac{2}{\pi}\sum_{k=1}^\infty\left( \frac{1}{2k+1}-\frac{1}{2k-1} \right)\cos(2k\pi x)$$
|
$$\bar{f}(x)=\frac{2}{\pi}+\frac{2}{\pi}\sum_{k=1}^\infty\left( \frac{1}{2k+1}-\frac{1}{2k-1} \right)\cos(2k\pi x)$$
|
||||||
Even with 10 terms, we get a pretty good approximation:
|
Even with 10 terms, we get a pretty good approximation:
|
||||||
![fouriercosineofsin.png](drawings/fouriercosineofsin.png)
|
![fouriercosineofsin.png](drawings/fouriercosineofsin.png)
|
||||||
|
Here's a little script I wrote to generate an audible waveform of this Fourier series!
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<button id="playButton">Play the sound</button>
|
||||||
|
|
||||||
|
<canvas id='scope'></canvas>
|
||||||
|
|
||||||
|
<canvas id='spectrum'></canvas>
|
||||||
|
|
||||||
|
<div class="slidecontainer">
|
||||||
|
<p>Number of harmonics: <span id="textHarmonics"></span></p>
|
||||||
|
<input type="range" min="0" max="100" value="50" style="width: 70%;" id="sliderHarmonics">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="slidecontainer">
|
||||||
|
<p>Frequency: <span id="textFreq"></span></p>
|
||||||
|
<input type="range" min="0" max="440" value="220" style="width: 70%;" id="sliderFreq">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="playaudio.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
||||||
We have prepared ourselves now, now we start solving PDE's. He's encouraging us to attend the lectures in these last two weeks. He's making it sound like PDE's are hard.
|
We have prepared ourselves now, now we start solving PDE's. He's encouraging us to attend the lectures in these last two weeks. He's making it sound like PDE's are hard.
|
|
@ -74,7 +74,7 @@ but we have a boundary condition:
|
||||||
$X(0)=0=c_{1}+c_{2}$
|
$X(0)=0=c_{1}+c_{2}$
|
||||||
$c_{1}+c_{2}=0$
|
$c_{1}+c_{2}=0$
|
||||||
$X(L)=c_{1}e^{\sqrt{ -\lambda }L}+c_{2}e^{-\sqrt{ -\lambda }L}=0$
|
$X(L)=c_{1}e^{\sqrt{ -\lambda }L}+c_{2}e^{-\sqrt{ -\lambda }L}=0$
|
||||||
this has a unique solution, as the determinant is non-zero: $\det\left(\begin{matrix}1 & 1 \\e^{\sqrt{ -\lambda }L} & e^{-\sqrt{ -\lambda }L}\end{matrix}\right)=e^{-\sqrt{ -\lambda }L}-e^{\sqrt{ -\lambda }L}\ne 0$ (as long as $L\ne 0$, which is true since we are assuming the tube has non-zero length.)
|
this has a unique solution, as the determinant is non-zero: $\det\left(\begin{matrix}1 & 1 \\e^{\sqrt{ -\lambda }L} & e^{-\sqrt{ -\lambda }L}\end{matrix}\right)=e^{-\sqrt{ -\lambda }L}-e^{\sqrt{ -\lambda }L}\ne 0$ (as long as $L\ne 0$, which is true since we are assuming the tube has non-zero length. Remember $\lambda\ne 0$ either since $\lambda<0$ in this case.)
|
||||||
the only solution is $c_{1}=0,\ c_{2}=0$
|
the only solution is $c_{1}=0,\ c_{2}=0$
|
||||||
which gives $X(x)=0$ for all $x\in[0,L]$ very boring solution!
|
which gives $X(x)=0$ for all $x\in[0,L]$ very boring solution!
|
||||||
</br>
|
</br>
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
var slider = document.getElementById("sliderHarmonics");
|
||||||
|
var textHarmonics = document.getElementById("textHarmonics");
|
||||||
|
var sliderFreq = document.getElementById("sliderFreq")
|
||||||
|
var textFreq = document.getElementById("textFreq");
|
||||||
|
var playing = document.getElementById("playButton");
|
||||||
|
textHarmonics.innerHTML = slider.value; // Display the default slider value
|
||||||
|
textFreq.innerHTML=sliderFreq.value
|
||||||
|
|
||||||
|
var isPlaying = false;
|
||||||
|
var real = new Float32Array(110);
|
||||||
|
var imag = new Float32Array(110);
|
||||||
|
|
||||||
|
var cspec = document.getElementById('spectrum'),
|
||||||
|
ctxspec = cspec.getContext("2d");
|
||||||
|
|
||||||
|
cspec.height = 200;
|
||||||
|
cspec.width = 500;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sliderFreq.oninput = function() {
|
||||||
|
textFreq.innerHTML=this.value;
|
||||||
|
osc.frequency.value=this.value;
|
||||||
|
}
|
||||||
|
// Update the current slider value (each time you drag the slider handle)
|
||||||
|
slider.oninput = function() {
|
||||||
|
textHarmonics.innerHTML = this.value;
|
||||||
|
if (isPlaying){
|
||||||
|
var numCoeffs = this.value; // The more coefficients you use, the better the approximation
|
||||||
|
//var real = new Float32Array(numCoeffs+10);
|
||||||
|
//var imag = new Float32Array(numCoeffs+10);
|
||||||
|
|
||||||
|
//real[0] = 0.5;
|
||||||
|
//for (var i = 1; i < numCoeffs; i++) { // note i starts at 1
|
||||||
|
// imag[i] = 1 / (i * Math.PI);
|
||||||
|
//}
|
||||||
|
for (var i = 1; i <= 110; i++) {
|
||||||
|
real[i]=0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= numCoeffs; i++) { // note i starts at 1
|
||||||
|
real[2*i] = (2/Math.PI) *( 1/(2*i+1)-1/(2*i-1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
osc.frequency.value = textFreq.innerHTML;
|
||||||
|
//var imag= new Float32Array([0,0,0,0,0]); // sine
|
||||||
|
//var real = new Float32Array(imag.length); // cos
|
||||||
|
var customWave = context.createPeriodicWave(real, imag); // cos,sine
|
||||||
|
osc.setPeriodicWave(customWave);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//isPlaying = false;
|
||||||
|
// osc.stop();
|
||||||
|
//playSound(this.value);}
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
//setup audio context
|
||||||
|
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||||
|
var context = new window.AudioContext();
|
||||||
|
|
||||||
|
//create nodes
|
||||||
|
var osc; //create in event listener so we can press the button more than once
|
||||||
|
var masterGain = context.createGain();
|
||||||
|
var analyser = context.createAnalyser();
|
||||||
|
|
||||||
|
//routing
|
||||||
|
masterGain.connect(analyser);
|
||||||
|
analyser.connect(context.destination);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//draw function for canvas
|
||||||
|
function drawWave(analyser, ctx) {
|
||||||
|
|
||||||
|
var buffer = new Float32Array(1024),
|
||||||
|
w = ctx.canvas.width;
|
||||||
|
|
||||||
|
ctx.strokeStyle = "#D44"; //reddish color
|
||||||
|
ctx.setTransform(1,0,0,-1,0,100.5); // flip y-axis and translate to center
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctxspec.strokeStyle = "#44D" //blueish color
|
||||||
|
ctxspec.setTransform(1,0,0,1,0,100.5);
|
||||||
|
ctxspec.lineWidth = 2;
|
||||||
|
var wspec=ctxspec.canvas.width;
|
||||||
|
(function loop() {
|
||||||
|
analyser.getFloatTimeDomainData(buffer);
|
||||||
|
var prevValue=999;
|
||||||
|
var currentValue=999;
|
||||||
|
for (var i=10; i<1024; i++){
|
||||||
|
currentValue=buffer[i];
|
||||||
|
if (currentValue>prevValue && currentValue>-0.05 && currentValue<0.05){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevValue=currentValue;
|
||||||
|
}
|
||||||
|
ctx.clearRect(0, -100, w, ctx.canvas.height);
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, buffer[i] * 90);
|
||||||
|
for (var x = i; x < w+i; x += 2) ctx.lineTo(x-i+2, buffer[x] * 90);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
//spectrum stuff:
|
||||||
|
//real=getReal();
|
||||||
|
//console.log(real);
|
||||||
|
ctxspec.clearRect(0, -100, wspec, ctxspec.canvas.height);
|
||||||
|
ctxspec.beginPath();
|
||||||
|
ctxspec.moveTo(0, 80);
|
||||||
|
for (var j=0; j<100; j++){
|
||||||
|
ctxspec.lineTo(j*10,real[j]*400+80);
|
||||||
|
}
|
||||||
|
ctxspec.stroke();
|
||||||
|
if (isPlaying) requestAnimationFrame(loop)
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
//button trigger
|
||||||
|
$(function() {
|
||||||
|
var c = document.getElementById('scope'),
|
||||||
|
ctx = c.getContext("2d");
|
||||||
|
|
||||||
|
c.height = 200;
|
||||||
|
c.width = 600;
|
||||||
|
|
||||||
|
// make 0-line permanent as background
|
||||||
|
ctx.moveTo(0, 100.5);
|
||||||
|
ctx.lineTo(c.width, 100.5);
|
||||||
|
ctx.stroke();
|
||||||
|
c.style.backgroundImage = "url(" + c.toDataURL() + ")";
|
||||||
|
|
||||||
|
$('button').on('mousedown', function() {
|
||||||
|
|
||||||
|
if (playing.innerHTML==="Pause sound"){
|
||||||
|
playing.innerHTML="Play the sound";
|
||||||
|
isPlaying = false;
|
||||||
|
osc.stop();
|
||||||
|
}else{
|
||||||
|
playing.innerHTML="Pause sound";
|
||||||
|
playSound(textHarmonics.innerHTML);
|
||||||
|
}});
|
||||||
|
});
|
||||||
|
|
||||||
|
function playSound(h){
|
||||||
|
var c = document.getElementById('scope'),
|
||||||
|
ctx = c.getContext("2d");
|
||||||
|
osc = context.createOscillator();
|
||||||
|
//osc settings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var numCoeffs = h; // The more coefficients you use, the better the approximation
|
||||||
|
|
||||||
|
|
||||||
|
//real[0] = 0.5;
|
||||||
|
//for (var i = 1; i < numCoeffs; i++) { // note i starts at 1
|
||||||
|
// imag[i] = 1 / (i * Math.PI);
|
||||||
|
//}
|
||||||
|
for (var i = 1; i <= 110; i++) {
|
||||||
|
real[i]=0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= numCoeffs; i++) { // note i starts at 1
|
||||||
|
real[2*i] = (2/Math.PI) *( 1/(2*i+1)-1/(2*i-1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//var imag= new Float32Array([0,0,0,0,0]); // sine
|
||||||
|
//var real = new Float32Array(imag.length); // cos
|
||||||
|
var customWave = context.createPeriodicWave(real, imag); // cos,sine
|
||||||
|
osc.setPeriodicWave(customWave);
|
||||||
|
osc.frequency.value = textFreq.innerHTML;
|
||||||
|
osc.connect(masterGain);
|
||||||
|
osc.start();
|
||||||
|
isPlaying = true;
|
||||||
|
|
||||||
|
drawWave(analyser, ctx);
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
var slider = document.getElementById("sliderHarmonics");
|
||||||
|
var textHarmonics = document.getElementById("textHarmonics");
|
||||||
|
var sliderFreq = document.getElementById("sliderFreq")
|
||||||
|
var textFreq = document.getElementById("textFreq");
|
||||||
|
var playing = document.getElementById("playButton");
|
||||||
|
textHarmonics.innerHTML = slider.value; // Display the default slider value
|
||||||
|
textFreq.innerHTML=sliderFreq.value
|
||||||
|
|
||||||
|
var isPlaying = false;
|
||||||
|
var real = new Float32Array(110);
|
||||||
|
var imag = new Float32Array(110);
|
||||||
|
|
||||||
|
var cspec = document.getElementById('spectrum'),
|
||||||
|
ctxspec = cspec.getContext("2d");
|
||||||
|
|
||||||
|
cspec.height = 200;
|
||||||
|
cspec.width = 500;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sliderFreq.oninput = function() {
|
||||||
|
textFreq.innerHTML=this.value;
|
||||||
|
osc.frequency.value=this.value;
|
||||||
|
}
|
||||||
|
// Update the current slider value (each time you drag the slider handle)
|
||||||
|
slider.oninput = function() {
|
||||||
|
textHarmonics.innerHTML = this.value;
|
||||||
|
if (isPlaying){
|
||||||
|
var numCoeffs = this.value; // The more coefficients you use, the better the approximation
|
||||||
|
//var real = new Float32Array(numCoeffs+10);
|
||||||
|
//var imag = new Float32Array(numCoeffs+10);
|
||||||
|
|
||||||
|
//real[0] = 0.5;
|
||||||
|
//for (var i = 1; i < numCoeffs; i++) { // note i starts at 1
|
||||||
|
// imag[i] = 1 / (i * Math.PI);
|
||||||
|
//}
|
||||||
|
for (var i = 1; i <= 110; i++) {
|
||||||
|
real[i]=0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= numCoeffs; i++) { // note i starts at 1
|
||||||
|
real[2*i] = (2/Math.PI) *( 1/(2*i+1)-1/(2*i-1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
osc.frequency.value = textFreq.innerHTML;
|
||||||
|
//var imag= new Float32Array([0,0,0,0,0]); // sine
|
||||||
|
//var real = new Float32Array(imag.length); // cos
|
||||||
|
var customWave = context.createPeriodicWave(real, imag); // cos,sine
|
||||||
|
osc.setPeriodicWave(customWave);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//isPlaying = false;
|
||||||
|
// osc.stop();
|
||||||
|
//playSound(this.value);}
|
||||||
|
}}
|
||||||
|
|
||||||
|
|
||||||
|
//setup audio context
|
||||||
|
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||||
|
var context = new window.AudioContext();
|
||||||
|
|
||||||
|
//create nodes
|
||||||
|
var osc; //create in event listener so we can press the button more than once
|
||||||
|
var masterGain = context.createGain();
|
||||||
|
var analyser = context.createAnalyser();
|
||||||
|
|
||||||
|
//routing
|
||||||
|
masterGain.connect(analyser);
|
||||||
|
analyser.connect(context.destination);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//draw function for canvas
|
||||||
|
function drawWave(analyser, ctx) {
|
||||||
|
|
||||||
|
var buffer = new Float32Array(1024),
|
||||||
|
w = ctx.canvas.width;
|
||||||
|
|
||||||
|
ctx.strokeStyle = "#D44"; //reddish color
|
||||||
|
ctx.setTransform(1,0,0,-1,0,100.5); // flip y-axis and translate to center
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctxspec.strokeStyle = "#44D" //blueish color
|
||||||
|
ctxspec.setTransform(1,0,0,1,0,100.5);
|
||||||
|
ctxspec.lineWidth = 2;
|
||||||
|
var wspec=ctxspec.canvas.width;
|
||||||
|
(function loop() {
|
||||||
|
analyser.getFloatTimeDomainData(buffer);
|
||||||
|
var prevValue=999;
|
||||||
|
var currentValue=999;
|
||||||
|
for (var i=10; i<1024; i++){
|
||||||
|
currentValue=buffer[i];
|
||||||
|
if (currentValue>prevValue && currentValue>-0.05 && currentValue<0.05){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevValue=currentValue;
|
||||||
|
}
|
||||||
|
ctx.clearRect(0, -100, w, ctx.canvas.height);
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(0, buffer[i] * 90);
|
||||||
|
for (var x = i; x < w+i; x += 2) ctx.lineTo(x-i+2, buffer[x] * 90);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
//spectrum stuff:
|
||||||
|
//real=getReal();
|
||||||
|
//console.log(real);
|
||||||
|
ctxspec.clearRect(0, -100, wspec, ctxspec.canvas.height);
|
||||||
|
ctxspec.beginPath();
|
||||||
|
ctxspec.moveTo(0, 80);
|
||||||
|
for (var j=0; j<100; j++){
|
||||||
|
ctxspec.lineTo(j*10,real[j]*400+80);
|
||||||
|
}
|
||||||
|
ctxspec.stroke();
|
||||||
|
if (isPlaying) requestAnimationFrame(loop)
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
//button trigger
|
||||||
|
$(function() {
|
||||||
|
var c = document.getElementById('scope'),
|
||||||
|
ctx = c.getContext("2d");
|
||||||
|
|
||||||
|
c.height = 200;
|
||||||
|
c.width = 600;
|
||||||
|
|
||||||
|
// make 0-line permanent as background
|
||||||
|
ctx.moveTo(0, 100.5);
|
||||||
|
ctx.lineTo(c.width, 100.5);
|
||||||
|
ctx.stroke();
|
||||||
|
c.style.backgroundImage = "url(" + c.toDataURL() + ")";
|
||||||
|
|
||||||
|
$('button').on('mousedown', function() {
|
||||||
|
|
||||||
|
if (playing.innerHTML==="Pause sound"){
|
||||||
|
playing.innerHTML="Play the sound";
|
||||||
|
isPlaying = false;
|
||||||
|
osc.stop();
|
||||||
|
}else{
|
||||||
|
playing.innerHTML="Pause sound";
|
||||||
|
playSound(textHarmonics.innerHTML);
|
||||||
|
}});
|
||||||
|
});
|
||||||
|
|
||||||
|
function playSound(h){
|
||||||
|
var c = document.getElementById('scope'),
|
||||||
|
ctx = c.getContext("2d");
|
||||||
|
osc = context.createOscillator();
|
||||||
|
//osc settings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var numCoeffs = h; // The more coefficients you use, the better the approximation
|
||||||
|
|
||||||
|
|
||||||
|
//real[0] = 0.5;
|
||||||
|
//for (var i = 1; i < numCoeffs; i++) { // note i starts at 1
|
||||||
|
// imag[i] = 1 / (i * Math.PI);
|
||||||
|
//}
|
||||||
|
for (var i = 1; i <= 110; i++) {
|
||||||
|
real[i]=0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= numCoeffs; i++) { // note i starts at 1
|
||||||
|
real[2*i] = (2/Math.PI) *( 1/(2*i+1)-1/(2*i-1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//var imag= new Float32Array([0,0,0,0,0]); // sine
|
||||||
|
//var real = new Float32Array(imag.length); // cos
|
||||||
|
var customWave = context.createPeriodicWave(real, imag); // cos,sine
|
||||||
|
osc.setPeriodicWave(customWave);
|
||||||
|
osc.frequency.value = textFreq.innerHTML;
|
||||||
|
osc.connect(masterGain);
|
||||||
|
osc.start();
|
||||||
|
isPlaying = true;
|
||||||
|
|
||||||
|
drawWave(analyser, ctx);
|
||||||
|
}
|
Loading…
Reference in New Issue