1

I'm having trouble with a javascript app I am currently working on. It's a boat design thing used to calculate hydrostatics data of yacht hulls. The trouble I'm having is that I have two functions that are interrelated and both need to arrive at a specific result.

To clarify, the user inputs a design displacement and the hull is moved up or down until the immersed volume equals the design displacement.

The user also inputs a longitudinal position for the center of gravity, and the hull is pitched until the longitudinal position of the center of buoyancy (centroid of the immersed volume) aligns with the center of gravity.

However, pitching the hull will change the displacement, and moving the hull up or down will change the position of the center of buoyancy.

What I currently do (pseudocode)

function raiseAndPitch
  while a < maxIterations
    if boat.volume < designVolume
      move boat down
    else if boat.volume > designVolume
      move boat up
    else
      done
    a++
  while b < maxIterations
    if boat.cg.x > designCG.x
      pitch boat forward
    else if boat.cg.x < designCG.x
      pitch boat aft
    else
      done
    b++

  if boat.cg.x == designCG.x && boat.volume == designVolume
    return data
  else
    raiseAndPitch

I have a maximum number of recursions in place. However this sometimes fails to converge even with a large number of recursions for both parameters when a very small movement in one or the other creates a big change in either displacement volume or center of buoyancy position.

Not shown in the pseudocode is the way I converge on the values, please indicate if it's relevant to my question and I will add it.

Is there a better way to do this that would allow me to make sure that both parameters get to the required values at the same time ?

jfoucher
  • 2,251
  • 2
  • 21
  • 29
  • I would choose some "loss function", like (cur_volume - desired_volume)^2 + (cur_cg - desired_cg)^2, which will equal 0 for a perfect fit. (Weight either term to make it more important.) Then you can search for a 2-element delta (update) vector (difference in depth, difference in angle) that will reduce the loss function; iterate. To choose a good vector: if you have continuous functions describing the volume and CG each as functions of depth and angle, you can use derivatives, otherwise just take a few guesses at directions. Either way, make sure the delta vector has small magnitude. – j_random_hacker Dec 05 '16 at 11:58
  • Thank you @j_random_hacker. This works as well, but in some conditions it is so sensitive to extremely small change in either pitch or depth that the delta vector should be extremely small, thus increasing the number of iterations drastically. I used some kind of delta vector increment or decrement according to the speed at which it converges or diverges from the solution. I have kept my original algorithm and added yours as a fallback. If neither converge properly I take the best solution from one or the other. I think I should read about gradient descent algorithms. Could that help ? – jfoucher Dec 12 '16 at 19:09
  • That will probably help -- I'm no expert I'm afraid! But I find it concerning that a very small change in one of the parameters can lead to a large change in the outcome. The upshot would seem to be that you'll need *incredibly precise* tools to actually construct such a boat; even putting a feather on the tip of the bow could throw everything off! This makes me wonder if you're calculating the volume and CG correctly (or is such sensitivity a known difficulty in this kind of design?). – j_random_hacker Dec 12 '16 at 20:18

0 Answers0