Minimum question

Status
Not open for further replies.

lmfoster

Member
I'm using arduino. So here's a portion of my code so far:

x=min(voltage0,voltage1);
y=min(voltage2,voltage3);
z=min(voltage3,voltage4);

i=min(x,y);
j=min(y,z);

k=min(i,j);

if (k < field){
Serial.print('s')
}


I'm trying to get the minimum of 5 variables, but now I'm trying to go back and figure out which specific on is the minimum. I've got the minimum but I don't know how to figure out which specific on was the minimum. I know there's better way to do this but I don't know how.
 
the min function returns the minimum value itself if I recall correctly. To get the actual variable with the lowest value, I'd consider writing your own comparison function, which could take an array and return the index in the array of the minimum value.

Note this is untested code:

Code:
int getMinimum(float* voltages, int numVoltages) {

    int minimum = 0;
    for(int i=1; i<numVoltage; i++) {
      if(voltages[i] < voltages[minimum]) {
         minimum = i;
         }
    }
    return minimum;
}


Then you could get the minimum by doing something like this:

Code:
float inputVoltages[5];
/* populate your array however you're getting the values */

float minimumValue = inputVoltages[getMinimum(inputVoltages, 5)];
 
Here's another way to do it (many different ways to approach it). Just compare the current value and the next value, and store the current index if it's smaller, or store the next index if it's larger.

Code:
void setup() {
  
    Serial.begin(9600);
  
}

void loop() {
  
    int variable[5] = {12, 6, 10, 5, 2};     // 5 variables
    uint8_t minIndex = 0;                    // variable to hold minimum index
    
    for (int i=0; i<4; i++) {                // loop through size of array - 1 (i.e., 5 - 1);
        if (variable[i] < variable[i+1]) {   // check if current value is less than next value
            minIndex = i;                    // if current value is less, store the index number (i)
        }
        else {
            minIndex = i+1;                  // if next value is smaller, store the next index (i+1)
        }
    }
    
    Serial.print("Minimum found at index: ");
    Serial.println(minIndex);
    delay(1000);
}
 
Last edited:
All these ways are getting me a minimum value but it's not telling me which variable had the minimum.. the more I think about it I'm not sure if this is possible
 
All these ways are getting me a minimum value but it's not telling me which variable had the minimum.. the more I think about it I'm not sure if this is possible

The index of the array is the variable with the minimum value...
 
Both methods posted above are actually essentially the same (just structured slightly differently). But both are doing as you ask; telling you which variable had the minimum.

If you look at my example, the function returns in the INDEX in the array, of the variable that was the minimum, NOT the value itself.

So to use your exact example with my function:

Code:
float inputVoltages[5];
/* populate your array however you're getting the values */
/* for example */
inputVoltages[0] = 7;
inputVoltages[1] = 2;
inputVoltages[2] = 5;
inputVoltages[3] = 9;
inputVoltages[4] = 22;

int minimumIndex = getMinimum(inputVoltages, 5);   //This variable will contain the value 1, telling you that the value in index 1 of the array is the minimum.
 
Maybe it would help if i gave you more details on my project.. I'm making a keyboard that types off of voltage and it currently types as you are mashing the keys on your keyboard. I'm trying to get it to type each key individually since there is no way to space out the the sensors anymore... the way the circuits are set up the lower the voltage read is actually detecting a higher voltage and I'm trying to get the overall lowest voltage to to display that key
 
Cosford, I didn't know you could use a fuction call / return as an index .... when I think about it, it makes sense, and I had never thought that you could pass an array 'pointer' as part of that process, esp when the pointer is for the array that it is the index for (if you know what I mean) ... in other words, I learnt a really interesting technique reading your code. Thanks.

Mr Prince's code is a good answer too.

Reading your codes has brightened my day.
 
adrian: Glad that it was of use. I'm a fan of trying to keep tidy code, and embedding function calls in things like that can be a neat way of doing things in a single line (or it can very easily end up looking messier if the function call has lots of arguments haha).

