Suppose the total duration is n
, rather than 20. Your function does two things as intensity i
changes:
- First,
k(i)
, the number of cycles changes. It starts off with k(0) = 1
, peaks at k(0.5) = n/2
, then drops to k(1) = 1
.
- Second, the ratio
r(i)
of time on/time off in each pair changes. If we have a cycle [a, b]
, with a
being the time on and b
the time off, then r(i)*a = b
. Going by your example, we have r(0) = 0
, r(0.5) = 1
, then an asymptote up to r(1) = infinity
There are a lot of functions that could match k(i)
and r(i)
, but let's stick with simple ones:
k(i) = (int) (n/2 - (n-2)*|i - 0.5|) r(i) = 1 / (1.000001 - i) - 1
where |x|
denotes the absolute value of x
. I've also substituted 1
for 1.000001
in r
's denominator so that we won't have to deal with divide-by-zero errors.
Now if the cycles need to sum to n
, then the length of any one cycle [a, b]
is n/k(i)
. Since we also have that r(i)*a = b
, it follows that
a = n/(k*(1+r)) b = r*a
and to form the array for intensity i
, we just have to repeat [a, b]
k
times. Here's an example of the output for n = 20
:
Intensity: 0.00, Timings: 20.0, 0.0
Intensity: 0.05, Timings: 9.5, 0.5, 9.5, 0.5
Intensity: 0.10, Timings: 6.0, 0.7, 6.0, 0.7, 6.0, 0.7
Intensity: 0.15, Timings: 4.3, 0.7, 4.3, 0.7, 4.3, 0.7, 4.3, 0.7
Intensity: 0.20, Timings: 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8
Intensity: 0.25, Timings: 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8
Intensity: 0.30, Timings: 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9
Intensity: 0.35, Timings: 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9
Intensity: 0.40, Timings: 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9
Intensity: 0.45, Timings: 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9
Intensity: 0.50, Timings: 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
Intensity: 0.55, Timings: 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1
Intensity: 0.60, Timings: 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3
Intensity: 0.65, Timings: 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6
Intensity: 0.70, Timings: 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0
Intensity: 0.75, Timings: 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5
Intensity: 0.80, Timings: 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2
Intensity: 0.85, Timings: 0.8, 4.2, 0.8, 4.2, 0.8, 4.2, 0.8, 4.2
Intensity: 0.90, Timings: 0.7, 6.0, 0.7, 6.0, 0.7, 6.0
Intensity: 0.95, Timings: 0.5, 9.5, 0.5, 9.5
Intensity: 1.00, Timings: 0.0, 20.0
And here's the shoddy code:
public void Test()
{
foreach (var intensity in Enumerable.Range(0, 20 + 1).Select(i => i/20f))
{
var cycle = new List<float> {a(intensity), b(intensity)};
var timings = Enumerable.Repeat(cycle, k(intensity)).SelectMany(timing => timing).ToArray();
SDebug.WriteLine(
String.Format("Intensity: {0,2:N2}, Timings: ", intensity) +
String.Join(", ", timings.Select(timing => String.Format("{0,2:N1}", timing))));
}
}
private static float r(float i)
{
return 1f/(1.000001f - i) - 1f;
}
private static int k(float i)
{
return Mathf.CeilToInt(10 - 18*Mathf.Abs(i - 0.5f));
}
private static float a(float i)
{
return 20/(k(i)*(1 + r(i)));
}
private static float b(float i)
{
return r(i)*a(i);
}
The best thing to do from here is mess with the function r(i)
. If you can though, first relax the first and last timings to be [n, 1]
and [1, n]
, which'll save you from having to bother with asymptotes.