a new (slightly inelegant) stab at eliminating the slow tail problem
This commit is contained in:
		
							
								
								
									
										78
									
								
								script/trapezoid_simulator.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								script/trapezoid_simulator.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
require 'pp'
 | 
			
		||||
 | 
			
		||||
def estimate_acceleration_distance(initial_rate, target_rate, acceleration) 
 | 
			
		||||
    (target_rate*target_rate-initial_rate*initial_rate)/(2*acceleration)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def intersection_distance(initial_rate, final_rate, acceleration, distance) 
 | 
			
		||||
    (2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4*acceleration)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
ACCELERATION_TICKS_PER_SECOND = 20
 | 
			
		||||
 | 
			
		||||
def trapezoid_params(step_event_count, nominal_rate, rate_delta, entry_factor, exit_factor)
 | 
			
		||||
  initial_rate = (nominal_rate * entry_factor).round
 | 
			
		||||
  final_rate = (nominal_rate * exit_factor).round
 | 
			
		||||
  acceleration_per_minute = rate_delta*ACCELERATION_TICKS_PER_SECOND*60
 | 
			
		||||
 | 
			
		||||
  accelerate_steps = 
 | 
			
		||||
    estimate_acceleration_distance(initial_rate, nominal_rate, acceleration_per_minute).round;
 | 
			
		||||
  decelerate_steps = 
 | 
			
		||||
    estimate_acceleration_distance(nominal_rate, final_rate, -acceleration_per_minute).round;
 | 
			
		||||
  
 | 
			
		||||
  # Calculate the size of Plateau of Nominal Rate. 
 | 
			
		||||
  plateau_steps = step_event_count-accelerate_steps-decelerate_steps;
 | 
			
		||||
  
 | 
			
		||||
  # Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
 | 
			
		||||
  # have to use intersection_distance() to calculate when to abort acceleration and start braking 
 | 
			
		||||
  # in order to reach the final_rate exactly at the end of this block.
 | 
			
		||||
  if (plateau_steps < 0)
 | 
			
		||||
    accelerate_steps = 
 | 
			
		||||
      intersection_distance(initial_rate, final_rate, acceleration_per_minute, step_event_count).round
 | 
			
		||||
    plateau_steps = 0;
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  accelerate_until = accelerate_steps;
 | 
			
		||||
  decelerate_after = accelerate_steps+plateau_steps;
 | 
			
		||||
  {:step_event_count => step_event_count,
 | 
			
		||||
   :initial_rate => initial_rate,
 | 
			
		||||
   :final_rate => final_rate,
 | 
			
		||||
   :nominal_rate => nominal_rate,
 | 
			
		||||
   :rate_delta => rate_delta,
 | 
			
		||||
   :accelerate_until => accelerate_until,
 | 
			
		||||
   :decelerate_after => decelerate_after}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def simulate_trapezoid(params)
 | 
			
		||||
  result = {}
 | 
			
		||||
  rate = params[:initial_rate]
 | 
			
		||||
  step_event = 0.0
 | 
			
		||||
  max_rate = 0
 | 
			
		||||
  while(step_event < params[:step_event_count]) do
 | 
			
		||||
    step_events_in_frame = rate/60.0/ACCELERATION_TICKS_PER_SECOND
 | 
			
		||||
    step_event += step_events_in_frame
 | 
			
		||||
    max_rate = rate if rate > max_rate
 | 
			
		||||
    if (step_event < params[:accelerate_until]) 
 | 
			
		||||
      rate += params[:rate_delta]
 | 
			
		||||
    elsif (step_event > params[:decelerate_after])
 | 
			
		||||
      if rate > params[:final_rate]
 | 
			
		||||
        rate -= params[:rate_delta]
 | 
			
		||||
      else
 | 
			
		||||
        return :underflow_at => step_event, :final_rate => rate, :max_rate => max_rate
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
#    puts "#{step_event} #{rate}"
 | 
			
		||||
  end 
 | 
			
		||||
  {:final_rate => rate, :max_rate => max_rate}
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
(10..100).each do |rate|
 | 
			
		||||
  (1..5).each do |steps|
 | 
			
		||||
    params = trapezoid_params(steps*1000, rate*100, 10, 0.1, 0.1)
 | 
			
		||||
    result = simulate_trapezoid(params)
 | 
			
		||||
  #  puts params.inspect
 | 
			
		||||
    line = "#{steps*10} final: #{result[:final_rate]} == #{params[:final_rate]} peak: #{result[:max_rate]} == #{params[:nominal_rate]} d#{params[:nominal_rate]-result[:max_rate]} "
 | 
			
		||||
    line << " (underflow at #{result[:underflow_at]})" if result[:underflow_at]
 | 
			
		||||
    puts line
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Reference in New Issue
	
	Block a user