Natural Frequency

\f\sub{0} = \frac{1}{2\pi} \tall{(}{170} \frac{s}{m} \tall{)}{170}\sup{1/2} \f\sub{0} = \reg{}{natFreq} Hz

Mass 1m [ kg ]

Spring 1s [ \ratio{N}{m} ]

Driving Force

F(t) = F\sub{A} cos\tall{(}{130} \omega t \tall{)}{130} F\sub{A} = \reg{}{force-amplitude} N

Displacement

\delta(t) = \delta\sub{A} cos\tall{(}{130} \omega t \tall{)}{130}

Amplitude

\delta\sub{A} = \frac{ F\sub{A} / m }{ \omega\sub{0}\sup{2} - \omega\sup{2} } \delta\sub{A} = \reg{}{m1-amp} [m]
color.add("mass","var(--theme-bright-light-2)","var(--theme-dull-dark-4)") color.add("mass-text","black","white") color.add("spring","var(--theme-bright-light-4)","var(--theme-dull-dark-3)") color.add("spring-text","white","black") color.add("force","orange") color.add("mark","orange") const spaceWidth = this.width/4 - 100 const p1 = this.newPlot({ position: [ this.left+100, this.bottom+20 ], size: [spaceWidth, this.height-40], rangeX: [-1.1,1.5], rangeY: [-5,5], labelX: "", labelY: "Position x [m]", gridX: false, tickArrayX: [], tickEndsX: false, tickArrayX: [-10], tickLabelFontSizeY: 30, tickLabelGapY: 10, 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 ], rangeX: [0,2], rangeY: [-5,5], labelX: "Driving Frequency \\f [Hz]", labelY: "Displacement Amplitude \\delta\\sub{A} [m]", tickStepX: 0.5, labelFontSizeY: 40, labelFontSizeX: 40, }) let ampM1, dispM1, fLength, natFreq const posM1 = 0 const posS1 = -5 const heightM = 1 const ampF = 50 reg.osc.onUpdate(t=>{ updatePosition() m1.update() s1.update() force.update() }) reg.freq.onUpdate(f=>{ updateResponse() updatePosition() force.update() frf.update() driveMark.update() m1.update() s1.update() }) reg.m1.onUpdate(v=>{ updateResponse() m1.update() frf.update() driveMark.update() }) reg.s1.onUpdate((v,p,el)=>{ updateResponse() s1.update() frf.update() driveMark.update() s1Spr.style.strokeWidth = 1 + 6*el.ratio }) reg.showForce.onUpdate(v=>{ force.classList.toggle("hidden",!v) reg.showForce.button.style.background = !v?"":color.force }) function updateResponse(){ reg.forceAmplitude.textContent = ampF natFreq = sqrt(reg.s1.value/reg.m1.value) / pi2 reg.natFreq.textContent = format(natFreq,2) ampM1 = amplitude(reg.freq.value) reg.m1Amp.textContent = format(ampM1,2) } updateResponse() function updatePosition(){ const T = pi2*reg.freq.value*reg.osc.value fLength = cos(T) dispM1 = ampM1*cos(T) } updatePosition() function amplitude(f){ return ( ampF / reg.m1.value ) / ( (natFreq*pi2)**2 - (f*pi2)**2 ) } const m1 = p1.group("m1") const m1Rect = p1.rect({ position: ()=>[0,posM1 + dispM1], size: ()=>[0.1 + 2*reg.m1.value/reg.m1.max,heightM], fill: color.mass, corner: 10, group: m1, }) p1.text({ position: ()=>[0,posM1 + dispM1], text: "m", group: m1, color: color.massText }) const s1 = p1.group("s1") const s1Spr = p1.spring({ start:()=>[0,posS1], end:()=>[0,posM1 - heightM/2 + dispM1], coils:6, diameter:1, group:s1, stroke:color.spring, strokeWidth:1 + 6*reg.s1.ratio, }) p1.rect({ position: ()=>[-0.8,(posS1 + posM1 + dispM1)/2], size: ()=>[p1.fromXsize(50),p1.fromYsize(50)], fill: "red", corner: 10, group: s1, fill: color.mass, opacity:0.25 }) p1.text({ position: ()=>[-0.8,(-5 + posM1 + dispM1)/2], text: "s", group: s1, color: color.springText }) const force = p1.arrow({ start:()=>[1,posM1 + heightM/2 + dispM1], end:()=>[1,posM1 + heightM/2 + dispM1 + fLength], size:()=>1/2, fill:color.force, stroke:color.force, strokeWidth:5 }) reg.showForce.value = true const frf = p2.group("frf") p2.plotFn({ y: f => { const A = amplitude(f) return A >= 0 ? A : 20e3 }, group: frf, }) p2.plotFn({ y: f => { const A = amplitude(f) return A <= 0 ? A : -20e3 }, group: frf, }) const driveMark = p2.group("mark") p2.line({ x: ()=>[reg.freq.value,reg.freq.value], y: ()=>[p2.y.min,p2.y.max], stroke: color.mark, group: driveMark, strokeWidth: 1, }) const test = p2.circle({ position: ()=>[reg.freq.value,ampM1], radius: 6, fill: color.mark, stroke: color.mark, group: driveMark, })