addResponsesメソッド

応答オブジェクトをモデルに追加します。

応答を設定したモデルオブジェクトが、最適化を実行するために最適化エンジンに渡されます。

4バーモデルの場合は、次の3つの応答を追加します:
  • カプラーリンクのCMが占めるX座標が移動経路に対して持つ偏差。
  • カプラーリンクのCMが占めるY座標が移動経路に対して持つ偏差。
  • カプラーリンクのCMが占めるAZ座標が移動経路に対して持つ偏差。

RMS2応答を使用してこの偏差を計算します。

def addResponses (self):

  m = self.mbsModel
  
  # Coupler-DX curve: Spline
  x1=(0   , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 , 0.55, 0.6 , 0.65, 
      0.7 , 0.75, 0.8 , 0.85, 0.9 , 0.95, 1   , 1.05, 1.1 , 1.15, 1.2 , 1.25, 1.3 , 1.35, 
     1.4 , 1.45, 1.5 , 1.55, 1.6 , 1.65, 1.7 , 1.75, 1.8 , 1.85, 1.9 , 1.95, 2)
  y1=(199.997, 141.431, 78.0588, 17.3066, -35.233, -75.736, -102.14, -114.06, -112.56,
       -99.81, -78.718, -52.477, -23.994, 5.10437, 36.8618, 82.4831, 157.392, 231.874, 
      260.213, 244.03, 199.997, 141.429, 78.0583, 17.3061, -35.234, -75.736, -102.14,     
      -114.06, -112.56, -99.81, -78.717, -52.477, -23.994, 5.10462, 36.8621, 82.4836, 
      157.392, 231.874, 260.213, 244.03, 199.999)
  xy  = list(zip(x1,y1))

  # Coupler-DX curve: The Measured value
  dx_coupler = "DX({marker})".format(marker=m.coupler.cm.id)

  # Coupler-DX curve: The x-deviation
  self.a2x = RMS2 ( label = "Coupler-DX", targetValue = xy, measuredValue = dx_coupler)  

  #############

  # Coupler-DY curve: Spline
  x2=(0   , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 , 0.55, 0.6 , 0.65, 
      0.7 , 0.75, 0.8 , 0.85, 0.9 , 0.95, 1   , 1.05, 1.1 , 1.15, 1.2 , 1.25, 1.3 , 1.35, 
      1.4 , 1.45, 1.5 , 1.55, 1.6 , 1.65, 1.7 , 1.75, 1.8 , 1.85, 1.9 , 1.95, 2)
  y2=(400    , 398.307, 382.665, 353.359, 312.589, 263.960, 211.853, 160.818, 115.093, 
      78.2737,  53.181, 41.9427, 46.3684, 68.8531, 113.983, 187.585, 275.874, 337.05, 
      369.449, 389.534, 400.001, 398.305, 382.665, 353.359, 312.589, 263.959, 211.853, 
      160.818, 115.093, 78.2735, 53.1808, 41.9426, 46.3685, 68.8534, 113.983, 187.586, 
      275.875, 337.05, 369.449, 389.534, 400)
  xy2 = list(zip(x2,y2))

  # Coupler-DY curve: The Measured value

  dy_coupler = "DY({marker})".format(marker=m.coupler.cm.id) 

  # Coupler-DX curve: The y-deviation
  self.a2y = RMS2 ( label = "Coupler-DY", targetValue = xy2, measuredValue = dy_coupler)

  #############
  
  # Coupler-PSI curve: Spline
  x3=(0   , 0.05, 0.1 , 0.15, 0.2 , 0.25, 0.3 , 0.35, 0.4 , 0.45, 0.5 , 0.55, 0.6 , 0.65, 
      0.7 , 0.75, 0.8 , 0.85, 0.9 , 0.95, 1   , 1.05, 1.1 , 1.15, 1.2 , 1.25, 1.3 , 1.35, 
      1.4 , 1.45, 1.5 , 1.55, 1.6 , 1.65, 1.7 , 1.75, 1.8 , 1.85, 1.9 , 1.95, 2)
  y3=(0.0    , -1.5036, -0.9390,  1.2498,  4.8231,  9.6362, 15.5739, 22.5081, 30.2735, 
      38.6522, 47.3546, 55.9772, 63.8940, 69.9926, 72.0582, 65.9705, 48.8237, 28.1874, 
      13.1512,  4.3989,  0.0   , -1.5036, -0.939 ,  1.2499,  4.8231,  9.6363, 15.574, 
      22.5081, 30.2736, 38.6522, 47.3547, 55.9772, 63.8941, 69.9927, 72.0582, 65.9704, 
      48.8235, 28.1873, 13.1511,  4.3988, 0.0)
  xy3 = list(zip(x3,y3))

  # Coupler-PSI curve: Measured value
  psi_coupler = "RTOD*AZ({marker})".format(marker=m.coupler.azMarker.id) 

  # Coupler-PSI curve: Z-rotation deviation
  self.a2psi = RMS2 ( label = "Coupler-PSI", targetValue = xy3, measuredValue = psi_coupler)
  return

