Untuk posting ini, y = f (t) di mana t adalah parameter yang Anda variasikan (waktu / kemajuan) dan y adalah jarak ke target. Jadi saya akan berbicara dalam hal titik pada plot 2D di mana sumbu horizontal adalah waktu / kemajuan dan vertikal adalah jarak.
Saya pikir Anda bisa membuat kurva Bezier kubik dengan titik pertama di (0, 1) dan keempat (terakhir) titik di (1, 0). Dua titik tengah dapat ditempatkan secara acak (x = rand, y = rand) dalam kotak 1-by-1 ini. Saya tidak dapat memverifikasi ini secara analitis, tetapi hanya dari bermain-main dengan applet (yeah, silakan saja dan tertawa) tampaknya kurva Bezier tidak akan pernah berkurang dengan kendala seperti itu.
Ini akan menjadi fungsi dasar Anda b (p1, p2) yang menyediakan jalur non-menurun dari titik p1 ke titik p2.
Sekarang Anda dapat menghasilkan ab (p (1) = (0, 1), p (n) = (1, 0)) dan memilih sejumlah p (i) sepanjang kurva ini sehingga 1
Pada dasarnya, Anda membuat satu jalur "umum", dan kemudian memecahnya menjadi segmen dan meregenerasi setiap segmen.
Karena Anda menginginkan fungsi matematika: Misalkan prosedur di atas dikemas ke dalam satu fungsi y = f (t, s) yang memberi Anda jarak pada t untuk fungsi seed s. Anda akan perlu:
- 4 angka acak untuk menempatkan 2 titik tengah dari spline Bezier utama (dari (0, 1) hingga (1, 0))
- nomor n-1 untuk batas setiap segmen jika Anda memiliki n segmen (segmen pertama selalu dimulai pada (0, 1) yaitu t = 0 dan ujung terakhir pada (1,0) yaitu t = 1)
- 1 angka jika Anda ingin mengacak jumlah segmen
- 4 angka lebih banyak untuk menempatkan titik tengah spline segmen tempat Anda akan t
Jadi setiap benih harus menyediakan salah satu dari yang berikut ini:
- 7 + n bilangan real antara 0 dan 1 (jika Anda ingin mengontrol jumlah segmen)
- 7 bilangan real dan satu bilangan bulat lebih besar dari 1 (untuk jumlah segmen acak)
Saya membayangkan Anda dapat mencapai salah satu dari ini dengan hanya menyediakan array angka sebagai benih. Atau, Anda bisa melakukan sesuatu seperti memasok satu angka s sebagai seed, dan kemudian memanggil generator angka acak bawaan dengan rand, rand (s + 1), rand (s + 2) dan sebagainya (atau menginisialisasi dengan s dan kemudian terus memanggil rand.NextNumber).
Perhatikan bahwa meskipun seluruh fungsi f (t, s) terdiri dari banyak segmen, Anda hanya mengevaluasi satu segmen untuk setiap t. Anda akan perlu berulang kali menghitung batas-batas segmen dengan metode ini, karena Anda akan harus menyortir mereka untuk memastikan tidak ada dua segmen tumpang tindih. Anda mungkin dapat mengoptimalkan dan menyingkirkan pekerjaan tambahan ini dan hanya menemukan titik akhir dari satu segmen untuk setiap panggilan, tetapi tidak jelas bagi saya saat ini.
Juga, kurva Bezier tidak diperlukan, spline berperilaku yang sesuai akan dilakukan.
Saya membuat contoh implementasi Matlab.
Fungsi Bezier (vektor):
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
Fungsi majemuk Bezier yang dijelaskan di atas (sengaja dibiarkan tidak terverifikasi untuk memperjelas berapa banyak evaluasi yang diperlukan untuk setiap panggilan):
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
Script yang memplot fungsi untuk seed acak (perhatikan bahwa ini adalah satu-satunya tempat di mana fungsi acak dipanggil, variabel acak ke semua kode lain disebarkan dari satu array acak ini):
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');
Berikut ini contoh keluaran:
Tampaknya memenuhi sebagian besar kriteria Anda. Namun:
- Ada "sudut". Ini mungkin bisa diterima dengan menggunakan kurva Bezier lebih tepat.
- Ini "jelas" terlihat seperti splines, meskipun Anda tidak bisa menebak apa yang akan dilakukan setelah periode waktu yang tidak sepele kecuali Anda tahu benihnya.
- Sangat jarang menyimpang terlalu banyak ke sudut (dapat diperbaiki dengan bermain dengan distribusi generator benih).
- Fungsi Bezier kubik tidak dapat mencapai area dekat sudut mengingat kendala ini.
f'(x)>0
, sehingga integrasi normal dari nilai absolut dari setiap fungsi noise akan memenuhi semua kebutuhan Anda. Sayangnya saya tidak tahu cara mudah untuk menghitung itu, tetapi mungkin orang lain melakukannya. :)