This is the beginning of exploring how to calculate and display the combinations of multiple waves. This requires finding the least common multiple of the frequencies, which can get pretty heavy to process.
Adjust the sliders to change frequency combinations. But watch out with some of the more complicated waves, sometimes the least common multiple can get above 1 million! (e.g. 79, 80, 81)
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: black;
color: rgb(200, 200, 200);
margin: 0px;
}
canvas {
margin-top: 10px;
}
table {
margin-left: 10px;
}
</style>
<script src="//d3js.org/d3.v4.min.js"></script>
</head>
<body>
<canvas></canvas>
<table>
<tr>
<td>freq. #1: <text id="f1"></text></td>
<td>freq. #2: <text id="f2"></text></td>
<td>freq. #3: <text id="f3"></text></td>
<td>Compound wavelength</td>
</tr>
<tr>
<td><input type="range" min="1" max="100" value="12" oninput="draw()"></td>
<td><input type="range" min="1" max="100" value="50" oninput="draw()"></td>
<td><input type="range" min="1" max="100" value="2" oninput="draw()"></td>
<th id="LCM"></th>
</tr>
</table>
</body>
<script>
const width = innerWidth,
height = innerHeight - 60;
const canvas = d3.select("canvas")
.attr("width", width)
.attr("height", height);
const canvasCtx = canvas.node().getContext("2d");
const x = d3.scaleLinear().range([0, width]);
const wave = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d, i) {return x(i)})
.y(function(d) {return d * height})
.context(canvasCtx);
draw();
function draw() {
canvasCtx.clearRect(0, 0, width, height);
canvasCtx.fillStyle = 'rgb(0, 0, 0)';
canvasCtx.fillRect(0, 0, width, height);
const fVals = d3.selectAll("input").nodes().map(function(d) {return +d.value});
const commonLength = LCM(LCM(fVals[0], fVals[1]), fVals[2]) * 2 + 1;
x.domain([0, commonLength]);
const wavesArray = fVals.map(function(d) { return []})
const compoundWave = [];
for (let i=0; i<commonLength; i++) {
let combinedVal = 0;
for (let n=0; n<wavesArray.length; n++) {
const d = fVals[n]
const thisVal = d3.easeSinInOut((i % (d*2) - d) / d);
combinedVal += thisVal
wavesArray[n].push(thisVal)
}
compoundWave.push(combinedVal/3)
}
wavesArray.map(function(d) {drawWave(d, 'rgb(200, 200, 200)', d.length > 1000 ? .1 : .4)})
drawWave(compoundWave, 'rgb(255, 0, 0)')
d3.select("#f1").html(fVals[0])
d3.select("#f2").html(fVals[1])
d3.select("#f3").html(fVals[2])
d3.select("#LCM").html(commonLength)
}
function drawWave(array, color, lineWidth = 1) {
canvasCtx.beginPath();
canvasCtx.lineWidth = lineWidth;
canvasCtx.strokeStyle = color;
canvasCtx.moveTo(0, 0);
wave(array)
canvasCtx.stroke();
}
function LCM(a, b) {
return (a/gcd(a, b)*b)
}
function gcd(a,b) {
while (true) {
if (b == 0) return a;
a %= b;
if (a == 0) return b;
b %= a;
}
}
</script>
</html>