简单的不平等约束破坏QP问题(控制分配)

发布于 2025-02-13 11:06:03 字数 3111 浏览 1 评论 0原文

优化问题仅用于上下文,而不是严格需要的。使用Scipy的“最小化”代码是将最佳控制力分配给在船上的环境力量上的船上的推进器(在3 DOF的潮汐中,Wind,Wave&电流),摇摆和偏航,以保持船位的位置(对于动态定位很重要)。 这艘船有4个推进器,1个固定角度推进器(隧道)和3个旋转推进器(方位角)。固定推进器具有一个方向(x1)的力,并且旋转推进器的力在两个方向x和y的两个方向上实现为可变对(x2,x3),(x4,x5),(x6,x7)。 eg x2和x3分别是x和y中的力,用于旋转推进器1 。对于3个DOF,还有3个松弛变量,以确保解决方案。

标准形式上的问题

编程问题:我想限制一个推进器的力通过对其实施不平等约束,但是通过实现约束“ ineq1”,所有输出都将所有输出最小化至零。约束应限制x1,并且非常简单:(x1< x1_max)随访:“最小化”似乎忽略了约束词典中的第一个约束,这是否是平等或不平等的关系约束。但是,第二个约束是维持的。

输出仅具有等价约束正确输出

输出带有破坏性不等式约束不平等的输出

我尝试过的是

  • ...尝试不同的算法
  • ...在约束中测试阳性/负面因素的每种组合
  • ...在标准形式A*X&lt中使用数组/向量A; b而不是仅仅是x [0]
  • ...使用数字代替fmax [0]
  • ...尝试了其他设计变量及其组合

code

可以很容易地运行。在第42行中的“ cons1”和“ cons2”之间的更改以查看不同的结果。

import numpy as np
from scipy.optimize import minimize

# Parameters
nf  = 1         # No. of fixed thrusters
nr  = 3         # No. of rotating thrusters
nt  = nf + 2*nr # No. of actuators
ns  = 3         # No. of slack variables (slacks)
n   = nt + ns   # Design variables
Lx  = np.array([30.5, 22.25, -35.5, -35.5])         # Thruster position
W   = np.diag([1, 1, 1, 1, 1, 1, 1])                # Weighting for thrusters
Q   = np.diag([1, 1, 1])*5000                       # Weighting for slacks
Te  = np.array([[0,1,0,1,0,1,0],                    # Thrust config. matrix
                [1,0,1,0,1,0,1],
                [Lx[0],0,Lx[1],0,Lx[2],0,Lx[3]]])
fmax = np.array([ 50000,  60000,  75000,  75000])

tau = np.array([50000,35000,0]) # Environmental forces in surge, sway & yaw
x0 = np.zeros(n)

# Problem definition
def obj(x):
    fe = x[:nt]
    s  = x[nt:]
    return fe.transpose()@W@fe + s.transpose()@Q@s

def eqcon(x):
    fe = x[:nt]
    s  = x[nt:]
    return tau + s - Te@fe # = 0

def ineq1(x):
    return fmax[0] - x[0] # > 0

cons1 = {'type': 'eq',   'fun': eqcon}

cons2 = {'type': 'eq',   'fun': eqcon,
         'type': 'ineq', 'fun': ineq1}

# Computing
opt = {'disp': True}
res = minimize(obj, x0, method='SLSQP', constraints=cons2, options=opt)

# Debugging
print("Environmental forces (surge, sway & yaw): ", tau)
print("Forces: ", np.round(res.x[:nt],1))
print("Slacks: ", np.round(res.x[nt:],1))
print(f"Thruster 1 has angle 90.00 with force {res.x[0]/1000:0.2f} kN")

angles = np.zeros(nr)
ux = res.x[nf:nt][::2]      # Every other force element in x for azimuth: ux2, ux3, ...
uy = res.x[nf:nt][1:][::2]  # uy2, uy3, ...

for i in range(nr):
    angles[i] = np.arctan2(uy[i], ux[i]) * 180 / np.pi
    print(f"Thruster {nf+i+1} has angle {angles[i]:0.2f} with force {np.sqrt(ux[i]**2+uy[i]**2)/1000:0.2f} kN")

有什么想法吗?

