Resonant

Frequencies

\f\sub{0} = \reg{}{f0} [Hz] \f\sub{1} = \reg{}{f1} [Hz]

Massm\sub{1} [ kg ]

Springs\sub{1} [ \ratio{N}{m} ]

Anti-Resonant

Frequency

\f\sub{-1} = \tall{(}{130} \frac{s\sub{2}}{m\sub{2}} \tall{)}{130}\sup{1/2} = \reg{}{f_1} [Hz]

Massm\sub{2} [ kg ]

Springs\sub{2} [ \ratio{N}{m} ]

Displacement

Amplitudes

\delta\sub{A\sub{1}} = \reg{}{m1-amp} [m] \delta\sub{A\sub{2}} = \reg{}{m2-amp} [m]

Driving Force

F(t) = F\sub{A} cos\tall{(}{130} \omega t \tall{)}{130} F\sub{A} = \reg{}{force-amplitude} [N]
let init = false const spaceWidth = this.width/4 const p1 = this.newPlot({ position: [ this.left+100, this.bottom+20 ], size: [spaceWidth, this.height-40], rangeX: [-3,3], rangeY: [-5,10], labelX: "", labelY: "Position x [m]", gridX: false, tickEndsX: false, tickArrayX: [-10], tickLabelFontSizeY: 30, tickLabelGapY: 10, tickStepY: 1, labelFontSizeY: 40, labelGapY: 15, }) const p2 = this.newPlot({ position: [ this.left + 100 + spaceWidth + 150, this.bottom+100], size: [this.width - spaceWidth - 100 - 150 - 20 ,this.height-100-40-40 ], rangeX: [0,2], rangeY: [-5,5], labelX: "Driving Frequency \\f [Hz]", labelY: "Amplitude \\delta\\sub{A} [m]", tickStepX: 0.5, tickStepY: 1, labelFontSizeX: 40, labelFontSizeY: 40, }) const [p2x,p2y] = p2.position const [p2w,p2h] = p2.size p2.text({ text:"Displacement \\delta(t) = \\delta\\sub{A} cos(2\\pi\\f t)", position:[p2x+p2w/2,p2y+p2h+20], anchor:[0.5,0], screen: true, clip: false, fontSize: 40, }) let ampM1, dispM1, ampM2, dispM2, fLength, f0, f1 const posM1 = 0 const posS1 = -5 const posM2 = 5 const heightM = 1 const posS2 = posM1 + heightM const ampF = 50 reg.forceAmplitude.textContent = ampF reg.osc.onUpdate(t=>{ updatePosition() m1g.update() s1g.update() m2g.update() s2g.update() force.update() }) reg.freq.onUpdate(()=>updateAll()) reg.m1.onUpdate(()=>updateAll()) reg.s1.onUpdate(()=>updateAll()) reg.m2.onUpdate(()=>updateAll()) reg.s2.onUpdate(()=>updateAll()) reg.showForce.onUpdate(v=>{ force.classList.toggle("hidden",!v) reg.showForce.button.style.background = !v?"":color.highlight reg.showForce.button.style.color = !v?"white":"black" }) function updateAll(){ updateResponse() updatePosition() updateGroups() } function updateGroups(){ m1g.update() s1g.update() m2g.update() s2g.update() force.update() frf.update() driveMark.update() } function updateResponse(){ const m1 = reg.m1.value const s1 = reg.s1.value const m2 = reg.m2.value const s2 = reg.s2.value const f = reg.freq.value const fT = frequency(m1,s1,m2,s2) f0 = fT.res[0]/pi2 f1 = fT.res[1]/pi2 f_1 = fT.anti[0]/pi2 reg.f0.textContent = format(f0,2) reg.f1.textContent = format(f1,2) reg.f_1.textContent = format(f_1,2) const [A1,A2] = amplitude(f,m1,s1,m2,s2) ampM1 = A1 ampM2 = A2 reg.m1Amp.textContent = format(ampM1,2) reg.m2Amp.textContent = format(ampM2,2) if(init) s1Spr.style.strokeWidth = 1 + 4*reg.s1.ratio if(init) s2Spr.style.strokeWidth = 1 + 4*reg.s2.ratio } function updatePosition(){ const T = pi2*reg.freq.value*reg.osc.value fLength = cos(T) dispM1 = ampM1*cos(T) dispM2 = ampM2*cos(T) } updateResponse() updatePosition() function frequency(m1, s1, m2, s2){ const A = (s1 + s2)*m2 + m1*s2 const B = sqrt(A**2 - 4*m1*m2*s1*s2) const C = 2*m1*m2 const res = [sqrt((A - B) / C), sqrt((A + B) / C)] const anti = [sqrt(s2/m2)] return {res,anti} } function amplitude(f,m1,s1,m2,s2){ const w = pi2*f const den = ( s1 + s2 - m1*w**2 )*( m2*w**2 - s2 ) + s2**2 const A1 = ( ampF *( m2*w**2 - s2 )) / den const A2 = -ampF * s2 / den return [A1,A2] } const m1g = p1.group("m1") p1.line({ x:()=>[0,2.15], y:()=>[posM1 + dispM1,posM1 + dispM1], group: m1g, strokeLinecap: "square", strokeWidth: 2, }) p1.rect({ position: ()=>[0,posM1 + dispM1], size: ()=>[2.1 + 2*reg.m1.ratio,heightM], corner: 10, group: m1g, }) p1.text({ position: ()=>[0,posM1 + dispM1], text: "m\\sub{1}", group: m1g, color: color.textInv }) const m2g = p1.group("m1") p1.line({ x:()=>[0,2.15], y:()=>[posM2 + dispM2,posM2 + dispM2], group: m2g, stroke: color.second, strokeLinecap: "square", strokeWidth: 2, }) p1.rect({ position: ()=>[0,posM2 + dispM2], size: ()=>[2.1 + 2*reg.m2.ratio,heightM], corner: 10, fill: color.second, group: m2g, }) p1.text({ position: ()=>[0,posM2 + dispM2], text: "m\\sub{2}", group: m2g, color: color.textInv }) const s1g = p1.group("s1") const s1Spr = p1.spring({ start:()=>[0,posS1], end:()=>[0,posM1 - heightM/2 + dispM1], coils:6, diameter:1.5, group:s1g, stroke:color.neutral }) p1.rect({ position: ()=>[-2,(posS1 + posM1 + dispM1)/2], size: ()=>[p1.fromXsize(50),p1.fromYsize(50)], anchor: [0,0.5], corner: 10, group: s1g, opacity:0.25, stroke:color.neutral, }) p1.text({ position: ()=>[-2 + p1.fromXsize(50)/2,(-5 + posM1 + dispM1)/2], text: "s\\sub{1}", group: s1g, }) const s2g = p1.group("s2") const s2Spr = p1.spring({ start:()=>[0,posM1 + heightM/2 + dispM1], end:()=>[0,posM2 + dispM2 - heightM/2], coils:6, diameter:1.5, group:s2g, stroke:color.neutral }) p1.rect({ position: ()=>[-2,((posM1 + heightM/2 + dispM1) + (posM2 + dispM2 - heightM/2))/2], size: ()=>[p1.fromXsize(50),p1.fromYsize(50)], anchor: [0,0.5], corner: 10, group: s2g, opacity:0.25, stroke:color.neutral, }) p1.text({ position: ()=>[-2 + p1.fromXsize(50)/2,((posM1 + heightM/2 + dispM1) + (posM2 + dispM2 - heightM/2))/2], text: "s\\sub{2}", group: s2g, }) const frf = p2.group("frf") const err = 0.001 p2.plotFn({ y: f => { const [A1,A2] = amplitude(f,reg.m1.value,reg.s1.value,reg.m2.value,reg.s2.value) return A2 }, max: ()=>f0-err, threshold:[-5,5], group: frf, stroke: color.second }) p2.plotFn({ y: f => { const [A1,A2] = amplitude(f,reg.m1.value,reg.s1.value,reg.m2.value,reg.s2.value) return A2 }, min: ()=>f0+err, max: ()=>f1-err, threshold:[-5,5], group: frf, stroke: color.second }) p2.plotFn({ y: f => { const [A1,A2] = amplitude(f,reg.m1.value,reg.s1.value,reg.m2.value,reg.s2.value) return A2 }, min: ()=>f1+err, threshold:[-5,5], group: frf, stroke: color.second }) p2.plotFn({ y: f => { const [A1,A2] = amplitude(f,reg.m1.value,reg.s1.value,reg.m2.value,reg.s2.value) return A1 }, max: ()=>f0-err, threshold:[-5,5], group: frf, }) p2.plotFn({ y: f => { const [A1,A2] = amplitude(f,reg.m1.value,reg.s1.value,reg.m2.value,reg.s2.value) return A1 }, min: ()=>f0+err, max: ()=>f1-err, threshold:[-5,5], group: frf, }) p2.plotFn({ y: f => { const [A1,A2] = amplitude(f,reg.m1.value,reg.s1.value,reg.m2.value,reg.s2.value) return A1 }, min: ()=>f1+err, threshold:[-5,5], group: frf, }) p2.line({ x: ()=>[f0,f0], y: ()=>[p2.y.min,p2.y.max], group: frf, strokeWidth: 2, clip: false, dash: "20 5" }) p2.text({ clip: false, text: "\\f\\sub{0}", color: color.main, group: frf, position: ()=>[f0,4.5], opaque: true, }) p2.line({ x: ()=>[f1,f1], y: ()=>[p2.y.min,p2.y.max], group: frf, strokeWidth: 2, clip: false, dash: "20 5" }) p2.text({ clip: false, text: "\\f\\sub{1}", color: color.main, group: frf, position: ()=>[f1,4.5], opaque: true, }) p2.line({ x: ()=>[f_1,f_1], y: ()=>[p2.y.min,p2.y.max], group: frf, strokeWidth: 2, clip: false, dash: "20 5", stroke: color.third }) p2.text({ clip: false, text: "\\f\\sub{-1}", color: color.third, group: frf, position: ()=>[f_1,4.5], opaque: true, }) const force = p1.group("force") reg.showForce.value = true p1.arrow({ start:()=>[2.1,posM1 + dispM1], end:()=>[2.1,posM1 + dispM1 + fLength], size:()=>[0.2,0.3], fill:color.highlight, stroke:color.highlight, strokeWidth:5, group: force, }) const driveMark = p2.group("mark") p2.line({ x: ()=>[reg.freq.value,reg.freq.value], y: ()=>[p2.y.min,p2.y.max], stroke: color.highlight, group: driveMark, strokeWidth: 2, clip: false, }) p2.circle({ position: ()=>[reg.freq.value,ampM1], radius: 6, fill: color.highlight, group: driveMark, }) p2.circle({ position: ()=>[reg.freq.value,ampM2], radius: 4, fill: color.highlight, group: driveMark, }) init = true