このPython関数は、
質点Aと質点Bの相対速度に比例する
粘性抵抗力を計算します。
質点Bを省略すると、
動かない空間や地面に対する
抵抗力を計算することができます。
1次元の計算だけでなく、
NumPy配列を入力することで
多次元の計算にも自動で対応します。
📋 関数の仕様
⚠️ 単位系について
本関数の入出力は、すべて 一貫した単位系 で入力されることを前提としています。
- たとえば、SI単位系
[N/(m/s), m/s]で入力すれば、出力も[N]で返ります - 関数内のコメントでは一例としてSI単位系を記載していますが、単位系が統一されていれば他の単位でも計算できます
▶ 入力
- 粘性係数 (
c)- 0以上の有限値
- 多次元の場合は、それぞれの成分に値を入力
- 質点Aの速度 (
v_a) - 質点Bの速度 (
v_b)- 省略した場合は、0(静止)として計算
▶ 出力
入力した質点Aの速度(v_a)と同じデータ形式(数値、1次元のNumPy配列)で出力します。
- 質点Aに働く粘性抵抗力 (
f_a) - 質点Bに働く粘性抵抗力 (
f_b)f_aと大きさが同じで、向きが逆(作用・反作用)
▶ 計算方法
- 相対速度に比例する力 を計算
- 質点Aに働く力として 、質点Bに働く力として を出力
具体的な計算方法は、
次のダウンロードエリアで
関数をご確認ください。
📥 ダウンロード
ご自身のコードに組み込む場合は、
以下の関数をコピーしてご使用ください。
⚠️ ご利用にあたって
本関数の利用・改変・再配布条件、および免責事項については、プライバシーポリシー・免責事項 をご確認ください。
▶ 計算関数
入力値が数値・1次元のNumPy配列の場合は、この関数単体で動作します。
- 入力値がリスト・タプルの場合や、入力値のエラーチェックを追加したい場合は、後述の内部関数もコピーしてご使用ください。
インポートするライブラリ
# NumPy配列(ndarray)を入力する場合
import numpy as np # 配列計算に使用するライブラリ関数
def calc_viscous_drag(c, v_a, v_b=None):
"""
粘性抵抗モデルに基づく抵抗力の計算(多次元対応)
Args:
c : float | tuple[float] | list[float] | ndarray 粘性係数 [N・s/m] (>= 0, 有限値)
v_a : float | tuple[float] | list[float] | ndarray 質点Aの速度 [m/s](有限値)
v_b : float | tuple[float] | list[float] | ndarray | None 質点Bの速度 [m/s](有限値、省略時は0)
※ ndarray は1次元配列(例:np.array([1.0, 2.0]))で指定してください。
※ 各要素が各成分(x, y, z)に対応します。
※ 0次元配列(例:np.array(1.0))はスカラーとして扱います。
※ 本関数のみを単体で使用する場合は、float または ndarray のみ対応します。
※ list・tuple を使う場合や、入力値のエラーチェックを行う場合は、次の内部関数も必要です。
・_to_array_1dsim_com : 入力値(数値・list・tuple・ndarray)を1次元ndarrayに変換
・_validate_values_1dsim_com : 配列内の各要素が実数・有限値・指定範囲内であるか確認
・_format_output_1dsim_com : 計算結果の桁あふれを確認し、基準入力と同じ形式に変換
Returns:
f_a : float | tuple[float] | list[float] | ndarray 質点Aに働く抵抗力 [N]
f_b : float | tuple[float] | list[float] | ndarray 質点Bに働く抵抗力 [N]
※ いずれも v_a と同じ形式(float / tuple / list / ndarray)で返します。
Raises:
TypeError : c, v_a, v_b の要素が実数でない場合、または c, v_a, v_b に数値・list・tuple・ndarray 以外を渡した場合
ValueError : c が0以上の有限値でない場合、v_a, v_b が有限値でない場合、c, v_a, v_b に2次元以上の ndarray を渡した場合、c, v_a, v_b の要素数が不一致・空の場合、または計算結果が桁あふれした場合
========================================================
Copyright (c) 2026 1Dsim.com
本関数の利用・改変・再配布の条件は、
1Dsim.com の「プライバシーポリシー・免責事項」
(https://www.1dsim.com/privacy-policy/)に従います。
このCopyright表記は削除しないでください。
========================================================
"""
# エラーメッセージの先頭に表示する関数名を定義
func_name = "calc_viscous_drag"
# --- 1. 計算準備と入力値の妥当性チェック ---
# 内部関数(_to_array_1dsim_com)が定義されている場合は、入力形式の変換を行います。
if "_to_array_1dsim_com" in globals():
# 入力の形式(数値・list・tuple・ndarray)にかかわらず同じ数式で計算できるよう、
# すべて1次元ndarrayに変換します。
c_calc = _to_array_1dsim_com(c, func_name)
v_a_calc = _to_array_1dsim_com(v_a, func_name)
# v_bが省略された場合は、質点Bを静止(速度0)とみなします(v_aの要素数に合わせます)。
dim = len(v_a_calc)
v_b_calc = np.array([0.0] * dim, dtype=object) if v_b is None else _to_array_1dsim_com(v_b, func_name)
# 粘性係数・速度の要素数(成分の数)が揃っているか確認します。
if not (len(c_calc) == dim == len(v_b_calc)):
raise ValueError(f"{func_name}: c, v_a, v_b の要素数が一致していません。")
# 要素数0(空のリストなど)では計算対象がないため、エラーとします。
if dim == 0:
raise ValueError(f"{func_name}: c, v_a, v_b が空です。")
else:
# _to_array_1dsim_com を使用しない場合は、変換を行わず、数値またはndarrayとしてそのまま計算します。
# (+ 0.0 により、整数型のndarrayが入力された場合でもfloat型に変換し、常に浮動小数点数で計算します)
c_calc = c + 0.0
v_a_calc = v_a + 0.0
v_b_calc = 0.0 if v_b is None else v_b + 0.0
# 内部関数(_validate_values_1dsim_com)が定義されている場合は、入力値の妥当性チェックを行います。
if "_validate_values_1dsim_com" in globals():
# 粘性係数cが0以上の実数・有限値であるか確認します。
_validate_values_1dsim_com(c, func_name, "粘性係数c", min_val=0, include_min=True)
# 速度v_a, v_bが実数・有限値であるか確認します(v_bが省略された場合は除く)。
for arr in (v_a, v_b):
if arr is not None:
_validate_values_1dsim_com(arr, func_name, "v_a, v_b")
# --- 2. 物理計算 ---
# 抵抗力 f_drag = c * (v_a - v_b)(相対速度に比例) [N]
f_drag = c_calc * (v_a_calc - v_b_calc)
# 質点Aには相対速度と逆向き(動きを妨げる向き)の力を、
# 質点Bには同じ大きさで逆向きの力(反作用)を与えます [N]
# (+ 0.0 により、力が0のとき -0.0 ではなく 0.0 を返します)
f_a = -f_drag + 0.0
f_b = f_drag + 0.0
# --- 3. 出力形式の調整 ---
# 出力形式は v_a の形式(型)のみで決定します(c, v_b の形式は影響しません)。
# 内部関数(_format_output_1dsim_com)が定義されている場合は、桁あふれを確認し、v_a と同じ形式に変換して返します。
if "_format_output_1dsim_com" in globals():
return _format_output_1dsim_com(v_a, func_name, f_a, f_b)
# _format_output_1dsim_com を使用しない場合は、計算結果(数値またはndarray)をそのまま返します。
return f_a, f_b▶ 内部関数①
計算関数にリスト・タプルを入力したいときは、
1次元のNumPy配列へ変換するために
この関数をコピーしてご使用ください。
- 計算関数と同じファイル内にコピーするだけで、計算関数に認識されて使用されます。
インポートするライブラリ
import numbers # 数値型の判定に使用する標準ライブラリ
import numpy as np # 配列計算に使用するライブラリ関数
def _to_array_1dsim_com(val, func_name):
"""入力値(数値・list・tuple・ndarray)を、成分ごとに分けた1次元ndarrayに変換する内部関数"""
# 例:5.0 → array([5.0])、(1.0, 2.0) → array([1.0, 2.0])、np.array([1.0, 2.0]) → array([1.0, 2.0])
# 上記以外の型(文字列・集合・辞書・range・pandas.Series など)は受け付けません。
# (受け付けると出力形式を正しく判定できず、結果の一部が失われるため)
if isinstance(val, np.ndarray):
# 2次元以上のndarrayは、各要素を成分(x, y, z)として扱えないため受け付けません。
if val.ndim > 1:
raise ValueError(f"{func_name}: ndarrayは1次元配列で指定してください(入力は{val.ndim}次元です)。")
# 0次元のndarray(np.array(1.0) など)は、中の数値を取り出して要素1つのリストにします。
if val.ndim == 0:
raw_list = [val.item()]
else:
# 1次元のndarrayは、要素を順に並べたリストに取り出します。
# (tolist() により、各要素は numpy の数値(np.float64 など)ではなく Python の数値になります)
raw_list = val.tolist()
# list・tupleは、要素を順に並べたリストに取り出します。
elif isinstance(val, (list, tuple)):
# numpyの数値(np.float64 など)が含まれる場合は、Pythonの数値に変換してから格納します。
raw_list = [x.item() if getattr(x, "ndim", None) == 0 else x for x in val]
# 数値(スカラー)は要素1つのリストにします。
elif isinstance(val, numbers.Number):
# numpyの数値(np.float64 など)は、Pythonの数値に変換してから格納します。
if getattr(val, "ndim", None) == 0:
raw_list = [val.item()]
else:
raw_list = [val]
# 上記のいずれにも当てはまらない型はエラーとします。
else:
raise TypeError(f"{func_name}: {type(val).__name__}型は入力できません。数値、list、tuple、ndarrayを使用してください。")
# 各要素の型(boolなど)を保持したまま要素ごとの四則演算ができるよう、object型の1次元ndarrayとして返します。
return np.array(raw_list, dtype=object)▶ 内部関数②
計算関数に入力される値が
実数や有限値であるか確認したいときは、
この関数をコピーしてご使用ください。
- 計算関数と同じファイル内にコピーするだけで、計算関数に認識されて使用されます。
インポートするライブラリ
import numbers # 数値型の判定に使用する標準ライブラリ関数
def _validate_values_1dsim_com(arr, func_name, label, min_val=None, include_min=True):
"""配列や数値の各要素が実数・有限値であり、指定された範囲内にあるか確認する内部関数"""
# 2次元以上のndarrayを除外(_to_array_1dsim_com を使用しない場合の対策)
if getattr(arr, "ndim", 0) > 1:
raise ValueError(
f"{func_name}:"
f" ndarrayは1次元配列で指定してください(入力は{arr.ndim}次元です)。"
)
# _to_array_1dsim_com を使用しない場合(スカラー値や0次元ndarrayが渡された場合)でも
# 同じループで判定できるよう、要素を並べたリストに取り出します。
raw_vals = arr.tolist() if hasattr(arr, "tolist") else arr
vals = raw_vals if isinstance(raw_vals, (list, tuple)) else [raw_vals]
for v_val in vals:
# list・tuple内に0次元のndarrayやnumpyの数値(np.float64 など)が含まれる場合は、Pythonの数値に変換します。
if getattr(v_val, "ndim", None) == 0:
v_val = v_val.item()
# 各要素が実数であるか確認します。
# (True/False は 1/0 として計算できてしまうため、bool型は明示的に除外します)
if isinstance(v_val, bool) or not isinstance(v_val, numbers.Real):
raise TypeError(f"{func_name}: {label}の各要素は実数で指定してください。")
# 下限値の指定がない場合は、無限大・NaNのみを除外します。
# (NaN は大小比較の結果が常に False になるため、この1つの条件で無限大と一緒に検出できます)
if min_val is None:
if not (-float("inf") < v_val < float("inf")):
raise ValueError(f"{func_name}: {label}は有限の値である必要があります。")
# 下限値を含む場合(min_val 以上)
elif include_min:
if not (min_val <= v_val < float("inf")):
raise ValueError(f"{func_name}: {label}は{min_val}以上の有限の値である必要があります。")
# 下限値を含まない場合(min_val より大きい)
else:
if not (min_val < v_val < float("inf")):
raise ValueError(f"{func_name}: {label}は{min_val}より大きい有限の値である必要があります。")▶ 内部関数③
計算結果の桁あふれを確認したり、
リスト・タプルで入力した計算結果を
リスト・タプルで出力したいときは、
この関数をコピーしてご使用ください。
- 計算関数と同じファイル内にコピーするだけで、計算関数に認識されて使用されます。
インポートするライブラリ
import numpy as np # 配列計算に使用するライブラリ関数
def _format_output_1dsim_com(ref_input, func_name, *result_arrays):
"""計算結果の桁あふれを確認し、基準入力(ref_input)と同じ形式に変換して返す内部関数"""
# _to_array_1dsim_com を使用しない場合(計算結果がスカラー値や0次元ndarrayの場合)でも
# 同じ処理で変換できるよう、各計算結果を要素のリストに統一します。
result_lists = []
for arr in result_arrays:
raw_vals = arr.tolist() if hasattr(arr, "tolist") else arr
result_lists.append(raw_vals if isinstance(raw_vals, list) else [raw_vals])
# 入力値が有限でも、値が極端に大きいと計算の途中で桁あふれ(オーバーフロー)し、
# 結果が無限大やNaNになるため、エラーとします。
for vals in result_lists:
for res_val in vals:
if not (-float("inf") < res_val < float("inf")):
raise ValueError(f"{func_name}: 計算結果が桁あふれしました。入力値の大きさを確認してください。")
# 基準入力がスカラー値(または0次元ndarray)なのに、計算結果が複数要素になっている場合は、
# 結果の一部が失われてしまうため、エラーとします。
# (_to_array_1dsim_com を使用しない場合に、スカラー値とndarrayが混在していると、ここで検出されます)
ref_is_scalar = not isinstance(ref_input, (list, tuple)) and getattr(ref_input, "ndim", 0) != 1
if ref_is_scalar and any(len(vals) != 1 for vals in result_lists):
raise ValueError(f"{func_name}: 入力値の要素数が一致していません。")
# 出力形式は ref_input の形式(型)のみで決定します。
if isinstance(ref_input, np.ndarray):
# 0次元のndarrayで入力された場合は、0次元のndarrayで返します。
if ref_input.ndim == 0:
res = tuple(np.array(vals[0]) for vals in result_lists)
else:
res = tuple(np.array(vals) for vals in result_lists)
elif isinstance(ref_input, list):
res = tuple(vals for vals in result_lists)
elif isinstance(ref_input, tuple):
res = tuple(tuple(vals) for vals in result_lists)
else:
# スカラー値(数値など)で入力された場合
res = tuple(vals[0] for vals in result_lists)
return res[0] if len(res) == 1 else res▶ 使用例
前述の計算関数を使って
動作を確認するためのテストコードです。
1次元も多次元も、
入力の形式に合わせて
正しく計算できていることが分かります。
# ===== 1次元のテスト(スカラー入力、v_b省略) =====
res_1d = calc_viscous_drag(0.5, 5.0)
print("1D Result:", res_1d, "\n")
# ===== 多次元のテスト(ndarray入力) =====
res_nd = calc_viscous_drag(np.array([0.5, 0.5, 0.5]), np.array([5.0, 5.0*10, 5.0*100]), np.array([0.0, 0.0, 0.0]))
print("ndarray Result:", res_nd)▶ Python関数+使用例
先ほどの関数を
すぐに実行できるようにまとめました。
速度差と粘性抵抗力の関係を描くグラフ付きです。
よろしければご活用ください!
☕ ちょっとした小話
粘性抵抗力は
物理モデリングでよく使われます。
動きを抑えられるので、
振動を減衰させるだけでなく、
数値計算の発散を防ぐためにも使われます。
ちなみに
入力の粘性係数(c)は、
実験的に求める値です。
もし「机上計算だけで求めたい!」と
声高に発言する人がいたら、
あまり実務経験がないと思われます。
このあたりのマニアックなお話は、
またいずれ!
🔗 こんな記事も書いてます
- ここで紹介した関数を使った記事を作成したら追記する予定です。
最後までお読みいただき
ありがとうございます!🙇♂️
少しでも参考になりましたら、
SNSでシェアしていただけると
次の記事を作成する励みになります!

