【Nomoto 船舶模型】
- 1. Nomoto 船舶模型簡介
- 2. 來源及發展歷程
- 3. 構建 一階模型Nomoto 船舶模型
- 3.1 C++ 實現
- 3.2 Python 實現
- 3.3 說明
- 5. 參數辨識方法
- 5.1 基于最小二乘法的參數辨識
- 5.2 數學推導
- 5.3 Python 實現
- 5.4 說明
- 4. 結論
- 參考文獻
1. Nomoto 船舶模型簡介
Nomoto 模型是由日本學者 T. Nomoto 于上世紀50年代提出的一種用于描述船舶操縱運動的數學模型。它最初是為了解決船舶在操舵時的動態響應問題,并且因其簡單性和實用性而被廣泛應用于航海工程和船舶自動控制領域。Nomoto 模型通過簡化實際的水動力特性來預測船舶在舵角輸入下的響應,適用于初步分析和控制系統設計。
參考學習:https://github.com/martinlarsalbert/blog/blob/master/_notebooks/2020-08-25-nomoto_model.ipynb
2. 來源及發展歷程
Nomoto 模型的發展經歷了多個階段,從最初的一階模型擴展到二階甚至更高階模型,以更準確地描述船舶的動態行為。盡管存在更復雜的模型(如 Abkowitz 整體模型、MMG 分離型模型、Fossen 的矩陣向量形式模型),Nomoto 模型由于其簡潔性仍然在許多應用中具有重要地位。
3. 構建 一階模型Nomoto 船舶模型
Nomoto 模型通常用以下微分方程表示:
τ 1 d ψ d t + ψ = K δ \tau_1 \frac{d\psi}{dt} + \psi = K \delta τ1?dtdψ?+ψ=Kδ
其中:
- ψ \psi ψ 是船舶的航向角(偏航角),單位為弧度。
- δ \delta δ是舵角,單位為弧度。
- K K K 是比例增益,表征舵角對航向角變化的影響程度。
- τ 1 \tau_1 τ1? 是時間常數,代表系統的時間響應特性。
3.1 C++ 實現
下面是一個簡單的C++代碼示例,用于模擬Nomoto模型的行為:
#include <iostream>
#include <cmath>class NomotoModel {
public:NomotoModel(double tau, double K) : tau_(tau), K_(K), psi_(0.0), dpsi_dt_(0.0) {}// 更新狀態void update(double delta, double dt) {// 計算導數double d2psi_dt2 = (-1.0 / tau_) * dpsi_dt_ + (K_ / tau_) * delta;// 使用歐拉法更新狀態dpsi_dt_ += d2psi_dt2 * dt;psi_ += dpsi_dt_ * dt;// 確保航向角在 [-pi, pi] 范圍內while (psi_ > M_PI) psi_ -= 2 * M_PI;while (psi_ < -M_PI) psi_ += 2 * M_PI;}// 獲取當前航向角double getHeading() const { return psi_; }private:double tau_, K_; // 模型參數double psi_; // 當前航向角double dpsi_dt_; // 當前航向角速度
};int main() {// 定義模型參數double tau = 5.0; // 時間常數double K = 0.05; // 比例增益// 創建 Nomoto 模型實例NomotoModel model(tau, K);// 模擬時間步長和總時間double dt = 0.1; // 時間步長 (秒)double totalTime = 30.0; // 總模擬時間 (秒)// 設置初始舵角double delta = M_PI / 6; // 初始舵角為 30 度for (double t = 0; t <= totalTime; t += dt) {// 更新模型狀態model.update(delta, dt);// 輸出當前時間和航向角std::cout << "Time: " << t << "s, Heading: " << model.getHeading() * 180.0 / M_PI << " degrees" << std::endl;}return 0;
}
3.2 Python 實現
下面是等效的Python代碼實現:
import mathclass NomotoModel:def __init__(self, tau, K):self.tau_ = tauself.K_ = Kself.psi_ = 0.0self.dpsi_dt_ = 0.0# 更新狀態def update(self, delta, dt):# 計算導數d2psi_dt2 = (-1.0 / self.tau_) * self.dpsi_dt_ + (self.K_ / self.tau_) * delta# 使用歐拉法更新狀態self.dpsi_dt_ += d2psi_dt2 * dtself.psi_ += self.dpsi_dt_ * dt# 確保航向角在 [-pi, pi] 范圍內while self.psi_ > math.pi:self.psi_ -= 2 * math.piwhile self.psi_ < -math.pi:self.psi_ += 2 * math.pi# 獲取當前航向角def get_heading(self):return self.psi_if __name__ == "__main__":# 定義模型參數tau = 5.0 # 時間常數K = 0.05 # 比例增益# 創建 Nomoto 模型實例model = NomotoModel(tau, K)# 模擬時間步長和總時間dt = 0.1 # 時間步長 (秒)total_time = 30.0 # 總模擬時間 (秒)# 設置初始舵角delta = math.pi / 6 # 初始舵角為 30 度for t in range(int(total_time / dt)):current_time = t * dt# 更新模型狀態model.update(delta, dt)# 輸出當前時間和航向角print(f"Time: {current_time:.1f}s, Heading: {math.degrees(model.get_heading()):.2f} degrees")
3.3 說明
-
參數解釋:
tau
:時間常數,反映了系統的慣性特性。K
:比例增益,決定了舵角對航向角變化的影響程度。
-
數值積分方法:
- 在上述實現中,使用了簡單的歐拉法進行數值積分。對于更精確的仿真,可以考慮使用更高階的數值積分方法,如龍格-庫塔法(Runge-Kutta method)。
-
角度范圍限制:
- 為了確保航向角保持在合理的范圍內,使用了
while
循環將角度限制在 ([-π, π]) 之間。
Nomoto 模型參數辨識是指通過實驗數據或仿真結果來確定模型中的未知參數,如時間常數 (\tau) 和比例增益 (K)。對于 Nomoto 一階模型:
- 為了確保航向角保持在合理的范圍內,使用了
τ d ψ d t + ψ = K δ \tau \frac{d\psi}{dt} + \psi = K \delta τdtdψ?+ψ=Kδ
其中:
- KaTeX parse error: Undefined control sequence: \ps at position 1: \?p?s?是船舶的航向角(偏航角)。
- δ \delta δ是舵角。
- KaTeX parse error: Undefined control sequence: \K at position 1: \?K?是比例增益,表征舵角對航向角變化的影響程度。
- τ \tau τ 是時間常數,代表系統的時間響應特性。
5. 參數辨識方法
實現參數辨識通常需要以下步驟:
- 實驗設計:進行操舵實驗,記錄船舶在不同舵角下的航向角隨時間的變化情況。
- 數據預處理:清洗和整理實驗數據,確保其適用于后續分析。
- 選擇辨識方法:根據問題的具體情況選擇合適的參數辨識方法,常用的有最小二乘法、遞推最小二乘法、極大似然估計等。
- 參數優化:利用選定的方法估計模型參數,使模型預測值與實際觀測值之間的誤差最小化。
下面介紹一種基于最小二乘法的簡單參數辨識方法,并提供相應的 Python 實現示例。
5.1 基于最小二乘法的參數辨識
假設我們已經有一組實驗數據,包含時間序列 t
、舵角序列 delta
和航向角序列 psi
。我們的目標是找到最優的 (\tau) 和 (K),使得模型預測值與實際觀測值之間的誤差平方和最小。
5.2 數學推導
首先將 Nomoto 模型重寫為離散形式:
ψ k + 1 = ( 1 ? Δ t τ ) ψ k + Δ t τ K δ k \psi_{k+1} = (1 - \frac{\Delta t}{\tau}) \psi_k + \frac{\Delta t}{\tau} K \delta_k ψk+1?=(1?τΔt?)ψk?+τΔt?Kδk?
其中 Δ t \Delta t Δt 是采樣間隔, k k k 表示第 k k k 個采樣點。
定義誤差函數 E E E 為:
E ( τ , K ) = ∑ k = 1 N ( ψ k model ? ψ k data ) 2 E(\tau, K) = \sum_{k=1}^{N} (\psi_k^{\text{model}} - \psi_k^{\text{data}})^2 E(τ,K)=k=1∑N?(ψkmodel??ψkdata?)2
其中 ψ k model \psi_k^{\text{model}} ψkmodel?是模型預測的航向角, ψ k data \psi_k^{\text{data}} ψkdata? 是實驗數據中的航向角。
我們的目標是最小化 E ( τ , K ) E(\tau, K) E(τ,K)。
5.3 Python 實現
以下是使用 Python 和 SciPy 庫進行參數辨識的示例代碼:
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt# 定義模型函數
def nomoto_model(params, delta, dt):tau, K = paramspsi_model = [0] # 初始航向角設為0for k in range(1, len(delta)):psi_next = (1 - dt / tau) * psi_model[-1] + (dt / tau) * K * delta[k]psi_model.append(psi_next)return np.array(psi_model)# 定義誤差函數
def error_function(params, delta, dt, psi_data):psi_model = nomoto_model(params, delta, dt)return np.sum((psi_model - psi_data) ** 2)# 生成模擬數據(用于測試)
np.random.seed(0)
time = np.linspace(0, 30, 300)
dt = time[1] - time[0]
delta = np.zeros_like(time)
delta[50:100] = np.radians(10) # 設置舵角為10度
delta[150:200] = np.radians(-10) # 設置舵角為-10度# 真實參數
true_tau = 5.0
true_K = 0.05# 使用真實參數生成模擬的航向角數據
psi_true = nomoto_model([true_tau, true_K], delta, dt)
psi_data = psi_true + np.random.normal(0, 0.01, size=psi_true.shape) # 添加噪聲# 參數辨識
initial_guess = [1.0, 0.1] # 初始猜測值
result = minimize(error_function, initial_guess, args=(delta, dt, psi_data), method='L-BFGS-B')estimated_tau, estimated_K = result.x
print(f"Estimated parameters: tau = {estimated_tau:.3f}, K = {estimated_K:.3f}")# 繪制結果
plt.figure(figsize=(10, 6))
plt.plot(time, np.degrees(psi_data), label="Noisy Data", linestyle='--')
plt.plot(time, np.degrees(nomoto_model([true_tau, true_K], delta, dt)), label="True Model")
plt.plot(time, np.degrees(nomoto_model(result.x, delta, dt)), label="Estimated Model")
plt.xlabel("Time (s)")
plt.ylabel("Heading Angle (degrees)")
plt.legend()
plt.show()
5.4 說明
-
數據生成:為了測試辨識算法的效果,我們首先生成了一組帶有噪聲的模擬數據。這里使用了真實的參數 (\tau) 和 (K) 來生成模擬的航向角數據,并添加了一些隨機噪聲以模擬實際情況。
-
誤差函數:定義了一個誤差函數
error_function
,它計算模型預測值與實驗數據之間的誤差平方和。 -
參數辨識:使用 SciPy 的
minimize
函數來最小化誤差函數,從而估計出最佳的 (\tau) 和 (K) 值。這里選擇了 L-BFGS-B 方法作為優化算法,因為它適合處理有界的參數空間。 -
結果展示:最后,繪制了原始數據、真實模型輸出以及辨識得到的模型輸出,以便直觀地比較它們之間的差異。
上述方法是一個簡單的實現,適用于初步的參數辨識任務。在實際應用中,可能需要考慮以下幾個方面進行改進:
- 更復雜的模型:如果需要更高的精度,可以考慮使用更高階的 Nomoto 模型或其他更為復雜的船舶操縱模型。
- 魯棒性:針對不同的噪聲水平和數據質量,優化算法的選擇和參數初始化可能會有所不同。
- 實時辨識:在某些應用場景下,可能需要在線實時地更新模型參數,這時可以考慮使用遞推最小二乘法等在線學習算法。
4. 結論
Nomoto 模型提供了一種簡便的方法來描述船舶的操縱行為,適用于初步分析和控制系統設計。盡管它有一定的局限性,但在很多情況下已經足夠有效。對于更精確的模擬和控制需求,可以考慮使用更復雜的模型,如 MMG 分離型模型或 Fossen 的矩陣向量形式模型。
通過【Nomoto 船舶模型C++與python實現】學習,您應該能夠用Nomoto 船舶模型描述船舶的操縱行為。從而實現對外部世界進行感知,充分認識這個有機與無機的環境,科學地合理地進行創作和發揮效益,然后為人類社會發展貢獻一點微薄之力。🤣🤣🤣
- 我會持續更新對應專欄博客,非常期待你的三連!!!🎉🎉🎉
- 如果鵬鵬有哪里說的不妥,還請大佬多多評論指教!!!👍👍👍
- 下面有我的🐧🐧🐧群推廣,歡迎志同道合的朋友們加入,期待與你的思維碰撞😘😘😘
參考文獻
- Nomoto, K., Taguchi, K., Honda, K., & Hirano, S. (1957). On the Steering Qualities of Ships. International Shipbuilding Progress, 4(35), 354-370.
- Fossen, T. I. (2011). Handbook of Marine Craft Hydrodynamics and Motion Control. John Wiley & Sons.