Feature description.
There are some cases where it would be beneficial to initialize wecopttool.pto.PTO with a matrix in transmission (or "transfer") form instead of pto_impedance.
Issue addressed.
If you want to model a PTO without gyrating effect, the PTO impedance matrix is not defined, see
Coe_2024. This could be the case when combining some transformative effect in the PTO with a loss map.
In the wecopttool.pto module we also only use the impedance matrix to compute
|
impedance_abcd = _make_abcd(impedance, ndof) |
|
self._transfer_mat = _make_mimo_transfer_mat(impedance_abcd, ndof) |
This
_transfer_mat is the
$[\boldsymbol{b}]$ in Coe_2024.
Describe the solution you'd like
We could make a PTO subclass with new __init__ method.
Something like:
class PTO_abcd(PTO):
"""A power take-off (PTO) object defined with transmission instead of impedance."""
def __init__(self,
ndof: int,
kinematics: Union[TStateFunction, np.ndarray],
controller: Optional[TStateFunction] = None,
transmission: Optional[np.ndarray] = None, # Changed from impedance to transmission
loss: Optional[TLOSS] = None,
names: Optional[list[str]] = None) -> None:
"""Create a PTO_abcd object.
The :py:class:`wecopttool.pto.PTO_abcd` class describes the
kinematics, control logic, transmission and/or non-linear power
loss of a power take-off system.
"""
self._ndof = ndof
# names
if names is None:
names = [f'PTO_{i}' for i in range(ndof)]
elif ndof == 1 and isinstance(names, str):
names = [names]
self._names = names
# kinematics
if callable(kinematics):
def kinematics_fun(wec, x_wec, x_opt, waves, nsubsteps=1):
pos_wec = wec.vec_to_dofmat(x_wec)
tmat = self._tmat(wec, nsubsteps)
pos_wec_td = np.dot(tmat, pos_wec)
return kinematics(pos_wec_td)
else:
def kinematics_fun(wec, x_wec, x_opt, waves, nsubsteps=1):
n = wec.nt*nsubsteps
return np.repeat(kinematics[:, :, np.newaxis], n, axis=-1)
self._kinematics = kinematics_fun
# controller
if controller is None:
controller = controller_unstructured
def force(wec, x_wec, x_opt, waves, nsubsteps=1):
return controller(self, wec, x_wec, x_opt, waves, nsubsteps)
self._force = force
# power
if transmission is not None:
check_1 = transmission.shape[0] == transmission.shape[1] == 2*self.ndof
check_2 = len(transmission.shape) == 3
if not (check_1 and check_2):
raise TypeError(
"Transmission should have size [2*ndof, 2*ndof, nfreq]"
)
# self._transfer_mat = transmission
self._transfer_mat = _make_mimo_transfer_mat(transmission, ndof)
else:
self._transfer_mat = None
self._impedance = 1 #should never be used in actual calcs, but is argument in if statement for post_porcessing
self._loss = loss
In the quick and dirty solution above the
self._impedance = 1 #should never be used in actual calcs, but is argument in if statement for post_porcessing
is not very clean, but required for post processing
|
if self.impedance is not None: |
So we want to consider changing the
wecopttool.pto as well.
Interest in leading this feature development?
I can lead, but I think we need to discuss the usefulness and general applicability
Feature description.
There are some cases where it would be beneficial to initialize
wecopttool.pto.PTOwith a matrix in transmission (or "transfer") form instead ofpto_impedance.Issue addressed.
If you want to model a PTO without gyrating effect, the PTO impedance matrix is not defined, see
Coe_2024. This could be the case when combining some transformative effect in the PTO with a loss map.
In the
wecopttool.ptomodule we also only use theimpedancematrix to computeWecOptTool/wecopttool/pto.py
Lines 145 to 146 in cde6b77
This
_transfer_matis theDescribe the solution you'd like
We could make a PTO subclass with new
__init__method.Something like:
In the quick and dirty solution above the
is not very clean, but required for post processing
WecOptTool/wecopttool/pto.py
Line 793 in cde6b77
So we want to consider changing the
wecopttool.ptoas well.Interest in leading this feature development?
I can lead, but I think we need to discuss the usefulness and general applicability