Rate Limiter not working correctly - java

I am writing an algorithm that takes in messages and then determines whether they compliant with the established messaging rate.
For example, no more than 5 messages are to be sent in ANY 50 second window. Therefore, this window MUST be a rolling window.
I have implemented this token bucket algorithm from this post. However, I can't get it working consistently. It passes some test cases but not others, which makes me think there is a logic issue hidden somewhere in here.
Here is what I have so far:
public class Messaging {
//times in millis
double time_before;
double time_now;
double now;
double time_passed;
double allowance;
//constants
static double per = 50000; // 50 seconds
static double rate = 5; //5 messages
public Messaging(){
time_before = System.currentTimeMillis();
allowance = rate;
}
public void onEvent(){
time_now = System.currentTimeMillis();
time_passed = time_now - time_before;
time_before = time_now;
allowance += time_passed * (rate / per);
if (allowance > rate){
allowance = rate;
System.out.println("Reset Allowance");
}
if (allowance < 1.0){
System.out.println("Discard");
}else{
System.out.println("Forward message");
allowance -= 1.0;
}
}
This doesn't work though!
public static void main(String[] args) {
Messaging orders = new Messaging();
for (int i = 0; i < 10; i++) {
orders.onEvent();
try {
Thread.sleep(5000);
} catch (Exception ex) {
}
}
}
Running the code above gives this:
Forward message. Time: 1469830426910
Forward message. Time: 1469830431912
Forward message. Time: 1469830436913
Forward message. Time: 1469830441920
Forward message. Time: 1469830446929
Forward message. Time: 1469830451937
Forward message. Time: 1469830456939
Forward message. Time: 1469830461952
Forward message. Time: 1469830466962
Discard. Time: 1469830471970
Total time passed: 50067
Why is only the last message being discarded? Shouldn't allowance be decremented enough that it fails automatically after the 5th message?
I would like help with this particular implementation please. The actual implementation will be in a proprietary language that doesn't have queues, etc.

For a rate-limited sliding window, you need to queue up each message, along with it's timestamp. That way, when the queue is full, you just discard any new messages. When the messages at the end of the queue have been in there for more than the allotted time, they leave the queue, and you have room for more new messages.
class MessageBuffer {
class Message {
double timestamp;
String value; // Can be any type you need it to be
public Message(double timestamp, String value) {
this.timestamp = timestamp;
this.value = value;
}
}
static final double WINDOW_SIZE = 5;
static final double TIME_LIMIT = 50000;
Queue<Message> messages = new ArrayDeque<>(WINDOW_SIZE);
public void onEvent(String message) {
double now = System.currentTimeMillis();
// If the queue has messages in them that are no longer in the sliding window,
// remove them from the queue
while (messages.size() > 0
&& messages.peek().timestamp + TIME_LIMIT > now)
messages.remove();
// If there is room in the queue, process this message, otherwise discard it
if (messages.size() < WINDOW_SIZE) {
System.out.println("Forward message: " + message);
messages.add(new Message(now, message));
} else {
System.out.println("Discard message: " + message);
}
}
}
Without this timestamp information, you can't tell when a message leaves the sliding window, so you can't know whether your window is full or not. FYI, that example you linked to is an approximation, and can actually limit you to less than 5 messages in 50 seconds.
Two minor nit-picks:
In an object-oriented world, classes are things, not actions. In most cases, your class name should be a noun that describes what it is (MessageBuffer), not a verb that describes what it does (Messaging).
The variable now should not be a member variable - when you first assign it, it does represent the current time, but once the method has finished, and another method is called, the value is stale - it doesn't actually represent the current time.

The algorithm you're using is an approximation - it will give you the rate you're looking for, on average. In the original post, the writer claims:
'allowance' grows at speed 5/8 units per seconds at most, i.e. at most five units per eight seconds. Every message that is forwarded deducts one unit, so you can't send more than five messages per every eight seconds.
This is not quite true - if allowance starts off at it's maximum value, say 5, it grows at 5/8 units per second, and then for every message sent, 1 is deducted. So allowance is shrinking at a rate of 3/8 units per second, and starting from 5, we can send around 10 messages before the throttling happens.
If you have a period where your messages are not coming in as fast as your throttle rate, then it will build up the allowance. Then, when the messages pick up pace, you have a brief period where you may end up processing 2 * rate messages before the throttling kicks in. If you change your loop to do 20 iterations, instead of 10, you'll see that eventually the throttling does behave as you'd expect it to. Alternatively, if you set the allowance to 0 to begin with, instead of rate, it will throttle straight away.

Related

How do I end a method in Java after a certain amount of time?

I would like to force a method to end after a certain amount of time even if it has not completed its task. How would I go about doing this?
Edit (added clarification and code):
I am programming a robot using Android Studio for the FTC (First Tech Challenge) robotics competition. To control the robot, I am using the FTC SDK (see https://github.com/ftctechnh/ftc_app).
The method works fine for going a particular distance and then stopping but after it stops by setting the power of all the motors to zero, it appears to get hung and no subsequent methods are invoked. Currently, it is only supposed to have the motors be stopped for one second before exiting but it appears to still get stuck on the first invocation of the method that sets the motor power to zero (setPower). For this reason, I would like to be able to terminate setPower after it has been running for a certain amount of time so that my method can exit and subsequent methods can be invoked.
Here is my method:
public void moveLine(DcMotor m1, DcMotor m2, DcMotor m3, DcMotor m4, double distance /* distance to move in meters */, double motorPower /* power to set the motors */) {
final double SPROCKET_CIRCUMFRENCE = Math.PI * 0.0652; //calculates the circumference of the sprocket
final int ENCODER_CPR_NR60 = 1680; //encoder counts for NeveRest 60
//final static int ENCODER_CPR_NR40 = 1120; //encoder counts for NeveRest 40
double amountOfRotationsCalc = distance / SPROCKET_CIRCUMFRENCE; //calculates the amount of rotations to move to reach the target distance
double amountOfEncUnitsCalc = ENCODER_CPR_NR60 * amountOfRotationsCalc; //calculates the amount of encoder units to move
//this gets the sum of the encoder positions of the drive motors
int currentEncPosSum = m1.getCurrentPosition() + m2.getCurrentPosition() + m3.getCurrentPosition() + m4.getCurrentPosition();
//this gets the average encoder position
int currentEncPosAvg = currentEncPosSum / 4;
//if the robot is supposed to be moving forward (positive distance), the motors will be set to positive values
if (distance > 0) {
//it may make sense to make this a while loop. Will this fix the issue?
if (currentEncPosAvg < amountOfEncUnitsCalc) {
m1.setPower(motorPower);
m2.setPower(motorPower);
m3.setPower(motorPower);
m4.setPower(motorPower);
} else {
//these stop the robot. Without them, it continues to move.
long start = System.currentTimeMillis();
long end = start + 1000;
while (System.currentTimeMillis() < end) {
m1.setPower(0);
m2.setPower(0);
m3.setPower(0);
m4.setPower(0);
}
return; //this is supposed to exit this method
}
} else {
//this is essentially the opposite of the code for going forwards
if (currentEncPosAvg > amountOfEncUnitsCalc) {
m1.setPower(-motorPower);
m2.setPower(-motorPower);
m3.setPower(-motorPower);
m4.setPower(-motorPower);
} else {
//these stop the robot. Without them, it continues to move.
long start = System.currentTimeMillis();
long end = start + 1000;
while (System.currentTimeMillis() < end) {
m1.setPower(0);
m2.setPower(0);
m3.setPower(0);
m4.setPower(0);
}
return;
}
}
}
long beginning = System.currentTimeMillis();
long end=beginning + yourTimeInMilliseconds;
while (end > System.currentTimeMillis()){
//your code here
}
I believe this is what you mean.
Some clarification, if you need any:
beginning is the current time in milliseconds.
end is obviously when it ends. (Start time plus delay)
While the time is still less than the set end time, the code keeps going.
I know this question is a bit old, but in the latest ftc_app Android SDKs it is recommended that for time aware methods and procedures that teams use the ElapsedTime class.
The most important thing to consider when pausing an opmode is that you can still shut it down when the stop button is pressed on the driver station app. you can make sure of this by including the opModeIsActive() method in your while condition
On our team we have a method for pausing OpModes that looks something like this. we have this declared in a separate class used for library purposes.
public static void pauseOpMode(LinearOpmode op, ElapsedTime et, double waitTime){
double startTime = et.milliseconds();
while (op.opModeIsActive() && et.milliseconds() < startTime + waitTime){}
}
Now that this method exists, in our OpMode we can create an Elapsed time Object and pass the necessarry parameters to the function required to pause the OpMode
class someOpMode extends LinearOpMode{
ElapsedTime gameTimer = new ElapsedTime();
#Override
public void RunOpMode(){
//pause program for 5 seconds
pauseOpMode(this,gameTimer,5000);
}
}

Timer alternative to measure request rate on the server side

I have client-server application in which i need to measure the rate of request arrival per second(Request rate). For this, i have a timer object that activates after every seconds, reads a synchronized counter and then sets it to zero. The counter increments on each request arrival.I used following code to detect request rate. There are so many other threads and timers in my application running.The problem is "due to the inaccuracy of timers i am not getting the perfect request rate". Is there any alternative of measuring request rate other than using timers.
public class FrequencyDetector extends TimerTask {
RequestCounter requestCounter;
FrequencyHolder frequencyHolder;
public FrequencyDetector(RequestCounter requestCounter,FrequencyHolder frequencyHolder){
this.frequencyHolder=new FrequencyHolder();
this.frequencyHolder=frequencyHolder;
}
#Override
public void run() {
int newFrequency=requestCounter.getCounter();
frequencyHolder.setFrequency(newFrequency);
requestCounter.setCounterToZero();
//calls to other fuctions
}
}
Instead of checking counter per unit time you can check time per unit counter. That will probably give you more accurate results. Algorithm is given below.
Increment counter on every request.
When counter reaches a certain FIXED_LIMIT calculate frequency by frequency=FIXED_LIMIT/duration since last record
Reset the counter and start with step 1
However this will record frequency at unpredictable intervals and if frequency of request decreases the duration between successive records will increase.
To handle it we can implement an adaptive algorithm, algorithm is given below.
Increment the counter on every request.
When counter reaches a certain ADAPTIVE_LIMIT record frequency as frequency=ADAPTIVE_LIMIT/duration since last record
Change ADAPTIVE_LIMIT as ADAPTIVE_LIMIT=frequency * DESIRED RECORD INTERVAL
Reset counter and start with step 1.
Above algorithm will reset the limit based on frequency last recorded. It's given that it will not be recording at optimal intervals but it will be pretty close.
Also it will give you highly accurate frequencies as it does not depend on any scheduled thread.
Following is an implementation of such an adaptive counter.
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
public class TestCounter {
//Keep initial counterInterval to a small value otherwise first record may take long time
final AtomicLong counterInterval = new AtomicLong(10);
AtomicLong requestCounter = new AtomicLong();
volatile long lastTime;
/**OPTIMAL_DURATION is the duration after which frequency is expected to be recorded
* Program adaptively tries to reach this duration
*/
static final double OPTIMAL_DURATION = 1.0; // 1 second
static final Random random = new Random();
public static void main(String[] args) {
System.out.println("Started ");
TestCounter main = new TestCounter();
for(int i = 0; i < 1000; i++) {
main.requestArrived();
}
}
/*
* Simulating requests
*/
public void requestArrived() {
printCounter();
try {
Thread.sleep(random.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//This will be in some Utility class
private void printCounter() {
requestCounter.incrementAndGet();
long currentTime = System.nanoTime();
long currentInterval = counterInterval.get();
if(requestCounter.get() > currentInterval) {
if(lastTime != 0) {
long timeDelta = currentTime - lastTime;
long frequency = (long)(currentInterval / (timeDelta / 1e9));
System.out.printf("time=%.2f, frequency=%d\n", (timeDelta / 1e9), frequency);
//updating the currentInterval for the miss
long newCounterInterval = (long)(frequency * OPTIMAL_DURATION);
counterInterval.set(newCounterInterval);
}
requestCounter.set(0);
lastTime = currentTime;
}
}
}
Output
Started
time=0.54, frequency=18
time=0.98, frequency=18
time=1.01, frequency=17
time=0.96, frequency=17
time=0.99, frequency=17
time=0.85, frequency=19
time=0.96, frequency=19
time=0.82, frequency=23
time=1.08, frequency=21
time=0.98, frequency=21
time=0.94, frequency=22
time=1.06, frequency=20
time=1.07, frequency=18
time=0.99, frequency=18
time=0.98, frequency=18
time=1.02, frequency=17
time=0.92, frequency=18
time=0.92, frequency=19
time=0.89, frequency=21
time=0.82, frequency=25
time=1.31, frequency=19
time=1.02, frequency=18

Synchronise to beats per minute / Send quantised messages

I'm getting periodic signals (beats per minute) from a Transmitter and now want to call methods in a fraction of the period, e.g. send 1/1, 1/2, 1/4, 1/8, 1/16,.. notes.
My solution for this is to create a thread, do a busy wait and then execute the methods. The problem here is that listening to the signal, processing it and sending it back creates a delay of a few milliseconds (depending on the system).
So now I want to determine the delay between the incoming signal and the periodic signal of the thread and if the delay is != 0, stop the current thread and start a new thread after "bpm - delay" milliseconds. How can this be done ?
Illustration:
transmitter signal: |----|----|----|----|
******runner signal : |----|----|----|----|
delay runner signal by "onePeriod - delay" milliseconds:
transmitter signal: |----|----|----|----|
***"runner signal :**** |----|----|----|----|
Both signals are now in sync.
public class Quantiser implements Receiver{
private int[] bpmsInMillis = new int[4];
private int bpmInMillis=0;
private double smallestNote = 1;
private long period=0;
private long fire=0;
private long prevTimeStamp=0;
private Runnable runny = new Runnable() {
#Override
public void run() {
while(true){
fire = System.nanoTime() + period;
while(System.nanoTime() < fire){} // busy wait
// Call some methods here.
}
}
};
private Thread thread = new Thread(runny);
#Override
public void send(MidiMessage message, long timeStamp) {
// Calculate average bpm
for(int i=0; i<bpmsInMillis.length-1;i++)
bpmsInMillis[i] = bpmsInMillis[i+1];
bpmsInMillis[bpmsInMillis.length-1] = (int) ((timeStamp - prevTimeStamp) / 1000);
bpmInMillis = arithmeticMean(bpmsInMillis);
prevTimeStamp = timeStamp;
period = (long) (bpmInMillis * smallestNote * 1000000);
if(!thread.isAlive()) {
thread.start();
}
/*
else{
Calculate delay between signal and thread-signal.
if(delay != 0){
Delay new thread by "bpm - delay" milliseconds.
Stop old thread.
Start new thread.
}
*/
}
#Override
public void close() {
}
One option would be to implment a Phase-Locked Loop (PLL).
http://en.wikipedia.org/wiki/Phase-locked_loop
Basically, you'll need two threads: One thread sits in a loop waiting for the input beats, and each time it gets a beat, it records the time of arrival.
long time_of_last_beat;
while (true) {
wait_for_next_beat();
time_of_last_beat = System.currentTimeMillis();
}
The other thread sits in a loop that goes sixteen times as fast:
long semiquaver_duration = <starting guess>;
while (true) {
notify_whoever_cares_that_its_time_for_the_next_semiquaver();
Thread.sleep(sixteenth_note_duration);
long phase_error = System.currentTimeMillis() - time_of_last_beat;
semiquaver_duration += estimate_phase_correction(phase_error);
}
I'll leave it to you to write the estimate_phase_correction() function. A linear function of the given error with the right coefficient may be all you need. If you get it right, the 16x loop should "lock in" so that every sixteenth semiquaver happens exactly on the beat.
Improvements:
have the beat loop compute the tempo.Base the starting guess for the semiquaver period on the current tempo.Notice significant (i.e. abrupt) tempo changes and re-set the semiquaver loop as needed.
In general, when I work with sound (usually sampled, not MIDI), I find it more accurate to use frame counts than elapsed time. With elapsed time there are too many unknowns (thread slicing, garbage collection, etc.). Latencies may vary, but 44100 frames (if that is the format) is always 1 sec.
With MIDI, doesn't every event have a field with the time that event is supposed to occur? I've seen readouts with both beats/measures and elapsed-time. I would use that info rather real-time time stamps when figuring any sort of positioning onto an existing Midi stream.
If this is something where the incoming is ASAP/real time, but you want to pass it through quantised, can you put scheduling info on the out-going Midi even if the incoming doesn't have it? Then you'd have a solid reference points for the positioning.
Reference on Real-Time. Low Latency Audio Processing in Java:
https://diuf.unifr.ch/main/pai/sites/diuf.unifr.ch.main.pai/files/publications/2007_Juillerat_Mueller_Schubiger-Banz_Real_Time.pdf

Arduino bat sensor registers too many times

I need to progam an Arduino for a project, and I thought I'd add something fancy, a LED color changing thingy. The LED has a sort of cyclus in which it changes colors, which takes about 40 seconds to do so. Though, the bat sensor, that makes the LED burn, registers the whole time and tells the LED a couple of times a second to go on, again. The LED never gets the time to change color and only stays the first color.
I have no idea how to fix this. I was trying to give the LED a delay or something, but apparently I did that wrong. The code so far is this;
//Pin which triggers ultrasonic sound.
const int pingPin = 13;
//Pin which delivers time to receive echo using pulseIn().
int inPin = 12;
//Range in cm which is considered safe to enter, anything
//coming within less than 5 cm triggers the red LED.
int safeZone = 10;
//LED pin numbers
int redLed = 3, greenLed = 5;
void setup() {
//Initialize serial communication
Serial.begin(9600);
//Initializing the pin states
pinMode(pingPin, OUTPUT);
pinMode(redLed, OUTPUT);
pinMode(greenLed, OUTPUT);
}
void loop()
{
//Raw duration in milliseconds, cm is the
//converted amount into a distance.
long duration, cm;
//Sending the signal, starting with LOW for a clean signal 2 staat voor reactie.
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
//Setting up the input pin, and receiving the duration in
//microseconds for the sound to bounce off the object in front.
pinMode(inPin, INPUT);
duration = pulseIn(inPin, HIGH); //Documentation for pulseIn():
//http://www.arduino.cc/en/Reference/PulseIn
//Convert the time into a distance
cm = microsecondsToCentimeters(duration);
//Printing the current readings to the serial display
Serial.print(cm);
Serial.print("cm");
Serial.println();
//If het is groter dan 10 dan gaat het lichtje uit
//else het is binnen bepaalde cm dan gaat het aan van 0 naar 255.
if(cm>10)
{
analogWrite(redLed, 0);
}
else{
analogWrite(redLed, map(cm,0,10,255,0));
dela
}
if(cm>5)
{
analogWrite(greenLed, 0);
}
else{
analogWrite(greenLed, map(cm,0,5,255,0));
}
delay(100);
}
long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}
But it still needs some kind of delay thing I think. I'm not sure what the sensor I'm using is called but it has two rounds with sensors in them, one sends and one receives, it measures how long it takes to receive back the sound and in my code I translate that to cm.
I hope you can help and understand what my problem is since my knowledge of this language is very poor.
Set a timeout value for pulseIn. Otherwise the program gets stuck in the line duration = pulseIn(inPin, HIGH); as you don't get the chance to send out another ultrasonic pulse if the previous ultrasonic pulse did not result in an echo.
In this case, the maximum range is 10 cm (20 cm travel distance for the sound pulse) so the timeout value can be set accordingly (s is distance, v is velocity and t is time):
s = v * t => t = s / v = 2 * 0.1 m / 343.2 m/s = 582.8 µs
The speed of sound is assumed to be in dry air at 20 °C.
Allowing for the width of the outgoing pulse of 2 µs the total time would then be 584.8 µs.
Instead of
duration = pulseIn(inPin, HIGH);
use
duration = pulseIn(inPin, HIGH, 585);
Other notes:
The outgoing pulse is very short, intended to be 2 µs.
digitalWrite() is quite slow, on the order of 5 µs so the actual pulse may be longer than 2 µs. Even so, the ultrasonic transducer may not be able to start up in such a short time.
Even if the outgoing pulse is longer than you think it is, it is on the order of a single period (if the ultrasonic transducer operates at 100 kHz the period is 10 µs)
Try to experiment with longer ranges and longer outgoing pulses to be sure this is not the problem.
Use delay(ms) to delay for 40 ms as required. That will shut the Arduino for 40 ms before it gets to process any data from the ultrasonic sensor.

Frequency from binary input

Background: I have a IOIO which I am using to measure the output from an photodiode, this is the converted into a digital output. I need to find the frequency at which the signal changes between 1 and 0. Everything I have tryed so far has hanged my test app, any suggestions?
current code:
if(diode == 1 && frequencyFound == false){
startTime = System.currentTimeMillis();
while((frequencyFound == false)){
if(diode == 0){
while(frequencyFound == false){
if(diode == 1){
double endTime = System.currentTimeMillis();
time = endTime - startTime;
frequency = (long) (1.0 / time);
frequencyFound = true;
}
Thread.sleep(100);
}
}
Thread.sleep(100);
}
}
There are a couple of issues here.
First, Android is a multi-tasking system, and you could find your timing thread put to sleep long enough to miss some signal transitions. Is there no way to be notified of a leading (or trailing) edge transition rather than sampling the input in a loop?
What sort of frequency are you looking at? Will a 100 ms sampling interval be fine enough?
Don't count on Thread.sleep() to sleep for exactly the time you specify. If the interval is too short, the system might decide to return immediately or it might round the sleep time up to a larger amount.
Your timing loop won't record the time to any precision better than 100ms (at best), so your estimate for the frequency will be very poor.
Zapl is right, you MUST run this from a separate thread from your UI thread.
Watching for a single transition will give you a very imprecise estimate of the frequency. Try something like this instead:
// Find frequency to the nearest hz (+/- 10%)
// It's assumed that some other process is responsible for updating the "diode"
// variable. "diode" must be declared volatile.
long duration = 1000; // 1 second
final int interval = 100; // sampling inteval = .1 second
int oldState = diode;
int count = 0;
final long startTime = System.currentTimeMillis();
final long endtime = startTime + duration;
while (System.currentTimeMillis() < endtime) {
// count all transitions, both leading and trailing
if (diode != oldState) {
++count;
oldState = diode;
}
Thread.sleep(interval);
}
// find the actual duration
duration = System.currentTimeMillis() - startTime;
// Compute frequency. The 0.5 term is because we were counting both leading and
// trailing edges.
float frequency = 0.5 * count / (duration/1000);
Two more extreme suggestions for working around some of the timing accuracy concerns Edward raised:
Do the measurement of interval times on the IOIO board under interrupts, where you can presumably accomplish (at least near-) real time operations. Report these time measurements to the Android device.
Skip the ioio board and build something simple to route the signal into the headset connector as a tone that turns on or off. Record audio using the built-in timing guarantees of the audio system, and then analyze the audio buffers (real time no longer required) to determine the intervals from the number of intervening audio samples times in units of the (relatively reliable compared to anything you could do in an android app) audio sample rate. You can also get an analog input easily by using the light sensor to vary the frequency of an audio oscillator.

Categories

Resources