制約条件はmsolveでは通常応答として扱われます。したがって、モデルに制約条件を追加する場合は、addResponsesメソッドでも同様な追加操作を実行できます。最適化では、制約条件の追加は非常に重要です。実現可能なポイントから最適化を開始した場合でも、適切な制約条件がなければ実現できない設計に、最適化エンジンが到達する可能性があるからです。

msolveでは、最適化問題が正のヌル形式で定式化されます。最初に実行する作業は、すべての不等式制約条件が、それが有効なときに正の値を持つように問題を変換することです。次に、各制約条件を応答としてaddResponsesメソッドに記述します。ここでは、4バーモデルにグラスホス条件を課すことで、このプロセスを示します。グラスホス条件を課す方法は多数ありますが、ここで示している方法はmsolveとの相性がよく、この方法の実装は容易です。

4バー機構でクランク-ロッカー運動を保証するために、このモデルは次のグラスホス条件を満たす必要があります:
  • クランクは最短のリンクであること。
  • 最短と最長の長さの合計は、他の2つの長さの合計未満であること。
def addResponses (self):
# Start adding your objective function
# Adding objective function completed

# Start adding constraints
# Crank needs to be the shortest link
# This means crank is shorter than any other links
self.cons1 = ResponseExpression(
  label    = "crank < base",
  function = "(dx-ax)**2 + (dy-ay)**2 - (bx-ax)**2 - (by-ay)**2",
  mapping  = {"ax":m.ax, "ay":m.ay, "bx":m.bx, "by":m.by, "dx":m.dx, "dy":m.dy}
)
    self.cons2 = ResponseExpression(
      label    = "crank < follower",
      function = "(dx-cx)**2 + (dy-cy)**2 - (bx-ax)**2 - (by-ay)**2",
      mapping  = {"ax": m.ax, "ay": m.ay, "bx": m.bx, "by": m.by, 
                  "cx": m.cx, "cy": m.cy, "dx": m.dx, "dy": m.dy}
    )
    self.cons3 = ResponseExpression(
      label    = "crank < coupler",
      function = "(cx-bx)**2 + (cy-by)**2 - (bx-ax)**2 - (by-ay)**2",
      mapping  = {"ax": m.ax, "ay": m.ay, "bx": m.bx, "by": m.by, "cx":m.cx, "cy":m.cy}
)

# s + l < p + q
# The crank is always the shortest
# So the sum of crank and some other link is always shorter than the sum of the other two
    self.cons4 = ResponseExpression(
      label    = "crank + base < other two",
      function = "-(bx-ax)**2 - (by-ay)**2 - (dx-ax)**2 - (dy-ay)**2 + (cx-dx)**2 + (cy-dy)**2 + (bx-cx)**2 + (by-cy)**2",
      mapping  = {"ax": m.ax, "ay": m.ay, "bx": m.bx, "by": m.by, 
                  "cx": m.cx, "cy": m.cy, "dx": m.dx, "dy": m.dy}
)
    self.cons5 = ResponseExpression(
      label    = "crank + coupler < other two",
      function = "-(bx-ax)**2 - (by-ay)**2 - (cx-bx)**2 - (cy-by)**2 + (dx-cx)**2 + (dy-cy)**2 + (dx-ax)**2 + (dy-ay)**2",
      mapping  = {"ax": m.ax, "ay": m.ay, "bx": m.bx, "by": m.by,
                  "cx": m.cx, "cy": m.cy, "dx": m.dx, "dy": m.dy}
)
    self.cons6 = ResponseExpression(
      label    = "crank + follower < other two",
      function = "-(bx-ax)**2 - (by-ay)**2 - (dx-cx)**2 - (dy-cy)**2 + (cx-bx)**2 + (cy-by)**2 + (dx-ax)**2 + (dy-ay)**2",
      mapping  = {"ax": m.ax, "ay": m.ay, "bx": m.bx, "by": m.by, 
                  "cx": m.cx, "cy": m.cy, "dx": m.dx, "dy": m.dy}
    )