From dce6e971023d6c4bc849641c10db5d65ce5fad55 Mon Sep 17 00:00:00 2001 From: mattkae Date: Sun, 9 Jan 2022 20:04:51 -0500 Subject: (mkosarek) Completed simulations for all damped motion --- 2d/softbody/softbody_1.html | 18 ++++- 2d/softbody/softbody_1.html.content | 18 ++++- 2d/softbody/softbody_1/damped.cpp | 136 ++++++++++++++++++++++++++------ 2d/softbody/softbody_1/damped.h | 1 + 2d/softbody/softbody_1/dist/output.js | 3 + 2d/softbody/softbody_1/dist/output.wasm | Bin 65388 -> 69005 bytes 2d/softbody/softbody_1/main.cpp | 6 ++ 7 files changed, 148 insertions(+), 34 deletions(-) (limited to '2d') diff --git a/2d/softbody/softbody_1.html b/2d/softbody/softbody_1.html index 3f0fc40..ae4b743 100644 --- a/2d/softbody/softbody_1.html +++ b/2d/softbody/softbody_1.html @@ -86,6 +86,7 @@ document.getElementById('damped_spring_length'), document.getElementById('damped_start_position'), document.getElementById('damped_spring_constant'), + document.getElementById('damped_viscous_constant'), document.getElementById('damped_spring_mass') ]); @@ -118,6 +119,7 @@ Damped_SetDisplacement = Module.cwrap('Damped_SetDisplacement', 'void', ['number']), Damped_SetK = Module.cwrap('Damped_SetK', 'void', ['number']), Damped_SetMass = Module.cwrap('Damped_SetMass', 'void', ['number']), + Damped_SetC = Module.cwrap('Damped_SetC', 'void', ['number']), Undamped_lengthSlider = document.getElementById('undamped_spring_length'), Undamped_displacementSlider = document.getElementById('undamped_start_position'), @@ -128,6 +130,7 @@ Damped_displacementSlider = document.getElementById('damped_start_position'), Damped_kSlider = document.getElementById('damped_spring_constant'), Damped_massSlider = document.getElementById('damped_spring_mass'), + Damped_cSlider = document.getElementById('damped_viscous_constant'), undampedSetLength = function(value) { value = Number(value); @@ -171,6 +174,7 @@ Damped_displacementSlider.addEventListener('change', function(event) { Damped_SetDisplacement(Number(event.target.value)); }); Damped_kSlider.addEventListener('change', function(event) { Damped_SetK(Number(event.target.value)); }); Damped_massSlider.addEventListener('change', function(event) { Damped_SetMass(Number(event.target.value)); }); + Damped_cSlider.addEventListener('change', function(event) { Damped_SetC(Number(event.target.value)); }); }; } @@ -234,25 +238,31 @@

- + - + - + + + + + + + - + diff --git a/2d/softbody/softbody_1.html.content b/2d/softbody/softbody_1.html.content index bef14d8..c5fb3cc 100644 --- a/2d/softbody/softbody_1.html.content +++ b/2d/softbody/softbody_1.html.content @@ -33,6 +33,7 @@ document.getElementById('damped_spring_length'), document.getElementById('damped_start_position'), document.getElementById('damped_spring_constant'), + document.getElementById('damped_viscous_constant'), document.getElementById('damped_spring_mass') ]); @@ -65,6 +66,7 @@ Damped_SetDisplacement = Module.cwrap('Damped_SetDisplacement', 'void', ['number']), Damped_SetK = Module.cwrap('Damped_SetK', 'void', ['number']), Damped_SetMass = Module.cwrap('Damped_SetMass', 'void', ['number']), + Damped_SetC = Module.cwrap('Damped_SetC', 'void', ['number']), Undamped_lengthSlider = document.getElementById('undamped_spring_length'), Undamped_displacementSlider = document.getElementById('undamped_start_position'), @@ -75,6 +77,7 @@ Damped_displacementSlider = document.getElementById('damped_start_position'), Damped_kSlider = document.getElementById('damped_spring_constant'), Damped_massSlider = document.getElementById('damped_spring_mass'), + Damped_cSlider = document.getElementById('damped_viscous_constant'), undampedSetLength = function(value) { value = Number(value); @@ -118,6 +121,7 @@ Damped_displacementSlider.addEventListener('change', function(event) { Damped_SetDisplacement(Number(event.target.value)); }); Damped_kSlider.addEventListener('change', function(event) { Damped_SetK(Number(event.target.value)); }); Damped_massSlider.addEventListener('change', function(event) { Damped_SetMass(Number(event.target.value)); }); + Damped_cSlider.addEventListener('change', function(event) { Damped_SetC(Number(event.target.value)); }); }; } @@ -181,25 +185,31 @@

