I think the sign of the rudder's surge term in shipClarke83.dynamics may be flipped, but I may be misreading the conventions, so I wanted to ask.
The code (src/python_vehicle_simulator/vehicles/shipClarke83.py, line 187 on master at 695c673):
Xdd = -0.5 * (1 - t_R) * self.rho * U_r ** 2 * AR * CN
...
delta_R = -delta # physical rudder angle (rad)
tau1 = (1 - t_deduction) * T - Xdd * math.sin(delta_R) ** 2
tau2 = -Yd * math.sin(2 * delta_R)
tau6 = -Nd * math.sin(2 * delta_R)
The handbook (Section 9.5, Rudder in Propeller Slipstream; the same equations are on slide 20 of the TTK4190 Chapter 9 lecture notes):
X_R = −(1 − t_R)(½ ρ U_R² A_R C_N) sin²(δ) ≈ −X_δδ δ², with X_δδ = ½(1 − t_R) ρ U_R² A_R C_N > 0,
and the slide adds that "the surge force increases resistance during turning."
Xdd already includes the minus sign (Xdd = −X_δδ), so the handbook's X_R is Xdd * sin(delta)**2, and tau1 adds −X_R ≥ 0 instead. In tau2 and tau6 the leading minus cancels delta_R = -delta because sin(2δ) is odd; written in delta, they are the handbook's Y_R and N_R. In surge it cannot cancel: sin²(δ) is even, so the rudder term in tau1 pushes the ship forward whichever sign convention is used for the rudder angle. The other models treat this term as a resistance. In PVS tanker.py, Xccdd = -0.093 enters as + Xccdd * abs(c) * c * delta ** 2. In MSS mariner.m, Xdd = -95e-5 enters as + Xdd*delta^2. In MSS container.m, which uses the same C_N = 6.13Λ/(Λ + 2.25), cRX*FN*sin(delta) has FN = -(...)*sin(alphaR), so it is about −cRX(...)sin²(delta).
Minimal example (default constructor values, rudder held at 30 deg after a straight-line settle):
import math, numpy as np
from python_vehicle_simulator.vehicles.shipClarke83 import shipClarke83
ship = shipClarke83("stepInput", 0, 50.0, 7.0, 5.0, 0.7, 0, 0, 1e5)
eta, nu, ua, h = np.zeros(6), np.array([3.0, 0, 0, 0, 0, 0]), np.zeros(1), 0.02
for delta_deg in (0.0, 30.0):
for _ in range(int(600 / h)):
nu, ua = ship.dynamics(eta, nu, ua, np.array([math.radians(delta_deg)]), h)
print(delta_deg, math.hypot(nu[0], nu[1]))
This prints 3.26 m/s for the straight line and 29.5 m/s after 600 s at 30 deg; along the way the speed is 4.15, 4.81 and 6.40 m/s after 60, 120 and 300 s. The rudder term grows with U² while the linear surge damping grows with U. With these defaults the rudder term outgrows the damping at every speed once the rudder angle is above about 28 deg, so at 30 deg the speed has no equilibrium. At smaller angles the ship still settles faster than on the straight, for example 3.88 m/s at 20 deg. A time step of 0.005s gives the same numbers. With + Xdd * math.sin(delta_R) ** 2 the speed settles at 2.64 m/s at 30 deg (0.81 of the straight-line speed), and the turning radius stays near 87 m either way.
Possible fix:
tau1 = (1 - t_deduction) * T + Xdd * math.sin(delta_R) ** 2
I think the sign of the rudder's surge term in
shipClarke83.dynamicsmay be flipped, but I may be misreading the conventions, so I wanted to ask.The code (
src/python_vehicle_simulator/vehicles/shipClarke83.py, line 187 on master at 695c673):The handbook (Section 9.5, Rudder in Propeller Slipstream; the same equations are on slide 20 of the TTK4190 Chapter 9 lecture notes):
X_R = −(1 − t_R)(½ ρ U_R² A_R C_N) sin²(δ) ≈ −X_δδ δ², with X_δδ = ½(1 − t_R) ρ U_R² A_R C_N > 0,
and the slide adds that "the surge force increases resistance during turning."
Xddalready includes the minus sign (Xdd= −X_δδ), so the handbook's X_R isXdd * sin(delta)**2, andtau1adds −X_R ≥ 0 instead. Intau2andtau6the leading minus cancelsdelta_R = -deltabecause sin(2δ) is odd; written indelta, they are the handbook's Y_R and N_R. In surge it cannot cancel: sin²(δ) is even, so the rudder term intau1pushes the ship forward whichever sign convention is used for the rudder angle. The other models treat this term as a resistance. In PVStanker.py,Xccdd = -0.093enters as+ Xccdd * abs(c) * c * delta ** 2. In MSSmariner.m,Xdd = -95e-5enters as+ Xdd*delta^2. In MSScontainer.m, which uses the same C_N = 6.13Λ/(Λ + 2.25),cRX*FN*sin(delta)hasFN = -(...)*sin(alphaR), so it is about −cRX(...)sin²(delta).Minimal example (default constructor values, rudder held at 30 deg after a straight-line settle):
This prints 3.26 m/s for the straight line and 29.5 m/s after 600 s at 30 deg; along the way the speed is 4.15, 4.81 and 6.40 m/s after 60, 120 and 300 s. The rudder term grows with U² while the linear surge damping grows with U. With these defaults the rudder term outgrows the damping at every speed once the rudder angle is above about 28 deg, so at 30 deg the speed has no equilibrium. At smaller angles the ship still settles faster than on the straight, for example 3.88 m/s at 20 deg. A time step of 0.005s gives the same numbers. With
+ Xdd * math.sin(delta_R) ** 2the speed settles at 2.64 m/s at 30 deg (0.81 of the straight-line speed), and the turning radius stays near 87 m either way.Possible fix: