Como criar valor pulsante de 0..1..0..1..0 etc por uma determinada duração?
-
26-09-2019 - |
Pergunta
Estou trabalhando em algum código onde tenho um Time
objeto com um membro time
. Time.time
Me dá tempo desde que meu aplicativo começou em segundos (valor float). Agora, quero criar um valor pulsante entre 0 e 1 e depois de 1 a 0 novamente, o que continua fazendo Thins até que o aplicativo pare.
Eu estava pensando em usar o sin (), mas não sei o que passar como parâmetros para criar esse valor pulsante.
Como eu criaria esse valor pulsante?
Atenciosamente, Pollux
Solução
Você menciona usar o sin (), então eu acho que você quer que ele pulse continuamente entre 0 e 1.
Algo assim fará:
float pulse(float time) {
const float pi = 3.14;
const float frequency = 10; // Frequency in Hz
return 0.5*(1+sin(2 * pi * frequency * time));
}
1/frequency = 0.1 second
é o período, que é o tempo entre 1's.
Outras dicas
Que tal x = 1 - x? Ou se você quiser que seja baseado no tempo, use o timer % 2
Oh, você também queria os valores entre 0 e 1. Que tal math.abs (100 - (timer % 200)) / 100 onde o timer é algo como DateTime.now.TimeOfday.TotalmillisEconds
Editar:Meus testes indicam que isso é mais que duas vezes mais rápido que o método do pecado. Para 1 milhão de iterações, o método SIN leva 0,048 segundos, enquanto o método ABS leva cerca de 0,023 segundos. Além disso, você obtém formas de onda diferentes das duas, é claro. O pecado produz uma onda senoidal, enquanto o ABS produz uma onda triangular.
static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
const int count = 1000000;
float[] results = new float[count];
for (int i = 0; i < count; i++)
{
results[i] = AbsPulse(i/1000000F);
//results[i] = SinPulse(i / 1000000F);
}
sw.Stop();
Console.WriteLine("Time Elapsed: {0} seconds", sw.Elapsed.TotalSeconds);
char[,] graph = new char[80, 20];
for (int y = 0; y <= graph.GetUpperBound(1); y++)
for (int x = 0; x <= graph.GetUpperBound(0); x++)
graph[x, y] = ' ';
for (int x = 0; x < count; x++)
{
int col = x * 80 / count;
graph[col, (int)(results[x] * graph.GetUpperBound(1))] = 'o';
}
for (int y = 0; y <= graph.GetUpperBound(1); y++)
{
for (int x = 0; x < graph.GetUpperBound(0); x++)
Console.Write(graph[x, y]);
Console.WriteLine();
}
}
static float AbsPulse(float time)
{
const int frequency = 10; // Frequency in Hz
const int resolution = 1000; // How many steps are there between 0 and 1
return Math.Abs(resolution - ((int)(time * frequency * 2 * resolution) % (resolution * 2))) / (float)resolution;
}
static float SinPulse(float time)
{
const float pi = 3.14F;
const float frequency = 10; // Frequency in Hz
return 0.5F * (1 + (float)Math.Sin(2 * pi * frequency * time));
}
Acho que uma função seno seria ideal, mas você precisa ajustar o período e a escala.
A função seno (sin(x)+1)/2
.
A função senoidal começa em zero, vai para 1 em Pi/2, zero novamente em Pi, -1 a 3*pi/2 e volta a zero a 2*pi. Escalado, o primeiro zero acontecerá em 3*pi/2 e o primeiro máximo depois disso será de 5/2*pi. Então x
na fórmula anterior é (2*time + 3) * pi/2
.
Juntando tudo: (sin((2*time.time + 3) * pi/2) + 1) / 2
Com que frequência você quer que ele pulse?
Digamos que você queira ir de 0 a 1 por mais de 10 segundos.
float pulseValueForTime(int sec) {
int pulsePoint = sec % 10;
float pulsePercent = (float)pulsePoint / (float)10;
float pulseInTermsOfPI = (pulsePercent * 2 * PI) - PI;
float sinVal = MagicalSinFunction(pulseInTermsOfPI); // what framework you use to compute sin is up to you... I'm sure you can google that!
return (sinVal + 1) / 2; // sin is between 1 and -1, translate to between 0 and 1
}
Olhe para as funções de facilidade. Eles fazem esse tipo de coisa em todos os tipos de maneiras - linear, poli, exp, pecado, etc.