- + - + - + + + + + + + - + diff --git a/2d/softbody/softbody_1/damped.cpp b/2d/softbody/softbody_1/damped.cpp index 0344bd0..f56f346 100644 --- a/2d/softbody/softbody_1/damped.cpp +++ b/2d/softbody/softbody_1/damped.cpp @@ -52,13 +52,17 @@ namespace Damped { float32 gamma = 6.2; float32 discriminant = 0.f; float32 omega1 = 0.f; + float32 c1 = 0.f; + float32 c2 = 0.f; + float32 r1 = 0.f; + float32 r2 = 0.f; // Update variables float32 displacement = 0.f; float32 timeElapsed = 0.f; - void load(Renderer2d* renderer, DampedSpringWeight* inWieight, float32 length, float32 loopRadius, float32 initialDisplacement); + void load(Renderer2d* renderer, DampedSpringWeight* inWieight, float32 length, float32 loopRadius, float32 initialDisplacement, float32 inK, float32 inC); void update(float32 dtSeconds); void render(Renderer2d* renderer); void unload(); @@ -92,7 +96,7 @@ namespace Damped { renderer.load(context); weight.load(&renderer, initVariables.mass, Vector4 { 55.f, 235.f, 35.f, 255.f }, Vector4 { 235.f, 5.f, 235.f, 255.f }); - spring.load(&renderer, &weight, initVariables.springLength, 16.f, initVariables.initialDisplacement); + spring.load(&renderer, &weight, initVariables.springLength, 16.f, initVariables.initialDisplacement, initVariables.k, initVariables.c); mainLoop.run(update); } @@ -164,30 +168,105 @@ namespace Damped { const float32 epsilon = 0.0001f; - void DampedSpring::load(Renderer2d* renderer, DampedSpringWeight* inWeight, float32 length, float32 loopRadius, float32 initialDisplacement) { - initialDisplacement = initialDisplacement; + void DampedSpring::load(Renderer2d* renderer, DampedSpringWeight* inWeight, float32 length, float32 loopRadius, float32 inInitialDisplacement, float32 inK, float32 inC) { + initialDisplacement = inInitialDisplacement; weight = inWeight; - discriminant = c * c - (4 * weight->mass * k); + k = inK; + c = inC; - if (discriminant < epsilon && discriminant > -epsilon) { // Real repeated root (~ zero): Overdamped motion - printf("Overdamped motion.\n"); - type = DampedSpringType::Overdamped; - } - else if (discriminant > 0) { // Two real roots (greater than zero): Critically damped motion + // Set the quadratic terms to something that we're familiar with. + float32 A = weight->mass; + float32 B = c; + float32 C = k; + + + discriminant = B * B - (4 * A * C); + timeElapsed = 0; + displacement = 0; + + if (discriminant < epsilon && discriminant > -epsilon) { + // Real repeated root (~ zero): Critically damped motion printf("Critically damped motion.\n"); - type = DampedSpringType::Critical; + + type = DampedSpringType::Critical; + + r1 = -B / (2 * A); + r2 = r1; + + // Solve for the initial displacement. + c2 = (initialDisplacement - r1) / (r2); + c2 = r2 * c2; + c1 = r1; + printf("Equation: %f e^(%f t) + %f t e^(%f t)\n", c1, r1, c2, r2); } - else { // Complex pair (less than zero): Underdamped motion + else if (discriminant > 0) { + // Two real roots (greater than zero): Overdamped motion + printf("Overdamped motion.\n"); + + type = DampedSpringType::Overdamped; + + // Discover the two treal roots. Both of these WILL be negative. + float32 sqrtDis = sqrtf(discriminant); + r1 = (-B + sqrtDis) / (2 * A); + r2 = (-B - sqrtDis) / (2 * A); + + // Now, solve for c1 and c2 given the initial displacement. The equation is: + // x(0) = r1 * c1 * e^(r1 * t) + r2 * c2 * e^(r2 * t) -> + // x(0) = r1 * c1 + r2 * c2 -> + // initialDisplacement = r1 * c1 + r2 * c2; -> if abs(r1) > abs(r2) => c1 = 1, else c2 = 1 + if (r1 < r2) { + c2 = (initialDisplacement - r1) / (r2); + c2 = r2 * c2; + c1 = r1; + } + else { + c1 = (initialDisplacement - r2) / (r1); + c1 = r1 * c1; + c2 = r2; + } + + printf("Equation: %f e^(%f t) + %f e^(%f t)\n", c1, r1, c2, r2); + } + else { + // Complex pair (less than zero): Underdamped motion printf("Underdamped motion.\n"); type = DampedSpringType::Underdamped; - omega1 = sqrtf(-discriminant) / (2.f * weight->mass); // Note that we negate the discriminant to get the REAL positive part. + float32 sqrtDis = sqrtf(-discriminant); + omega1 = sqrtf(sqrtDis) / (2.f * A); // Note that we negate the discriminant to get the REAL positive part. + + r1 = (-B + sqrtDis) / (2 * A); + r2 = (-B - sqrtDis) / (2 * A); + + // Now, solve for c1 and c2 given the initial displacement. The equation is: + // x(0) = r1 * c1 * e^(r1 * t) + r2 * c2 * e^(r2 * t) -> + // x(0) = r1 * c1 + r2 * c2 -> + // initialDisplacement = r1 * c1 + r2 * c2; -> if abs(r1) > abs(r2) => c1 = 1, else c2 = 1 + if (r1 < r2) { + c2 = (initialDisplacement - r1) / (r2); + c2 = r2 * c2; + c1 = r1; + } + else { + c1 = (initialDisplacement - r2) / (r1); + c1 = r1 * c1; + c2 = r2; + } + + // At this point, we have: + // x(t) = c1 cos(omega1 t) + c2 cos(omega1 t) -> + // x(t) = A cos(omega1 t - Φ) -> + // Now we need to solve for A and Φ for our initial displacement, so: + // initialDisplacement = c1 + R = sqrtf(c1 * c1 + c2 * c2); + if (initialDisplacement < 0) { + R = -R; + } + gamma = atanf(c2 / c1); + + printf("Equation: %f e^(-(%f / %f) t) * cos(%f t - %f)\n", R, c, weight->mass, omega1, gamma); } - - - timeElapsed = 0.f; - const int32 verticesPerSegment = 6; numSegments = 256; numVertices = numSegments * verticesPerSegment; @@ -226,16 +305,21 @@ namespace Damped { float32 lastDisplacement = displacement; - if (discriminant < epsilon && discriminant > -epsilon) { // Real repeated root: Overdamped motion - - } - else if (discriminant > 0) { // Two real roots: Critically damped motion - - } - else { // Complex pair (less than zero): Underdamped motion - float32 exponent = (-c / (2 * weight->mass)) * timeElapsed; + switch (type) { + case DampedSpringType::Critical: + displacement = c1 * pow(E, r1 * timeElapsed) + c2 * timeElapsed * pow(E, r2 * timeElapsed); + break; + case DampedSpringType::Overdamped: + displacement = c1 * pow(E, r1 * timeElapsed) + c2 * pow(E, r2 * timeElapsed); + break; + case DampedSpringType::Underdamped: { + float32 exponent = -(c / (2 * weight->mass)) * timeElapsed; displacement = R * pow(E, exponent) * (cosf(omega1 * timeElapsed - gamma)); - } + break; + } + default: + break; + } float32 dx = displacement - lastDisplacement; int32 vidx = 0; diff --git a/2d/softbody/softbody_1/damped.h b/2d/softbody/softbody_1/damped.h index eeb4aa9..47ae0ef 100644 --- a/2d/softbody/softbody_1/damped.h +++ b/2d/softbody/softbody_1/damped.h @@ -9,6 +9,7 @@ namespace Damped { float32 initialDisplacement = 10.f; float32 mass = 1.f; float32 k = 4.f; + float32 c = 1.f; }; void init(WebglContext* inContext); diff --git a/2d/softbody/softbody_1/dist/output.js b/2d/softbody/softbody_1/dist/output.js index a304400..9de60fb 100644 --- a/2d/softbody/softbody_1/dist/output.js +++ b/2d/softbody/softbody_1/dist/output.js @@ -3104,6 +3104,9 @@ var _Damped_SetK = Module["_Damped_SetK"] = createExportWrapper("Damped_SetK"); /** @type {function(...*):?} */ var _Damped_SetMass = Module["_Damped_SetMass"] = createExportWrapper("Damped_SetMass"); +/** @type {function(...*):?} */ +var _Damped_SetC = Module["_Damped_SetC"] = createExportWrapper("Damped_SetC"); + /** @type {function(...*):?} */ var _main = Module["_main"] = createExportWrapper("main"); diff --git a/2d/softbody/softbody_1/dist/output.wasm b/2d/softbody/softbody_1/dist/output.wasm index 19696f3..4c82a10 100755 Binary files a/2d/softbody/softbody_1/dist/output.wasm and b/2d/softbody/softbody_1/dist/output.wasm differ diff --git a/2d/softbody/softbody_1/main.cpp b/2d/softbody/softbody_1/main.cpp index 66792d3..355ba1c 100644 --- a/2d/softbody/softbody_1/main.cpp +++ b/2d/softbody/softbody_1/main.cpp @@ -65,4 +65,10 @@ extern "C" { initVariables.mass = mass; Damped::setInitVariables(initVariables); } + + EMSCRIPTEN_KEEPALIVE void Damped_SetC(float c) { + Damped::DampedInitVariables initVariables = Damped::getInitVariables(); + initVariables.c = c; + Damped::setInitVariables(initVariables); + } } -- cgit v1.2.1