Reputation: 1257
I am trying to find a way to create a trajectory between two points with specified speeds in a vectorized way.
For example start point is [0, 0]
and end point is [25, 15]
.
Next I need to specified speeds [25, 4, 8, 2]
and their corresponding probabilities [0.4, 0.2, 0.3, 0.1]
. So for each time interval, speed can be 25 m/s
(with probability 40%
), or 4 m/s
(probability 20%
), etc.
Here is an example of desired output:
[[0,0], [3,1], [6,3.5], [12,7], [14,8], [19,11], [25,15]]
As you see object moved from [0,0]
to [3,1]
with speed e.g. 4 m/s
, next from [3,1]
to [6,3.5]
with speed e.g. 8 m/s
, etc.
(note it is just example with approximate coordinates)
Here is my attempt to create a script to generate such trajectories:
from math import asin, degrees
ue_speed = [3, 4, 8, 25]
ue_speed_prob = [0.4, 0.2, 0.3, 0.1]
steps = 20 # this parameter hardcoded and should be removed
square_size = 100 # need for scaling
time_interval = 100 # need for scaling
start_coord = [0, 0]
end_coord = [25, 15]
b = end_coord[0] - start_coord[0]
a = end_coord[1] - start_coord[1]
c = (a**2 + b**2)**0.5
theta = [degrees(asin(a/c))] * (steps - 1)
start = [start_coord]
v = np.random.choice(ue_speed, size=steps-1, p=ue_speed_prob)
R = np.expand_dims(((v * time_interval) / square_size), axis=-1)
xy = np.dstack((np.cos(theta), np.sin(theta))) * R
trajectory_ = np.hstack((np.zeros((1, 1, 2)), np.cumsum(xy, axis=1)))
trajectory = np.abs(trajectory_[0] + start )
Output:
array([[ 0. , 0. ],
[ 2.69850332, 1.31075545],
[ 5.39700664, 2.62151089],
[ 8.09550996, 3.93226634],
[10.79401327, 5.24302179],
[14.3920177 , 6.99069571],
[21.58802655, 10.48604357],
[24.28652987, 11.79679902],
[26.98503318, 13.10755446],
[30.58303761, 14.85522839],
[33.28154093, 16.16598384],
[35.98004425, 17.47673929],
[38.67854756, 18.78749473],
[45.87455641, 22.28284259],
[49.47256084, 24.03051652],
[56.66856969, 27.52586437],
[59.36707301, 28.83661982],
[62.06557632, 30.14737527],
[65.66358075, 31.8950492 ],
[69.26158517, 33.64272312]])
Output is not correct. End point should be [25, 15]
.
Is it possible to change somehow code above to generate correct results?
Upvotes: 1
Views: 2781
Reputation: 3845
First I think you were fooled by a simple but yet subtle mathematical error you made. In your illustration, you show the first path segment to be from (0,0) to (3,1). This however does not correspond to a "speed" of 4, as your object moves along the diagonal path. For the first line segment you would get a speed of
v = (1**2 + 3**2)**0.5 (= 3.162)
Even less obvious to me is, how you got to a speed of 4 in the second line segment, but you mentioned approximate coordinates, so I will assume, that these are not the exact coordinates that you are looking for.
That put aside, you will not generally be able to get to the exact ending point with different specified speeds, so I will show a solution, that gets just past the ending point and stops there.
import numpy as np
ue_speed = [3, 4, 8, 25]
ue_speed_prob = [0.4, 0.2, 0.3, 0.1]
square_size = 100 # need for scaling
time_interval = 100 # need for scaling
start_coord = [0, 0]
end_coord = [25, 15]
b = end_coord[0] - start_coord[0]
a = end_coord[1] - start_coord[1]
c = (a**2+b**2)**0.5
theta = np.arctan2(a,b)
steps = int(c//(min(ue_speed)*time_interval/square_size) + 1) # fixed scaling issue
v = np.random.choice(ue_speed, size=steps, p=ue_speed_prob)
R = np.cumsum((v * time_interval) / square_size)
R = R[:np.argmax(R>c)+1]
P = np.column_stack((R*np.cos(theta)+start_coord[0],
R*np.sin(theta)+start_coord[1]))
trajectory = P
This will print trajectory
as
[[ 2.57247878 1.54348727]
[ 5.14495755 3.08697453]
[12.00490096 7.20294058]
[33.4422241 20.06533446]]
Note: You also made a very serious error in your code, when your converted the result of the math.asin
to degrees and then used it again in trigonometric functions like np.sin
and np.cos
. I strongly recommand you to stick to radiant angle values and only convert them to degrees if you want to print them out.
Also I recommend the use of an arctan2
like function, to correctly get the angle of an x and y coordinate, as this will also work for negative x directions.
Upvotes: 1
Reputation: 27966
Correct, vectorized solution follows.
You will notice one of the samples is the end point. You can play with the numbers.
Also, I think it is best staying with Cartesian coordinates. No need to work with angles at all for this.
import numpy as np
# ue_speed = np.array([3, 4, 8, 25])
ue_speed = np.array([1, 1, 1, 1])
ue_speed_prob = np.array([0.4, 0.2, 0.3, 0.1])
steps = 200 # this parameter hardcoded and should be removed
time_interval = 1 # need for scaling
start_coord = np.array([0, 0])
end_coord = np.array([25, 15])
r_direction = end_coord - start_coord
r_hat = r_direction / np.linalg.norm(r_direction)
v = np.random.choice(ue_speed, size=steps + 1, p=ue_speed_prob)
dr = v * time_interval
dr_vecs = r_hat[np.newaxis, :] * dr[:, np.newaxis]
r_vecs = np.cumsum(dr_vecs, axis=0)
r = start_coord + r_vecs
print(r_vecs)
With given parameters, this outputs
[[ 0.85749293 0.51449576]
[ 1.71498585 1.02899151]
[ 2.57247878 1.54348727]
[ 3.4299717 2.05798302]
[ 4.28746463 2.57247878]
[ 5.14495755 3.08697453]
[ 6.00245048 3.60147029]
[ 6.85994341 4.11596604]
[ 7.71743633 4.6304618 ]
[ 8.57492926 5.14495755]
[ 9.43242218 5.65945331]
[ 10.28991511 6.17394907]
[ 11.14740803 6.68844482]
[ 12.00490096 7.20294058]
[ 12.86239389 7.71743633]
[ 13.71988681 8.23193209]
[ 14.57737974 8.74642784]
[ 15.43487266 9.2609236 ]
[ 16.29236559 9.77541935]
[ 17.14985851 10.28991511]
[ 18.00735144 10.80441086]
[ 18.86484437 11.31890662]
[ 19.72233729 11.83340237]
[ 20.57983022 12.34789813]
[ 21.43732314 12.86239389]
[ 22.29481607 13.37688964]
[ 23.15230899 13.8913854 ]
[ 24.00980192 14.40588115]
[ 24.86729485 14.92037691]
[ 25.72478777 15.43487266]
[ 26.5822807 15.94936842]
[ 27.43977362 16.46386417]
[ 28.29726655 16.97835993]
[ 29.15475947 17.49285568]
[ 30.0122524 18.00735144]
[ 30.86974533 18.5218472 ]
[ 31.72723825 19.03634295]
[ 32.58473118 19.55083871]
[ 33.4422241 20.06533446]
[ 34.29971703 20.57983022]
[ 35.15720995 21.09432597]
[ 36.01470288 21.60882173]
[ 36.87219581 22.12331748]
[ 37.72968873 22.63781324]
[ 38.58718166 23.15230899]
[ 39.44467458 23.66680475]
[ 40.30216751 24.18130051]
[ 41.15966043 24.69579626]
[ 42.01715336 25.21029202]
[ 42.87464629 25.72478777]
[ 43.73213921 26.23928353]
[ 44.58963214 26.75377928]
[ 45.44712506 27.26827504]
[ 46.30461799 27.78277079]
[ 47.16211091 28.29726655]
[ 48.01960384 28.8117623 ]
[ 48.87709677 29.32625806]
[ 49.73458969 29.84075381]
[ 50.59208262 30.35524957]
[ 51.44957554 30.86974533]
[ 52.30706847 31.38424108]
[ 53.16456139 31.89873684]
[ 54.02205432 32.41323259]
[ 54.87954725 32.92772835]
[ 55.73704017 33.4422241 ]
[ 56.5945331 33.95671986]
[ 57.45202602 34.47121561]
[ 58.30951895 34.98571137]
[ 59.16701187 35.50020712]
[ 60.0245048 36.01470288]
[ 60.88199773 36.52919864]
[ 61.73949065 37.04369439]
[ 62.59698358 37.55819015]
[ 63.4544765 38.0726859 ]
[ 64.31196943 38.58718166]
[ 65.16946235 39.10167741]
[ 66.02695528 39.61617317]
[ 66.88444821 40.13066892]
[ 67.74194113 40.64516468]
[ 68.59943406 41.15966043]
[ 69.45692698 41.67415619]
[ 70.31441991 42.18865195]
[ 71.17191283 42.7031477 ]
[ 72.02940576 43.21764346]
[ 72.88689869 43.73213921]
[ 73.74439161 44.24663497]
[ 74.60188454 44.76113072]
[ 75.45937746 45.27562648]
[ 76.31687039 45.79012223]
[ 77.17436331 46.30461799]
[ 78.03185624 46.81911374]
[ 78.88934917 47.3336095 ]
[ 79.74684209 47.84810525]
[ 80.60433502 48.36260101]
[ 81.46182794 48.87709677]
[ 82.31932087 49.39159252]
[ 83.17681379 49.90608828]
[ 84.03430672 50.42058403]
[ 84.89179965 50.93507979]
[ 85.74929257 51.44957554]
[ 86.6067855 51.9640713 ]
[ 87.46427842 52.47856705]
[ 88.32177135 52.99306281]
[ 89.17926427 53.50755856]
[ 90.0367572 54.02205432]
[ 90.89425013 54.53655008]
[ 91.75174305 55.05104583]
[ 92.60923598 55.56554159]
[ 93.4667289 56.08003734]
[ 94.32422183 56.5945331 ]
[ 95.18171475 57.10902885]
[ 96.03920768 57.62352461]
[ 96.89670061 58.13802036]
[ 97.75419353 58.65251612]
[ 98.61168646 59.16701187]
[ 99.46917938 59.68150763]
[100.32667231 60.19600339]
[101.18416523 60.71049914]
[102.04165816 61.2249949 ]
[102.89915109 61.73949065]
[103.75664401 62.25398641]
[104.61413694 62.76848216]
[105.47162986 63.28297792]
[106.32912279 63.79747367]
[107.18661571 64.31196943]
[108.04410864 64.82646518]
[108.90160157 65.34096094]
[109.75909449 65.85545669]
[110.61658742 66.36995245]
[111.47408034 66.88444821]
[112.33157327 67.39894396]
[113.18906619 67.91343972]
[114.04655912 68.42793547]
[114.90405205 68.94243123]
[115.76154497 69.45692698]
[116.6190379 69.97142274]
[117.47653082 70.48591849]
[118.33402375 71.00041425]
[119.19151667 71.51491 ]
[120.0490096 72.02940576]
[120.90650253 72.54390152]
[121.76399545 73.05839727]
[122.62148838 73.57289303]
[123.4789813 74.08738878]
[124.33647423 74.60188454]
[125.19396715 75.11638029]
[126.05146008 75.63087605]
[126.90895301 76.1453718 ]
[127.76644593 76.65986756]
[128.62393886 77.17436331]
[129.48143178 77.68885907]
[130.33892471 78.20335482]
[131.19641763 78.71785058]
[132.05391056 79.23234634]
[132.91140349 79.74684209]
[133.76889641 80.26133785]
[134.62638934 80.7758336 ]
[135.48388226 81.29032936]
[136.34137519 81.80482511]
[137.19886811 82.31932087]
[138.05636104 82.83381662]
[138.91385397 83.34831238]
[139.77134689 83.86280813]
[140.62883982 84.37730389]
[141.48633274 84.89179965]
[142.34382567 85.4062954 ]
[143.20131859 85.92079116]
[144.05881152 86.43528691]
[144.91630445 86.94978267]
[145.77379737 87.46427842]
[146.6312903 87.97877418]
[147.48878322 88.49326993]
[148.34627615 89.00776569]
[149.20376907 89.52226144]
[150.061262 90.0367572 ]
[150.91875493 90.55125296]
[151.77624785 91.06574871]
[152.63374078 91.58024447]
[153.4912337 92.09474022]
[154.34872663 92.60923598]
[155.20621955 93.12373173]
[156.06371248 93.63822749]
[156.92120541 94.15272324]
[157.77869833 94.667219 ]
[158.63619126 95.18171475]
[159.49368418 95.69621051]
[160.35117711 96.21070626]
[161.20867003 96.72520202]
[162.06616296 97.23969778]
[162.92365589 97.75419353]
[163.78114881 98.26868929]
[164.63864174 98.78318504]
[165.49613466 99.2976808 ]
[166.35362759 99.81217655]
[167.21112051 100.32667231]
[168.06861344 100.84116806]
[168.92610637 101.35566382]
[169.78359929 101.87015957]
[170.64109222 102.38465533]
[171.49858514 102.89915109]
[172.35607807 103.41364684]]
BONUS
if you want to not hard code the steps, you can do
steps = int((np.linalg.norm(end_coord - start_coord) / np.min(ue_speed)) / time_interval)
steps = steps if steps > 0 else 1
and the last sample will be approximately the end coord.
Upvotes: 0