Open CagtayFabry opened 4 years ago
we should be closer to this with #76
So just to get this sorted. We are aiming for some interfaces like this?
t = DynamicTranslation(x="2*t + 3", y="3", z="2*sin(t)")
m = t.interp_time(Q_([1, 2, 3], "s"))
where m
is an instance of LocalCoordinateSystem
?
Or for a rotation:
r = DynamicRotation(sequence = "xy", angles=["10*t", "5*t"], degrees=True)
ideally something like:
# omitting `TimeSeries` args but of course there would have to be a check on dimensions etc.
lcs_0 = LCS(coordinates=TimeSeries(...), orientation=TimeSeries(...))
only interpolate when requested by CSM or otherwise. Of course mix/match between discrete translation/rotation for LCS should also be viable
Creating something like DynamicRotation
would also make sense when subclassing TimeSeries
with additional restrictions (or just "easily/safely" create proper a TimeSeries
)
Not sure about the TimeSeries
here. If we have dedicated objects with an overloaded call operator I think it is okay, because it is their purpose. However, the TimeSeries
has multiple other functionalities, and making it callable would be somehow strange. Feels unintuitive. Maybe we can simply use a function of the same name that is implemented for all objects that should support this feature?
my thought was that TimeSeries
is the default object representing time dependent data so it would fit here
We only really need interp_time
from the TimeSeries
object for this
That should allow something like
ts_sine = weldx.util.sine(f=Q_(0.5 * 2 * np.pi, "Hz"), amp=Q_([[0, 0.75, 0]], "mm"))
tcp_sine = lcs(coordinates=ts_sine)
instead of
ts_sine = util.sine(f=Q_(0.5 * 2 * np.pi, "Hz"), amp=Q_([[0, 0.75, 0]], "mm"))
t = pd.timedelta_range(start=t_start, end=t_end, freq="10ms")
ts_sine_data = util.lcs_coords_from_ts(ts_sine, t)
tcp_sine = lcs(coordinates=ts_sine_data)
/maybe my *args
syntax was unfortunate in the initial example
I think I got confused about the return value of the call-operator. Got it now.
Reminder: Implement interp_like
for TimeSeries
and use it in the CSM
I started implementing this feature in PR #366. Turns out that this is rather complicated for several reasons. I decided to split the work across several PRs. The mentioned one will feature only coordinates as TimeSeries
. In a follow-up, we should discuss how to threat orientations because I am not really sure about the best approach here. Sympy supports matrices as far as I can see, but I don't know if the interfaces aren't too complex to pass them to our future user base without wrapping the important features first.
for rotations I suggest the following:
we add the ability to pass a TimeSeries
to the LCS constructor like we did with the coordinates
.
For now it should be enough to support only one very specific definition of this TimeSeries
(otherwise we would have to expose an additional API to let the user classify the format). For now the TimeSeries
should be be of shape [t,3]
and represent a xyz
Euler rotation
here is an example that defines a TimeSeries
representing a rotation of 60 deg/s
around the x-axis, -10 deg/s
around the y-axis and 1 deg/s
around the z-axis:
import pandas as pd
from weldx import MathematicalExpression, TimeSeries, WXRotation, Q_
from weldx.welding.util import sine
expr_string = "o*t"
parameters = {"o": Q_([[60, -10, 1]], "deg/s")}
expr = MathematicalExpression(expression=expr_string, parameters=parameters)
expr
#> <MathematicalExpression>
#> Expression:
#> o*t
#> Parameters:
#> o = [[ 60 -10 1]] deg / s
#>
ts_vector = TimeSeries(data=expr)
ts = ts_vector.interp_time(pd.timedelta_range(start="0s", end="5s", freq="1000ms"))
ts.data.shape
#> (6, 3)
ts.data
#> <Quantity([[ 0. -0. 0. ]
#> [ 1.04719755 -0.17453293 0.01745329]
#> [ 2.0943951 -0.34906585 0.03490659]
#> [ 3.14159265 -0.52359878 0.05235988]
#> [ 4.1887902 -0.6981317 0.06981317]
#> [ 5.23598776 -0.87266463 0.08726646]], 'dimensionless')>
rot = WXRotation.from_euler(seq="xyz", angles=ts.data, degrees=False)
rot.as_euler(seq="xyz", degrees=True)
#> array([[ 0., 0., 0.],
#> [ 60., -10., 1.],
#> [ 120., -20., 2.],
#> [ 180., -30., 3.],
#> [-120., -40., 4.],
#> [ -60., -50., 5.]])
The ts_vector
would be the input for LCS(orientation=ts_vector)
One thing I noticed:
For some reason, the Mathexpression converts back to dimensionless
(=rad
) instead of deg
, you can see that in the output of ts.data
. I am not sure if that always happens or where.
You can see that it is actually the correct rotation represented in rad
when transforming back using the WXRotation
object.
Internally in the LCS we could try to always convert to and work with rad
for interpolation just to be sure.
Similar to the astropy implementation of
DynamicMatrixTransform
I think we should consider supporting callable functions for defining translations and rotations as a future additionThese objects would return values at specific timestamps on request (in the appropriate xarray format), ideally with a similar syntax as our "data-based" coordinate systems. Schema implementation could reuse the
mathematical_expression
with matching input/output shape definitions.Some example use cases regarding welding applications:
[0, 2 * sin(t), 0]
)