lmfoster: Has my most recent reply helped you at all? This function does exactly what I believe you're asking, I think the difficulty here is convincing you it is what you're looking for (perhaps it doesn't look quite how you expected). I'd suggest just dropping that example into a sketch and trying it out.

To try and explain, I've renamed some of my variables to clearer names and written a full sketch for you to try out here:

Code:
int getIndexOfMinimum(float* voltagesArray, int numberOfVoltages) {

    int indexOfMinimum = 0;
    for(int i=1; i<numberOfVoltages; i++) {
      if(voltagesArray[i] < voltagesArray[indexOfMinimum]) {
         indexOfMinimum = i;
         }
    }
    return indexOfMinimum;
}

float inputVoltages[] = { 7, 4, 9, 2, 5, 3, 6 };
const int numOfInputVoltages = 7;

void setup() {
    Serial.begin(9600);
    Serial.println("Hello World!");

    Serial.print("Computing minimum value of: ");
    for(int i=0; i<numOfInputVoltages; i++) {
        Serial.print(inputVoltages[i]);
        Serial.print(", ");
    }
    Serial.println("");
    Serial.print(numOfInputVoltages);
    Serial.print(" values in total.\n");
    
    int indexOfMinimumVoltage = getIndexOfMinimum(inputVoltages, numOfInputVoltages);
    float minimumVoltage = inputVoltages[indexOfMinimumVoltage];

    Serial.print("Index of minimum voltage in array: ");
    Serial.println(indexOfMinimumVoltage);
    Serial.print("Value of minimum voltage in array: ");
    Serial.println(minimumVoltage);

    Serial.println("\nFinished!");
}


void loop() {

}

You can change the values in the inputVoltages[] array, or even add or remove them, provided you update the number stored in numOfInputVoltages (as you can see, it's 7 in the example as there are 7 numbers in the array).
 
Last edited:
The more I look at it the more I think you're code is right.. I'm just new at arduino so I don't fully know what you did but I'm slowly figuring it out.
 
joe_prince I tried you're code but I keep getting the error...
code prob.PNG
 
joe_prince I tried you're code but I keep getting the error...
View attachment 5606

That's a warning, rather than an error. It's a notification that there might be something wrong with your code, but it was able to compile fine. But looking at joe_prince's code, you shouldn't get that warning. Check for typo's in your sketch if it doesn't work as expected.
 
I copied everything but the serial.print commands... i'm about to test it with the board I'll let you know how it goes
 
I commented out a lot of my original code that acted like I was mashing the keys. Here's my code:

//Static Electric Keyboard

int a=0;
int b=1;
int c=2;
int d=3;
int e=4;
int value0=0;
int value1=0;
int value2=0;
int value3=0;
int value4=0;
int slow=0;
int field=1;
int blinking=100;
int voltage0=0;
int voltage1=0;
int voltage2=0;
int voltage3=0;
int voltage4=0;




void setup() {

Serial.begin(9600);

}

void loop() {

float value0=analogRead(a);
float voltage0=value0*5.00/1023.00;
//if (voltage0 < field){
//digitalWrite(6,HIGH);
//Serial.print('a');
//delay(blinking);
//digitalWrite(6,LOW);
//delay(slow);}


float value1=analogRead(b);
float voltage1=value1*5.00/1023.00;
//if (voltage1 < field){
//digitalWrite(6,HIGH);
//Serial.print('b');
//delay(blinking);
//digitalWrite(6,LOW);
//delay(slow );}

float value2=analogRead(c);
float voltage2=value2*5.00/1023.00;
//if (voltage2 < field){
//digitalWrite(6,HIGH);
//Serial.print('c');
//delay(blinking);
//digitalWrite(6,LOW);
//delay(slow);}

float value3=analogRead(d);
float voltage3=value3*5.00/1023.00;
//if (voltage3 < field){
// digitalWrite(6,HIGH);
//Serial.print('d');
//delay(blinking);
//digitalWrite(6,LOW);
//delay(slow);}

float value4=analogRead(e);
float voltage4=value4*5.00/1023.00;
//if (voltage4 < field){
//digitalWrite(6,HIGH);
//Serial.print('e');
//delay(blinking);
//digitalWrite(6,LOW);
//delay(slow);}




//delay(1000);


float variable[5] = {voltage0,voltage1,voltage2,voltage3,voltage4}; // 5 variables
if (variable[5] < field){
int minIndex = 0; // variable to hold minimum index

for (int i=0; i<4; i++) { // loop through size of array - 1 (i.e., 5 - 1);
if (variable < variable[i+1]) { // check if current value is less than next value
minIndex = i; // if current value is less, store the index number (i)
}
else {
minIndex = i+1; // if next value is smaller, store the next index (i+1)
}
}

switch (minIndex){
case 1:
Serial.print('a');
case 2:
Serial.print('b');
case 3:
Serial.print('c');
case 4:
Serial.print('d');
case 5:
Serial.print('e');
break;}

}
}



The output I'm currently getting is just the letters d and e again and again.
 
You need to add "break;" to every case, otherwise it will continue traversing even if it finds a match. Hence why you're seeing 'e' all the time, as well as 'd' since that's probably where the match is. Also, it doesn't hurt to add small delays (maybe 1ms) between analog reads, that way the ADC doesn't get overwhelmed (as well as a delay for the entire loop).
 
Okay, I'm just taking a look.
For future reference, when posting code, put [co de] and [/co de] tags (without spaces), before and after your code respectively. That way it comes out all nicely formatted.

This line "if(variable[5] < field)" will have what we call undefined behaviour (result could be random). This is because array values start at zero.
For instance, where you have
Code:
 float variable[5] = {voltage0,voltage1,voltage2,voltage3,voltage4}; // 5 variables
the way you'd access voltage4 is with variable[4] (because it is the fifth element in the array, starting at zero. eg, 0, 1, 2, 3, 4). variable[5] doesn't actually exist (it will be something random in the teensy's memory).

In addition, your switch statement requires 'break;' statements.
For example:

Code:
case 1:
    Serial.print('a');
    break;

If you do not have these breaks, program flow doesn't stop between case statements. That means, in your example, if minIndex == 2, it would print b, c, d and e.

Other than that, I can't see any errors. If it's just printing d and e over and over, I would suggest it is because however you're randomly generating these 'key presses' is resulting in voltages which result in this happening.
 
Last edited:
Here's my updated code
Code:
int a=0;
int b=1;
int c=2;
int d=3;
int e=4;
int value0=0;
int value1=0;
int value2=0;
int value3=0;
int value4=0;
int slow=0;
int field=1;
int blinking=100;
int voltage0=0;
int voltage1=0;
int voltage2=0;
int voltage3=0;
int voltage4=0;




void setup() {
  
 Serial.begin(9600);
 
}

void loop() {
  delay(1000);

float value0=analogRead(a);
float voltage0=value0*5.00/1023.00;
//if (voltage0 < field){
//digitalWrite(6,HIGH); 
//Serial.print('a');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow)//;}


float value1=analogRead(b);
float voltage1=value1*5.00/1023.00;
//if (voltage1 < field){
//digitalWrite(6,HIGH); 
//Serial.print('b');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow )//;}

float value2=analogRead(c);
float voltage2=value2*5.00/1023.00;
//if (voltage2 < field){
//digitalWrite(6,HIGH); 
//Serial.print('c');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow)//;}

float value3=analogRead(d);
float voltage3=value3*5.00/1023.00;
//if (voltage3 < field){
//  digitalWrite(6,HIGH); 
//Serial.print('d');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow)//;}

float value4=analogRead(e);
float voltage4=value4*5.00/1023.00;
//if (voltage4 < field){
//digitalWrite(6,HIGH); 
//Serial.print('e');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow)//;}




//delay(1000);


float variable[4] = {voltage0,voltage1,voltage2,voltage3,voltage4};   // 5 variables
if (variable[4] < field){
    int minIndex = 0;                    // variable to hold minimum index
    
    for (int i=0; i<4; i++) {                // loop through size of array - 1 (i.e., 5 - 1);
       if (variable[i] < variable[i+1]) {   // check if current value is less than next value
          minIndex = i;                    // if current value is less, store the index number (i)
        }
        else {
           minIndex = i+1;                  // if next value is smaller, store the next index (i+1)
       }
   }

switch (minIndex){
case 0:
  Serial.print('a');
  break;
case 1:
  Serial.print('b');
  break;
case 2:
    Serial.print('c');
    break;
case 3:
    Serial.print('d');
    break;
case 4:
   Serial.print('e');
break;}

}
}

I'm getting saying 'variable' is not declared in this scope
 
Okay, first things first you need to add semicolons to the end of your delay(slow) function calls.

After that, where you've edited
Code:
float variable[4] = {voltage0,voltage1,voltage2,voltage3,voltage4};   // 5 variables
On that line, you were actually correct the first time to have the decleration of the array, as [5]. This is because you are declaring an array of type float, called variable, with 5 elements.

It is when you are accessing those elements, you need to consider that the first element of the array is at index 0.

So it should read:

Code:
float variable[5] = {voltage0,voltage1,voltage2,voltage3,voltage4};   // 5 variables
if (variable[4] < field){
 
I figured out the semicolon error really quick... let me check this code and see if it works and I'll let you know the results.. thank you so much for all you're help.. but don't go to far in case i need more help
 
Code:
int a=0;
int b=1;
int c=2;
int d=3;
int e=4;
int value0=0;
int value1=0;
int value2=0;
int value3=0;
int value4=0;
int slow=0;
int field=1;
int blinking=100;
int voltage0=0;
int voltage1=0;
int voltage2=0;
int voltage3=0;
int voltage4=0;




void setup() {
  
 Serial.begin(9600);
 
}

void loop() {
  delay(1000);

float value0=analogRead(a);
float voltage0=value0*5.00/1023.00;
//if (voltage0 < field){
//digitalWrite(6,HIGH); 
//Serial.print('a');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);


float value1=analogRead(b);
float voltage1=value1*5.00/1023.00;
//if (voltage1 < field){
//digitalWrite(6,HIGH); 
//Serial.print('b');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow );

float value2=analogRead(c);
float voltage2=value2*5.00/1023.00;
//if (voltage2 < field){
//digitalWrite(6,HIGH); 
//Serial.print('c');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);

float value3=analogRead(d);
float voltage3=value3*5.00/1023.00;
//if (voltage3 < field){
//  digitalWrite(6,HIGH); 
//Serial.print('d');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);

float value4=analogRead(e);
float voltage4=value4*5.00/1023.00;
//if (voltage4 < field){
//digitalWrite(6,HIGH); 
//Serial.print('e');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);




//delay(1000);


float variable[5] = {voltage0,voltage1,voltage2,voltage3,voltage4};   // 5 variables
if (variable[4] < field){
    int minIndex = 0;                    // variable to hold minimum index
    
    for (int i=0; i<4; i++) {                // loop through size of array - 1 (i.e., 5 - 1);
       if (variable[i] < variable[i+1]) {   // check if current value is less than next value
          minIndex = i;                    // if current value is less, store the index number (i)
        }
        else {
           minIndex = i+1;                  // if next value is smaller, store the next index (i+1)
       }
   }

switch (minIndex){
case 0:
  Serial.print('a');
  break;
case 1:
  Serial.print('b');
  break;
case 2:
    Serial.print('c');
    break;
case 3:
    Serial.print('d');
    break;
case 4:
   Serial.print('e');
break;}

}
}

I'm not getting any output now
 
On that line, you were actually correct the first time to have the decleration of the array, as [5]. This is because you are declaring an array of type float, called variable, with 5 elements.

It is when you are accessing those elements, you need to consider that the first element of the array is at index 0.

So should my case statements start with 0?
 
this code sets minIndex to 3 or 4, never to 0, 1 or 2. That's why you only get e and d in the Serial Monitor.
Code:
for (int i=0; i<4; i++) {                // loop through size of array - 1 (i.e., 5 - 1);
       if (variable[i] < variable[i+1]) {   // check if current value is less than next value
          minIndex = i;                    // if current value is less, store the index number (i)
        }
        else {
           minIndex = i+1;                  // if next value is smaller, store the next index (i+1)
       }
   }


The code example from Cosford in post #2 gives you the correct index. The case statements should start with 0. This is the updated code:
Code:
int a=0;
int b=1;
int c=2;
int d=3;
int e=4;
int value0=0;
int value1=0;
int value2=0;
int value3=0;
int value4=0;
int slow=0;
int field=1;
int blinking=100;
int voltage0=0;
int voltage1=0;
int voltage2=0;
int voltage3=0;
int voltage4=0;




void setup() {
  
 Serial.begin(9600);
 
}

void loop() {
  delay(1000);

float value0=analogRead(a);
float voltage0=value0*5.00/1023.00;
//if (voltage0 < field){
//digitalWrite(6,HIGH); 
//Serial.print('a');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);


float value1=analogRead(b);
float voltage1=value1*5.00/1023.00;
//if (voltage1 < field){
//digitalWrite(6,HIGH); 
//Serial.print('b');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow );

float value2=analogRead(c);
float voltage2=value2*5.00/1023.00;
//if (voltage2 < field){
//digitalWrite(6,HIGH); 
//Serial.print('c');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);

float value3=analogRead(d);
float voltage3=value3*5.00/1023.00;
//if (voltage3 < field){
//  digitalWrite(6,HIGH); 
//Serial.print('d');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);

float value4=analogRead(e);
float voltage4=value4*5.00/1023.00;
//if (voltage4 < field){
//digitalWrite(6,HIGH); 
//Serial.print('e');
//delay(blinking);
//digitalWrite(6,LOW);
delay(slow);




//delay(1000);


float variable[5] = {voltage0,voltage1,voltage2,voltage3,voltage4};   // 5 variables

    int minIndex = 0;                    // variable to hold minimum index
    
    for (int i=0; i<5; i++) {                // loop through size of array
       if (variable[i] < variable[minIndex]) {   // if current value is less
          minIndex = i;                        //  store the index number (i)
       }
   }

switch (minIndex){
case 0:
  Serial.print('a');
  break;
case 1:
  Serial.print('b');
  break;
case 2:
    Serial.print('c');
    break;
case 3:
    Serial.print('d');
    break;
case 4:
   Serial.print('e');
break;}
}
 
this code sets minIndex to 3 or 4, never to 0, 1 or 2. That's why you only get e and d in the Serial Monitor.
Code:
for (int i=0; i<4; i++) {                // loop through size of array - 1 (i.e., 5 - 1);
       if (variable[i] < variable[i+1]) {   // check if current value is less than next value
          minIndex = i;                    // if current value is less, store the index number (i)
        }
        else {
           minIndex = i+1;                  // if next value is smaller, store the next index (i+1)
       }
   }

Good catch HWGuy! Here is an updated code that should work fine:

Code:
void setup() {
  
    Serial.begin(9600);
  
}

void loop() {
  
    int variable[5] = {2, 10, 12, 1, 4};     // 5 variables
    uint8_t minIndex = 0;                    // variable to hold minimum index
    uint16_t minValue = 0;                   // variable to hold minimum value
    
    minValue = variable[0];                  // set minimum value to first element in array
    
    for (int i=1; i<5; i++) {                // loop through array starting at second element
        if (variable[i] < minValue) {        // check if current element is less than the minimum value
            minIndex = i;                    // update current index
            minValue = variable[i];          // update minimum value
        }
    }
    
    Serial.print("Min value: ");
    Serial.print(minValue);
    Serial.print('\t');
    Serial.print("Index: ");
    Serial.println(minIndex);
    delay(1000);
    
}
 
Status
Not open for further replies.
Back
Top