Đối với bài đăng này, y = f (t) trong đó t là tham số bạn thay đổi (thời gian / tiến độ) và y là khoảng cách đến mục tiêu. Vì vậy, tôi sẽ nói về các điểm trên các ô 2D trong đó trục ngang là thời gian / tiến độ và chiều dọc là khoảng cách.
Tôi nghĩ bạn có thể tạo một đường cong Bezier hình khối với điểm đầu tiên tại (0, 1) và điểm thứ tư (cuối cùng) tại (1, 0). Hai điểm giữa có thể được đặt ngẫu nhiên (x = rand, y = rand) trong hình chữ nhật 1-1 này. Tôi không thể xác minh điều này một cách phân tích, nhưng chỉ từ việc chơi xung quanh với một applet (vâng, hãy tiếp tục và cười) có vẻ như đường cong Bezier sẽ không bao giờ giảm với một ràng buộc như vậy.
Đây sẽ là hàm cơ bản b (p1, p2) của bạn cung cấp đường dẫn không giảm từ điểm p1 đến điểm p2.
Bây giờ bạn có thể tạo ab (p (1) = (0, 1), p (n) = (1, 0)) và chọn một số p (i) dọc theo đường cong này sao cho 1
Về cơ bản, bạn đang tạo một đường dẫn "chung", sau đó chia nó thành các phân đoạn và tạo lại mỗi phân đoạn.
Vì bạn muốn có một hàm toán học: Giả sử quy trình trên được đóng gói thành một hàm y = f (t, s) cung cấp cho bạn khoảng cách tại t cho hàm của hạt giống s. Bạn sẽ cần:
- 4 số ngẫu nhiên để đặt 2 điểm giữa của spline Bezier chính (từ (0, 1) đến (1, 0))
- n-1 số cho giới hạn của mỗi phân đoạn nếu bạn có n phân đoạn (phân đoạn đầu tiên luôn bắt đầu tại (0, 1) tức là t = 0 và kết thúc cuối cùng tại (1,0) tức là t = 1)
- 1 số nếu bạn muốn chọn ngẫu nhiên số lượng phân khúc
- Thêm 4 số để đặt các điểm giữa của spline của đoạn mà t của bạn hạ cánh tại
Vì vậy, mỗi hạt giống phải cung cấp một trong những điều sau đây:
- 7 + n số thực từ 0 đến 1 (nếu bạn muốn kiểm soát số lượng phân khúc)
- 7 số thực và một số nguyên lớn hơn 1 (cho một số phân đoạn ngẫu nhiên)
Tôi tưởng tượng bạn có thể thực hiện một trong hai điều này bằng cách đơn giản là cung cấp một mảng các số làm hạt giống. Ngoài ra, bạn có thể làm một cái gì đó như cung cấp một số s làm hạt giống, sau đó gọi trình tạo số ngẫu nhiên tích hợp với rand (s), rand (s + 1), rand (s + 2), v.v. s và sau đó tiếp tục gọi rand.NextNumber).
Lưu ý rằng mặc dù toàn bộ hàm f (t, s) được tạo thành từ nhiều phân đoạn, bạn chỉ đánh giá một phân đoạn cho mỗi t. Bạn sẽ cần phải liên tục tính toán ranh giới của các phân đoạn bằng phương pháp này, bởi vì bạn sẽ phải sắp xếp chúng để đảm bảo không có hai phân đoạn trùng nhau. Bạn có thể có thể tối ưu hóa và loại bỏ công việc bổ sung này và chỉ tìm thấy các điểm cuối của một phân đoạn cho mỗi cuộc gọi, nhưng điều này đối với tôi không rõ ràng ngay bây giờ.
Ngoài ra, đường cong Bezier là không cần thiết, bất kỳ spline hành xử phù hợp sẽ làm.
Tôi đã tạo một triển khai Matlab mẫu.
Hàm Bezier (vector hóa):
function p = bezier(t, points)
% p = bezier(t, points) takes 4 2-dimensional points defined by 2-by-4 matrix
% points and gives the value of the Bezier curve between these points at t.
%
% t can be a number or 1-by-n vector. p will be an n-by-2 matrix.
coeffs = [
(1-t').^3, ...
3*(1-t').^2.*t', ...
3*(1-t').*t'.^2, ...
t'.^3
];
p = coeffs * points;
end
Hàm Bezier ghép được mô tả ở trên (cố tình bỏ trống không được ghi chú để làm rõ mức độ cần thiết cho mỗi cuộc gọi):
function p = bezier_compound(t, ends, s)
% p = bezier(t, points) takes 2 2-dimensional endpoints defined by a 2-by-2
% matrix ends and gives the value of a "compound" Bezier curve between
% these points at t.
%
% t can be a number or 1-by-n vector. s must be a 1-by-7+m vector of random
% numbers from 0 to 1. p will be an n-by-2 matrix.
%% Generate a list of segment boundaries
seg_bounds = [0, sort(s(9:end)), 1];
%% Find which segment t falls on
seg = find(seg_bounds(1:end-1)<=t, 1, 'last');
%% Find the points that segment boundaries evaluate to
points(1, :) = ends(1, :);
points(2, :) = [s(1), s(2)];
points(3, :) = [s(3), s(4)];
points(4, :) = ends(2, :);
p1 = bezier(seg_bounds(seg), points);
p4 = bezier(seg_bounds(seg+1), points);
%% Random middle points
p2 = [s(5), s(6)] .* (p4-p1) + p1;
p3 = [s(7), s(8)] .* (p4-p1) + p1;
%% Gather together these points
p_seg = [p1; p2; p3; p4];
%% Find what part of this segment t falls on
t_seg = (t-seg_bounds(seg))/(seg_bounds(seg+1)-seg_bounds(seg));
%% Evaluate
p = bezier(t_seg, p_seg);
end
Kịch bản vẽ đồ thị cho hàm ngẫu nhiên (lưu ý rằng đây là nơi duy nhất gọi hàm ngẫu nhiên, các biến ngẫu nhiên cho tất cả các mã khác được truyền từ một mảng ngẫu nhiên này):
clear
clc
% How many samples of the function to plot (higher = higher resolution)
points = 1000;
ends = [
0, 0;
1, 1;
];
% a row vector of 12 random points
r = rand(1, 12);
p = zeros(points, 2);
for i=0:points-1
t = i/points;
p(i+1, :) = bezier_compound(t, ends, r);
end
% We take a 1-p to invert along y-axis here because it was easier to
% implement a function for slowly moving away from a point towards another.
scatter(p(:, 1), 1-p(:, 2), '.');
xlabel('Time');
ylabel('Distance to target');
Đây là một đầu ra mẫu:
Nó dường như đáp ứng hầu hết các tiêu chí của bạn. Tuy nhiên:
- Có "góc". Điều này có thể được chấp nhận bằng cách sử dụng các đường cong Bezier phù hợp hơn.
- Nó "rõ ràng" trông giống như splines, mặc dù bạn thực sự không thể đoán nó sẽ làm gì sau một khoảng thời gian không tầm thường trừ khi bạn biết hạt giống.
- Nó rất hiếm khi lệch quá nhiều về góc (có thể được sửa bằng cách chơi với phân phối của trình tạo hạt giống).
- Hàm Bezier hình khối không thể đạt đến một khu vực gần góc với các ràng buộc này.
f'(x)>0
, vì vậy việc tích hợp chuẩn hóa giá trị tuyệt đối của bất kỳ hàm nhiễu nào sẽ đáp ứng tất cả các yêu cầu của bạn. Thật không may, tôi không biết cách dễ dàng nào để tính toán điều đó, nhưng có lẽ người khác cũng vậy. :)