Resonant

Frequencies

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

Massm\sub{1} [ kg ]

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

Damperr\sub{1} [ \ratio{kg}{s} ]

\beta\sub{1} = \reg{}{B1} [1/s]

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} ]

Damperr\sub{2} [ \ratio{kg}{s} ]

\beta\sub{2} = \reg{}{B2} [1/s]

Displacement

Amplitudes

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

Displacement

Phases

\Phi\sub{1} = \reg{}{m1-phase} \pi [rad] \Phi\sub{2} = \reg{}{m2-phase} \pi [rad]

Plot phase relative to

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.center-50], size: [this.width - spaceWidth - 100 - 150 - 20 ,this.height/2 - 40 ], rangeX: [0,2], rangeY: [0,5], labelX: "", 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 - \\Phi)", position:[p2x+p2w/2,p2y+p2h+20], anchor:[0.5,0], screen: true, clip: false, fontSize: 40, }) const p3 = this.newPlot({ position: [p2x,this.bottom+100], size: [p2w,p2h - 170], rangeX: [0,2], rangeY: [0,pi2*1.00001], labelX: "Driving Frequency \\f [Hz]", labelY: "Phase \\reg{\\Phi}{phaseTypeLab} [rad]", tickStepX: 0.5, tickArrayY: [0,{value:pi,label:"\\pi"},{value:pi/2,label:"\\frac{\\pi}{2}"},{value:3*pi/2,label:"3\\frac{\\pi}{2}"},{value:pi2,label:"2\\pi"}], labelFontSizeX: 40, labelFontSizeY: 40, }) let ampM1, phaseM1, dispM1, ampM2, phaseM2, dispM2, fLength, f0, f1, dampRatio1, dampRatio2 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() r1g.update() m2g.update() s2g.update() r2g.update() force.update() }) reg.freq.onUpdate(()=>updateAll()) reg.m1.onUpdate(()=>updateAll()) reg.s1.onUpdate(()=>updateAll()) reg.r1.onUpdate(()=>updateAll()) reg.m2.onUpdate(()=>updateAll()) reg.s2.onUpdate(()=>updateAll()) reg.r2.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" }) reg.phaseType.onUpdate(v=>{ reg.phaseType.button.style.background = v?"":color.highlight reg.phaseType.button.style.color = v?"white":"black" frfPh1.classList.toggle("hidden",v) frfPh2.classList.toggle("hidden",v) frfPhDiff.classList.toggle("hidden",!v) reg.phaseTypeLab.update(!v?"\\Phi":"\\Phi\\sub{2} - \\Phi\\sub{1}") updateGroups() }) function updateAll(){ updateResponse() updatePosition() updateGroups() } function updateGroups(){ m1g.update() s1g.update() r1g.update() m2g.update() s2g.update() r2g.update() force.update() frf.update() frfPh.update() freqMarks.update() } function updateResponse(){ const m1 = reg.m1.value const s1 = reg.s1.value const r1 = reg.r1.value const m2 = reg.m2.value const s2 = reg.s2.value const r2 = reg.r2.value const f = reg.freq.value const fT = frequency(m1,s1,r1,m2,s2,r2) 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) reg.B1.textContent = format(r1/2/m1,2) reg.B2.textContent = format(r1/2/m1,2) const [A1,A2,ph1,ph2] = ampPhase(f,m1,s1,r1,m2,s2,r2) ampM1 = A1 ampM2 = A2 reg.m1Amp.textContent = format(ampM1,2) reg.m2Amp.textContent = format(ampM2,2) phaseM1 = ph1 phaseM2 = ph2 reg.m1Phase.textContent = format(phaseM1/pi,2) reg.m2Phase.textContent = format(phaseM2/pi,2) if(init){ s1Spr.style.strokeWidth = 1 + 4*reg.s1.ratio 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 - phaseM1) dispM2 = ampM2*cos(T - phaseM2) } updateResponse() updatePosition() function frequency(m1, s1, r1, m2, s2, r2){ 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 ampPhase(f, m1, s1, r1, m2, s2, r2){ const w = pi2*f const w1 = sqrt(s1/m1) const w2 = sqrt(s2/m2) const B1 = r1/(2*m1) const B2 = r2/(2*m2) const a = w**4 - ( w1**2 + w2**2*( 1 + m2/m1 ) + 4*B1*B2 )*w**2 + w1**2 * w2**2 const b = ( B1*w1*w2**2 + B2*w1**2 )*w - ( B1 + B2*( 1 + m2/m1 ) )*w**3 const A1 = (ampF / s1) * w1**2 * hypot(w2**2 - w**2, 2*B2*w) / hypot(a, 2*b) const A2 = (ampF / s2) * w1**2 * hypot(w2**2, 2*B2*w) / hypot(a, 2*b) const phD = atan(2*b, a) const ph1 = phD - atan(2*B2*w, w2**2 - w**2) const ph2 = phD - atan(2*B2*w, w2**2) return [A1, A2, wrap2pi(ph1), wrap2pi(ph2)] } 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("m2") 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:()=>[-1,posS1], end:()=>[-1,posM1 - heightM/2 + dispM1], coils:6, diameter:1.5, group:s1g, stroke:color.neutral }) p1.rect({ position: ()=>[-2.75,(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.75 + p1.fromXsize(50)/2,(-5 + posM1 + dispM1)/2], text: "s\\sub{1}", group: s1g, }) const s2g = p1.group("s2") const s2Spr = p1.spring({ start:()=>[-1,posM1 + heightM/2 + dispM1], end:()=>[-1,posM2 + dispM2 - heightM/2], coils:6, diameter:1.5, group:s2g, stroke:color.neutral }) p1.rect({ position: ()=>[-2.75,((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.75 + p1.fromXsize(50)/2,((posM1 + heightM/2 + dispM1) + (posM2 + dispM2 - heightM/2))/2], text: "s\\sub{2}", group: s2g, }) const r1g = p1.group("r1") p1.damper({ start:()=>[1,posS1], end:()=>[1,posM1 - heightM/2 + dispM1], gap:()=>(1-reg.r1.ratio**0.5), atRatio:()=>0.5, diameter:1, group:r1g, stroke:color.neutral }) p1.rect({ position: ()=>[2,(posS1 + posM1)*(4/5)], size: ()=>[p1.fromXsize(50),p1.fromYsize(50)], anchor: [0,0.5], corner: 10, group: r1g, opacity:0.25, stroke:color.neutral, }) p1.text({ position: ()=>[2 + p1.fromXsize(50)/2,(posS1 + posM1)*(4/5)], text: "r\\sub{1}", group: r1g, }) const r2g = p1.group("r2") p1.damper({ start:()=>[1,posM1 + heightM/2 + dispM1], end:()=>[1,posM2 + dispM2 - heightM/2], gap:()=>(1-reg.r1.ratio**0.5), atRatio:()=>0.5, diameter:1, group:r2g, stroke:color.neutral }) p1.rect({ position: ()=>[1.5,((posM1 + heightM/2 + dispM1) + (posM2 + dispM2 - heightM/2))/2], size: ()=>[p1.fromXsize(50),p1.fromYsize(50)], anchor: [0,0.5], corner: 10, group: r2g, opacity:0.25, stroke:color.neutral, }) p1.text({ position: ()=>[1.5 + p1.fromXsize(50)/2,((posM1 + heightM/2 + dispM1) + (posM2 + dispM2 - heightM/2))/2], text: "r\\sub{2}", group: r2g, }) const frf = p2.group("frf") p2.plotFn({ y: f => { const [A1,A2,ph1,ph2] = ampPhase(f,reg.m1.value,reg.s1.value,reg.r1.value,reg.m2.value,reg.s2.value,reg.r2.value) return A2 }, group: frf, stroke: color.second, }) p2.plotFn({ y: f => { const [A1,A2,ph1,ph2] = ampPhase(f,reg.m1.value,reg.s1.value,reg.r1.value,reg.m2.value,reg.s2.value,reg.r2.value) return A1 }, group: frf, }) const frfPh = p3.group("frfPh") const frfPh2 = p3.plotFn({ y: f => { const [A1,A2,ph1,ph2] = ampPhase(f,reg.m1.value,reg.s1.value,reg.r1.value,reg.m2.value,reg.s2.value,reg.r2.value) return ph2 }, group: frfPh, stroke: color.second, }) const frfPh1 = p3.plotFn({ y: f => { const [A1,A2,ph1,ph2] = ampPhase(f,reg.m1.value,reg.s1.value,reg.r1.value,reg.m2.value,reg.s2.value,reg.r2.value) return ph1 }, group: frfPh, }) const frfPhDiff = p3.plotFn({ y: f => { const [A1,A2,ph1,ph2] = ampPhase(f,reg.m1.value,reg.s1.value,reg.r1.value,reg.m2.value,reg.s2.value,reg.r2.value) return ph2 - ph1 }, group: frfPh, }) frfPhDiff.classList.add("hidden") const freqMarks = p3.group("freqMarks") p2.line({ x: ()=>[f0,f0], y: ()=>[p2.fromY(p3.toY(p3.y.min)),p2.y.max], group: freqMarks, strokeWidth: 2, clip: false, dash: "20 5" }) p2.text({ clip: false, text: "\\f\\sub{0}", color: color.main, group: freqMarks, position: ()=>[f0,4.5], opaque: true, }) p2.line({ x: ()=>[f1,f1], y: ()=>[p2.fromY(p3.toY(p3.y.min)),p2.y.max], group: freqMarks, strokeWidth: 2, clip: false, dash: "20 5" }) p2.text({ clip: false, text: "\\f\\sub{1}", color: color.main, group: freqMarks, position: ()=>[f1,4.5], opaque: true, }) p2.line({ x: ()=>[f_1,f_1], y: ()=>[p2.fromY(p3.toY(p3.y.min)),p2.y.max], group: freqMarks, strokeWidth: 2, clip: false, dash: "20 5", stroke: color.third }) p2.text({ clip: false, text: "\\f\\sub{-1}", color: color.third, group: freqMarks, 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, }) p2.line({ x: ()=>[reg.freq.value,reg.freq.value], y: ()=>[p2.fromY(p3.toY(p3.y.min)),p2.y.max], stroke: color.highlight, group: freqMarks, strokeWidth: 2, clip: false, }) p2.circle({ position: ()=>[reg.freq.value,ampM1], radius: 6, fill: color.highlight, group: freqMarks, }) p2.circle({ position: ()=>[reg.freq.value,ampM2], radius: 4, fill: color.highlight, group: freqMarks, }) p3.circle({ position: ()=>[reg.freq.value,!reg.phaseType.value?phaseM1:phaseM2-phaseM1], radius: 6, fill: color.highlight, group: freqMarks, }) p3.circle({ position: ()=>[reg.freq.value,!reg.phaseType.value?phaseM2:-1], radius: 4, fill: color.highlight, group: freqMarks, }) init = true