Applying easing to a loop delay - loops

To speak simple, I am trying to figure out how to apply easing to a loop delay.
for (i := 0; i < 114; i++) {
// do a task
time.Sleep(//delay before next job)
}
As you can read it, this is very basic. Let say I want to complete the whole loop in 3s (job completion time is negligeable, t <= us). What is the proper method with Penner's Equations to calculate for each iteration the proper eased delay ?
So, with this function, to simulate an acceleration from zero-velocity, how should I use the t parameter each iteration of the loop to create the proper delay to sleep for ?
func easeInQuad(t float64) {
return math.Pow(t, 2)
}
I would be very thankfull if you could help me about this. Equations has not been a problem so far, but how to use them with my use case instead.
My question could looks like this one at first : Applying easing to setTimeout delays, within a loop
but this one does not take the total time of the loop in account.
However, I think it may be better to use equations rewritten to use only one parameter, in range [0,1] : https://gist.github.com/rezoner/713615dabedb59a15470
From my understanding, I have to calculate the abstract "percentage time elapsed", and somehow interpolate this value with an easing function.
This Node project seems to do just that : https://github.com/CharlotteGore/animation-timer, but again I can't figure out how to reproduce it.

Penner's Equations fundamentally require two parameters: the current progress, and the total possible progress. Alternatively, however, you can instead provide it with percentage-of-total-progress as a single parameter (as a value between 0 and 1), since that's what it uses the current and total to calculate anyway.
Using your original code, if you want 114 iterations to take place within 3 seconds, the easiest way is to use your iteration index as the current progress, and 114 as the total, then multiply the calculated delay factor by your total duration 3.0s.
Note, Penner's Equations calculate total displacement from start position, NOT relative displacement for each step, so you actually need to calculate that difference yourself. Thus the delay for this iteration is the total displacement (delay) for this iteration minus the total displacement for the last iteration:
func DoStuffWithEasing() {
iterations := 114
runTime := 3 * time.Second
for i := 1; i <= iterations; i++ {
// do a task
time.Sleep(easeInQuadDelay(i, iterations, runTime))
}
}
func easeInQuadDelay(c, t int, dur time.Duration) time.Duration {
if c <= 0 || t == 0 { // invalid cases
return 0
}
// This return can be a single-liner, but I split it up for clarity
// Note that time.Durations are fundamentally int64s,
// so we can easily type convert them to float64s and back
this := math.Pow(float64(c)/float64(t), 2)
last := math.Pow(float64(c-1)/float64(t), 2)
return time.Duration((this - last) * float64(dur))
}
https://play.golang.org/p/TTgZUYUvxW
Graph of the easing

I think, you can use time.Ticker.
numLoops := 144
timePerIteration := time.Duration(3) * time.Second / time.Duration(numLoops)
ticker := time.NewTicker(timePerIteration)
for i := 0; i < numLoops; i++ {
// your code
<-ticker.C
}
ticker.Stop()

Related

may you explain this algorithm of calculate to average for noise

I am working on embedded programming with written code by other people.
this algorithm be used in calculate average for mic and accelerometer
sound_value_Avg = 0;
sound_value = 0;
memset((char *)soundRaw, 0x00, SOUND_COUNT*2);
for(int i2=0; i2 < SOUND_COUNT; i2++)
{
soundRaw[i2] = analogRead(PIN_ANALOG_IN);
if (i2 == 0)
{
sound_value_Avg = soundRaw[i2];
}
else
{
sound_value_Avg = (sound_value_Avg + soundRaw[i2]) / 2;
}
}
sound_value = sound_value_Avg;
acceleromter is similar to this
n1=p1
(n2+p1)/2 = p2
(n3+p2)/2 = p3
(n4+p3)/2 = p4
...
avg(n1~nx)=px
it not seems to be correct.
can someone explain why he used this algorithm?
is it specific way for sin graph? like noise, vibration?
It appears to be a flawed attempt at maintaining a cumulative mean. The error is in believing that:
An+1 = (An + sn) / 2
when in fact it should be:
An+1 = ((An * n) + s) / (n + 1)
However it is computationally simpler to maintain a running sum and generate an average in the usual manner:
S = S + s
An = S / n
It is possible that the intent was to avoid overflow when the sum grows large, but the attempt is mathematically flawed.
To see how wrong this statement is consider:
True
n s Running Avg. (An + sn) / 2
--------------------------------------
1 20 20 20
2 21 20.5 20.25
3 22 21 20.625
In this case however, nothing is done with the intermediate mean value, so you don'e in fact need to maintain a running mean at all. You simply need to accumulate a running sum and calculate the average at the end. For example:
sum = 0 ;
sound_value = 0 ;
for( int i2 = 0; i2 < SOUND_COUNT; i2++ )
{
soundRaw[i2] = analogRead( PIN_ANALOG_IN ) ;
sum += soundRaw[i2] ;
}
sound_value = sum / SOUND_COUNT ;
In this you do need to make sure that the data type forsum can accommodate a value of the maximum analogRead() return multiplied by SOUND_COUNT.
However you say that this is used for some sort of signal conditioning or processing of both a microphone and an accelerator. These devices have rather dissimilar bandwidth and dynamics, and it seems rather unlikely that the same filter would suit both. Applying robust DSP techniques such as IIR or FIR filters with suitably calculated coefficients would make a great deal more sense. You'd also need a suitable fixed sample rate that I am willing to bet is not achieved by simply reading the ADC in a loop with no specific timing

Max Min Ant System for TSP Optimisation

I have implemented an Ant System algorithm to solve the TSP which obtains tour results only about 5% longer the optimum tour (acceptable). Now I am trying to implement the similar Max Min Ant System algorithm.
The algorithm I have implements works as follows:
func UpdateMaxMin {
// decay pheromone
graph.decayPheromone()
// get best path from this iteration
bestPath = paths[0]
for path in paths {
bestPath = path.length < bestPath.length ? path : bestPath
}
// update for only the best path (sometimes use the global best)
if random(0, 10) > 8 {
graph.updatePheromone(globalBestPath)
} else {
graph.updatePheromone(bestPath)
}
// clamp pheromone levels between min and max
graph.clampPheromone()
// check for stagnation
if graph.checkStagnation() {
// update max
max = 1 / (rho * globalBestPath.Length)
// reset all pheromones to max
graph.SetPheromoneMatrix(max)
}
}
However, the algorithm stagnates far too quickly (after only a few iterations) and once it has stagnated, the max pheromone becomes a tiny number (smaller than min).
From what I have found online I am using a pheromone decay rate of rho = 0.5 and initialising max to a large number and min to
a := antCount
p := math.Pow(0.05, 1/a)
min = max * (1 - p) / (((a / 2) - 1) * p)
Besides this, the actual amount of pheromone which the best ant deposits on each edge in their tour is calculated by:
deposit = 1 / tour.Length
However, this value is much much much too small to actually create a distinct best path - for example, if the pheromone starts at 5, after the first tour it will decay to 2.5 and the best ant will lay down about 0.001 pheromone on relevant edges. Even if I multiply the deposit by the number of ants a huge number of ants is required to create a significant change.
The results of my MMAS are better than random but much worse than the vanilla AS. The MMAS constructs tours about twice as long as the optimal tour.
Could anyone point out my mistake (or suggest improvements) to my algorithm?

Printing output at every nth time step

I am a bit confused about how to write the code to implement this concept. So please help me out if anyone knows how to work around my problem.
I have a while loop to run a simulation where I want to see the diffusion of a mass of fluid for a time that is given by t_domain. The time t is incremented in steps of dt both of which are variables of the type double, however I want to take snapshots of the diffusion process only at Del_t time intervals. What I mean is that if I run my simulation for 1000 seconds where time t is incremented by 0.01 seconds, I want to take the snapshots of the diffusion process every 10 seconds.
Now what I am unable to figure out is the section of the code for the print densities at every nth time step to a file. Can someone give suggestions?
while(t<t_domain)
{
//runs a function to solve the continuity equation and Navier Stokes equation
density_solve(fdparam_1.N,r,r0,ux0,vy0,fdparam_1.Dt,fdparam_1.diff,fdparam_1.MAXIT);
//print densities at every nth time step to a file
t+=dt
}
Thanks in advance
int i = 0;
int times = 23;
while(t<t_domain)
{
//runs a function to solve the continuity equation and Navier Stokes equation
density_solve(fdparam_1.N,r,r0,ux0,vy0,fdparam_1.Dt,fdparam_1.diff,fdparam_1.MAXIT);
//print densities at every nth time step to a file
if(i++%times==0)
{
// print every 23th loop round
}
t+=dt
}
Write a if statement to check like this :
while(t<t_domain)
{
//runs a function to solve the continuity equation and Navier Stokes equation
density_solve(fdparam_1.N,r,r0,ux0,vy0,fdparam_1.Dt,fdparam_1.diff,fdparam_1.MAXIT);
if(((int)t*100)%1000==0)
{
//print densities at every nth time step to a file
}
t+=dt
}
now every time t is 10's multiple it is printed.
As your time would come in float or double with precision of 0.01 I multiply time by 100 to convert it to a workable integer.now I check if it is divisible by 100*10 i.e, 1000 to check if it is a perfect multiple of 10.To make the long story short.........
only numbers like 10.00 and 20.00 are accepted and not
numbers like 10.01 or 10.79
int iteration = 0;
const int N = 10;
while(t<t_domain)
{
...
if(0 == (iteration++ % N))
{
// will printe once every 10 iterations
printf(...);
}
}

Configuring and limiting output of PI controller

I have implemented simple PI controller, code is as follows:
PI_controller() {
// handling input value and errors
previous_error = current_error;
current_error = 0 - input_value;
// PI regulation
P = current_error //P is proportional value
I += previous_error; //I is integral value
output = Kp*P + Ki*I; //Kp and Ki are coeficients
}
Input value is always between -π and +π.
Output value must be between -4000 and +4000.
My question is - how to configure and (most importantly) limit the PI controller properly.
Too much to comment but not a definitive answer. What is "a simple PI controller"? And "how long is a piece of string"? I don't see why you (effectively) code
P = (current_error = 0 - input_value);
which simply negates the error of -π to π. You then aggregate the error with
I += previous_error;
but haven't stated the cumulative error bounds, and then calculate
output = Kp*P + Ki*I;
which must be -4000 <= output <= 4000. So you are looking for values of Kp and Ki that keep you within bounds, or perhaps don't keep you within bounds except in average conditions.
I suggest an empirical solution. Try a series of runs, filing the results, stepping the values of Kp and Ki by 5 steps each, first from extreme neg to pos values. Limit the output as you stated, counting the number of results that break the limit.
Next, halve the range of one of Kp and Ki and make a further informed choice as to which one to limit. And so on. "Divide and conquer".
As to your requirement "how to limit the PI controller properly", are you sure that 4000 is the limit and not 4096 or even 4095?
if (output < -4000) output = -4000;
if (output > 4000) output = 4000;
To configure your Kp and Ki you really should analyze the frequency response of your system and design your PI to give the desired response. To simply limit the output decide if you need to freeze the integrator, or just limit the immediate output. I'd recommend freezing the integrator.
I_tmp = previous_error + I;
output_tmp = Kp*P + Ki*I_tmp;
if( output_tmp < -4000 )
{
output = -4000;
}
else if( output_tmp > 4000 )
{
output = 4000;
}
else
{
I = I_tmp;
output = output_tmp;
}
That's not a super elegant, vetted algorithm, but it gives you an idea.
If I understand your question correctly you are asking about anti windup for your integrator.
There are more clever ways to to it, but a simple
if ( abs (I) < x)
{
I += previous_error;
}
will prevent windup of the integrator.
Then you need to figure out x, Kp and Ki so that abs(x*Ki) + abs(3.14*Kp) < 4000
[edit] Off cause as macduff states, you first need to analyse your system and choose the korrect Ki and Kp, x is the only really free variable in the above equation.

VHDL - loop failure/'empty' cycle issue

I'm not so great with VHDL and I can't really see why my code won't work. I needed an NCO, found a working program and re-worked it to fit my needs, but just noticed a bug: every full cycle there is one blank cycle.
The program takes step for argument (jump between next samples) and clock as trigger.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; --try to use this library as much as possible.
entity sinwave_new_01 is
port (clk :in std_logic;
step :in integer range 0 to 1000;
dataout : out integer range 0 to 1024
);
end sinwave_new_01;
architecture Behavioral of sinwave_new_01 is
signal i : integer range 0 to 1999:=0;
type memory_type is array (0 to 999) of integer range 0 to 1024;
--ROM for storing the sine values generated by MATLAB.
signal sine : memory_type :=(long and boring array of 1000 samples here);
begin
process(clk)
begin
--to check the rising edge of the clock signal
if(rising_edge(clk)) then
dataout <= sine(i);
i <= i+ step;
if(i > 999) then
i <= i-1000;
end if;
end if;
end process;
end Behavioral;
What do I do to get rid of that zero? It appears every full cycle - every (1000/step) pulses. It's not supposed to be there and it messes up my PWM...
From what I understand the whole block (dataout changes, it is increased, and if i>999 then i<=i-1000) executes when there is a positive edge of clock applied on the entrance...
BUT it looks like it requires one additional edge to, I don't know, reload it? Does the code execute sequentially, or are all conditions tested when the clock arrives? Am I reaching outside the table, and that's why I'm getting zeroes in that particular pulse? Program /shouldn't/ do that, as far as I understand if statement, or is it VHDL being VHDL and doing its weird stuff again.
How do I fix this bug? Guess I could add one extra clock tick every 1k/step pulses, but that's a work around and not a real solution. Thanks in advance for help.
It looks like your problem is that your variable 'i' exceeds 999 before you reset it. Remember, you're in a sequential process. 'i' doesn't get the assigned value until the next clock tick AFTER you assign it.
I think if you change this code
i <= i + step;
if (i > 999) then
i <= i-1000;
to
if ((i + step) > 999) then
i <= (i + step) - 1000;
else
i <= i + step;
you should get the behavior you're looking for.
One more thing...
Does the declaration of sine (sample array) actually creates combinatory circuit (bad) or allocates those samples in ROM memory ('good')?

Resources