3

I'm a design teacher trying to help a student with a programming challenge, so I code for fun, but I'm no expert.

She needs to find the mode (most frequent value) in a dataset built using data from sensors coupled to an Arduino, and then activate some functions based on the result.

We've got most of it figured out, except how to calculate the mode in Arduino. I found the post Get the element with the highest occurrence in an array that solves the problem in JavaScript, but I haven't been able to "port" it.

3
  • What form does the 'dataset' you refer to take? Is it an (Arduino) array of integers? Commented Oct 26, 2011 at 21:28
  • Hi Matthew. We haven't coded it yet, but yes, it will probably be an array of integers, although we might take the float way too. She (the student) will measure an object's speed, and act upon that. For the scale prototype, the speed will be also "scaled down", so we will have to test if integers are fine, or if we should take decimal numbers for the evaluation. Commented Oct 27, 2011 at 2:55
  • If you're using a floating point number I'd be concerned that there may be no single 'mode' (i.e. every result could be different). Is this likely to be a problem or can we assume that that can't happen in this case? Commented Oct 27, 2011 at 13:07

2 Answers 2

3

I've used a HashMap to replace the js {} dynamic object instance and floats, but @weberik's port looks more straightforward.

void setup() {
    int numValues = 10;
    float[] values = new float[numValues]; //Create an empty sample array
    for(int i = 0 ; i < numValues ; i++) values[i] = random(0.0,100.0); //Populate it with random values.
    println("mode: " + mode(values));
}

float mode(float[] source) {
    if (source.length == 0)
        return -1;
    HashMap<Float,Integer> modeMap = new HashMap<Float,Integer>();
    float result = source[0];
    int maxCount = 1;
    for (int i = 0; i < source.length; i++) {
        float el = source[i];
        if (modeMap.get(el) == null)
            modeMap.put(el,1);
        else
            modeMap.put(el,modeMap.get(el)+1);
        if (modeMap.get(el) > maxCount) {
            result = el;
            maxCount = modeMap.get(el);
        }
    }
    return result;
}

You've mentioned sensor input, so I presume data will be sampled continuously, so values could be stored at a certain interval, then sent to Processing for the mode. Just a wild guess, but isn't she looking to average/smooth out sensor readings a bit? If so, she could cache a few values (say 10) in an array in Arduino and get the average everytime a new values is added:

int vals[10]; //Array to store caches values.

void setup() {
    Serial.begin(9600);
    for (int i=0 ; i < 10 ; i++) 
        vals[i] = 0; //Init with zeroes
}

void loop() {
    delay(100);
    int currentVal = average(analogRead(0));
    //Serial.print(currentVal,BYTE);
    Serial.println(currentVal);
}

int average(int newVal) {
    int total = 0; //Used to store the addition of all currently cached values
    for(int i = 9; i > 0; i--) { //Loop backwards from the one before last to 0
        vals[i] = vals[i-1]; //Overwrite the prev. value with the current(shift values in array by 1)
        total += vals[i]; //Add to total
    }
    vals[0] = newVal; //Add the newest value at the start of the array
    total += vals[0]; //Add that to the total as well
    return total *= .1; //Get the average (for 10 elemnts) same as total /= 10, but multiplication is faster than division.
}
Sign up to request clarification or add additional context in comments.

4 Comments

The thought of using a template on a micrcontroller makes my mind bleed. The inefficiencies are painful. On that note, you did show how to port the code over, if it will compile on arduino, I am not sure.
Thanks George, very thoughtful response. Indeed she would have to average the readings a bit, and your solution is clear and made me learn about HashMaps! Do you think it might be done in Arduino alone (excluding the Processing part)? Don't show me code, but the answer :)
Kortuk, you are right about efficiency, but that's not the target for Arduino...it's supposed to make it simple/less scary for anyone with little or no programming experience to use a microcontroller. Regarding the ported code, that is for Processing/Java, not Arduino, so it will no run on Arduino obviosuly, but values can be sent from Arduino to Processing via the built-in Serial library.
Thanks George. In the end I took an aproach based on the previous response, however yours led me to learn about Hash maps!
2

I ported the code from your linked post to Processing, but it's limited to int arrays. I hope that helps.

void setup()
{
    int[] numbers = {1, 2, 3, 2, 1, 1, 1, 3, 4, 5, 2};
    println(mode(numbers));
}


int mode(int[] array) {
    int[] modeMap = new int [array.length];
    int maxEl = array[0];
    int maxCount = 1;

    for (int i = 0; i < array.length; i++) {
        int el = array[i];
        if (modeMap[el] == 0) {
            modeMap[el] = 1;
        }
        else {
            modeMap[el]++;
        }

        if (modeMap[el] > maxCount) {
            maxEl = el;
            maxCount = modeMap[el];
        }
    }
    return maxEl;
}

3 Comments

Thank you weberik, your solution is clear and easy tu follow!
Am I correct in saying that this code requires that the elements in the original array be smaller than the length of the original array?
This solution is both wrong and not a port from the original JS code. In the original JS code modeMap is a map (a JavaScript Object) and a new entry (key) for the current mode will be automatically added if the key is not already present. As already stated by @j_v_wow_d, this code will only work by chance and only if the values of the elements of the array are always smaller than the length of the array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.