Optimization problem: Just for context, not strictly needed. Using SciPy's "minimize" the code is allocating optimal control forces to thrusters on a ship given environmental forces acting on the ship (wind, waves & current) in the 3 DOFs surge, sway and yaw to hold the ship's position (Important for Dynamic Positioning).
This ship has 4 thrusters, 1 fixed-angle thruster (tunnel) and 3 rotating thrusters (azimuth). The fixed thruster has a force in one direction (x1) and the rotating thrusters has forces in two directions, x and y, implemented as variable pairs (x2, x3), (x4, x5), (x6, x7). E.g. x2 and x3 is the force in x and y, respectively, for rotating thruster 1. There are also 3 slack variables for the 3 DOFs to ensure a solution.

Problem on standard form

Programming problem: I want to limit one of the thrusters' force by implementing an inequality constraint on it, but by implementing the constraint "ineq1" all outputs are minimized to zero. The constraint should limit x1 and is very simply like this: (x1 < x1_max) Follow-up: "minimize" seems to ignore the first constraint in the constraint dictionary and it doesn't matter if it's an equality or inequality constraint. The second constraint is however upheld.

Output with only equality constraint:
Correct output

Output with breaking inequality constraint:
Incorrect output with inequality

What I've tried is

  • ... trying different algorithms
  • ... test every combination of positives/negatives in the constraint
  • ... use an array/vector A as in the standard form A*x < b instead of just x[0]
  • ... using a number instead of fmax[0]
  • ... tried other design variables and combinations of them

Code:

This can be readily run. Change between "cons1" and "cons2" in line 42 to see the different results.

import numpy as np
from scipy.optimize import minimize

# Parameters
nf  = 1         # No. of fixed thrusters
nr  = 3         # No. of rotating thrusters
nt  = nf + 2*nr # No. of actuators
ns  = 3         # No. of slack variables (slacks)
n   = nt + ns   # Design variables
Lx  = np.array([30.5, 22.25, -35.5, -35.5])         # Thruster position
W   = np.diag([1, 1, 1, 1, 1, 1, 1])                # Weighting for thrusters
Q   = np.diag([1, 1, 1])*5000                       # Weighting for slacks
Te  = np.array([[0,1,0,1,0,1,0],                    # Thrust config. matrix
                [1,0,1,0,1,0,1],
                [Lx[0],0,Lx[1],0,Lx[2],0,Lx[3]]])
fmax = np.array([ 50000,  60000,  75000,  75000])

tau = np.array([50000,35000,0]) # Environmental forces in surge, sway & yaw
x0 = np.zeros(n)

# Problem definition
def obj(x):
    fe = x[:nt]
    s  = x[nt:]
    return fe.transpose()@W@fe + s.transpose()@Q@s

def eqcon(x):
    fe = x[:nt]
    s  = x[nt:]
    return tau + s - Te@fe # = 0

def ineq1(x):
    return fmax[0] - x[0] # > 0

cons1 = {'type': 'eq',   'fun': eqcon}

cons2 = {'type': 'eq',   'fun': eqcon,
         'type': 'ineq', 'fun': ineq1}

# Computing
opt = {'disp': True}
res = minimize(obj, x0, method='SLSQP', constraints=cons2, options=opt)

# Debugging
print("Environmental forces (surge, sway & yaw): ", tau)
print("Forces: ", np.round(res.x[:nt],1))
print("Slacks: ", np.round(res.x[nt:],1))
print(f"Thruster 1 has angle 90.00 with force {res.x[0]/1000:0.2f} kN")

angles = np.zeros(nr)
ux = res.x[nf:nt][::2]      # Every other force element in x for azimuth: ux2, ux3, ...
uy = res.x[nf:nt][1:][::2]  # uy2, uy3, ...

for i in range(nr):
    angles[i] = np.arctan2(uy[i], ux[i]) * 180 / np.pi
    print(f"Thruster {nf+i+1} has angle {angles[i]:0.2f} with force {np.sqrt(ux[i]**2+uy[i]**2)/1000:0.2f} kN")

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风吹雪碎 2025-02-20 11:06:03

预计约束将是字典列表,因此使用

cons2 = [{'type': 'eq',   'fun': eqcon},
         {'type': 'ineq', 'fun': ineq1}]

应解决您的问题。话虽如此,字典中的键应该是独一无二的。否则,您将无法通过模棱两可的键在字典中访问特定值。

The constraints are expected to be a list of dictionaries, so using

cons2 = [{'type': 'eq',   'fun': eqcon},
         {'type': 'ineq', 'fun': ineq1}]

should fix your problem. That being said, the keys inside a dictionary should be unique. Otherwise, you aren't able to access a specific value in the dictionary by ambiguous keys.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文