Go Down

Topic: Flickering Potentiometer (Read 1 time) previous topic - next topic

GoForSmoke

When I was looking at Terry King's RS485 interface circuitry I saw a good bit of what I'd call pulldown flow that Terry did identify as there for stability. It's like ripples being pulled away on a flowing stream.

Otherwise try shielding the wires. Even grounded foil may make a difference. Paper clips will hold and contact foil, it won't solder.
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

PieterP

When I was looking at Terry King's RS485 interface circuitry
Do you mean this interface? Where are the pulldowns you're talking about?

GoForSmoke

Here:
http://arduino-info.wikispaces.com/RS485-Modules

On the right side there is VCC through 20KR to one data line then through 120R to the next data line then through 20KR to ground.

Serial default/zero state is HIGH, one state is LOW, that's a pullup and pulldown, why I write flow, it's noise resistant.
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

6v6gt

I produced a 7  bit resolution version of my standard hysteresis template in case it helps in solving the problem here. It produces 128 discrete values (0..127) from analog values in the range 0 to 1023. I can test it with only a rough old preset type potentiometer, but it seems to work nicely with a margin of +/- 2.

This version does not have a table of range endpoints because the intervals between endpoints are all equal. A calculation is used instead. This would make it more practical to define it as a class and have multiple instances.

Code: [Select]

/*

  Hysteresis

  This code example shows obtaining values 0-127 from a potentiometer wired
  as a voltage divider. These values remain stable even if the potentiometer
  is set on a border point between two values.

 
  6v6gt 13.apr.2018

  ver 0.01 03.02.2018 Original verson with table to represent range end points
  ver 0.02 13.04.2018 Original verson with calculation to determine range end points.

*/




uint8_t getOutputLevel( uint16_t inputLevel ) {
 //
 //  convert an input value into an output value with hysteresis to
 //  avoid instability at cutover points ( eliminate thrashing/flicker etc.)
 //
 //  6v6gt 13.apr.2018 ver 0.02

 // adjust these 4 constants to suit your application

 // ========================================
 // margin sets the 'stickyness' of the hysteresis or the relucatance to leave the current state.
 // It is measured in units of the the input level. As a guide it is a few percent of the
 // difference between two end points. Don't make the margin too wide or ranges may overlap.
 const uint16_t margin = 2 ;   //  +/- 2

 // set the number of output levels. These are numbered starting from 0.
 /*
  * bits
  * resolution      levels
  * 1                    2
  * 2                    4
  * 3                    8
  * 4                    16
  * 5                    32
  * 6                    64  
  * 7                    128
  * 8                    256    Too high for 10 bit adc
  * 9                    512    Too high for 10 bit adc
  */
 const uint16_t numberOfLevelsOutput = 128 ;  // 128 => 0..127  ( power of 2 ideally  )

 // number of discrete input values.
 // 8 bit ADC = 256, 9 bit ADC = 512, 10 bit ADC = 1024, 11 bit ADC = 2048, 12 bit ADC = 4096
 const uint16_t numberOfInputValues = 1024  ;  //  0..1023 (power of 2 ideally )

 // initial output level (usually zero)
 const  uint16_t initialOutputLevel = 0 ;
 // ========================================

 // the current output level is retained for the next calculation.
 // Note: initial value of a static variable is set at compile time.
 static uint16_t currentOutputLevel = initialOutputLevel ;


 // get lower and upper bounds for currentOutputLevel
 uint16_t lb =   (float) ( (float) numberOfInputValues / numberOfLevelsOutput ) * currentOutputLevel  ;
 if ( currentOutputLevel > 0 ) lb -= margin  ;   // subtract margin

 uint16_t ub =   ( (  (float) ( (float) numberOfInputValues / numberOfLevelsOutput ) * ( currentOutputLevel + 1 )  )  - 1 )  ;
 if ( currentOutputLevel < numberOfLevelsOutput ) ub +=  margin  ;  // add margin
   // now test if input is outside the outer margins for current output value
   // If so, calculate new output level.
 if ( inputLevel < lb || inputLevel > ub ) {
   // determine new output level
   currentOutputLevel =   (  ( (float) inputLevel * (float) numberOfLevelsOutput ) /  numberOfInputValues ) ;
 }
 return currentOutputLevel ;
}




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

void loop() {

 Serial.print(  getOutputLevel( analogRead(A0) ) ) ;
 Serial.print("  " ) ;
 Serial.println( analogRead(A0) ) ;

 delay ( 500 ) ;
}


PieterP

I produced a 7  bit resolution version of my standard hysteresis template in case it helps in solving the problem here.
If you'd only said that you were going to do that earlier, I just wrote a very similar sketch last week :)

Anyway, thanks a lot for the responses!
I've got some other work right now, but I'll look into it further when  I find the time.

ciabio

Hello everyone, sorry if I answer only now, to make more clear:

all the potentiometers are connected with rigid wires (maximum length 40 cm minimum 5 cm)

the potentiometers are connected to multiplexers and on each multiplexer is a ceramic capacitor.

all the multiplexers are connected to the teensy 3.6 and use the 3.3V pin

the potentiometers are 10k ohm linear

for the flicker not on all potentiometer happens, the flicker is very low but it's annoying enough not to be able to map all these potentiometers ..

the answers have confused me a bit, and I would like to know if there is anything practical I can do to solve this problem.

thank you so much

wvmarle

the answers have confused me a bit, and I would like to know if there is anything practical I can do to solve this problem.
Lots of suggestions given - that's what you can do - if it's confusing feel free to ask for clarification.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

PeterPan321

#22
Apr 17, 2018, 04:51 pm Last Edit: Apr 17, 2018, 04:56 pm by PeterPan321
I don't see the low level library code where the analog readings are actually being taken, but maybe you can apply my solution somehow. I added this to one of my own projects that required smoothing of a few analog inputs in an Arduino NANO, to filter out noise. Basically it filters inputs exponentially, as an RC filter would. This allows the latest readings to have the greatest affect on the final output.  First, the basic idea for a single input works like this..

Code: [Select]
#define DIV_SHIFT 4
static long  accum = 0;
int output;

accum -= (accum >> DIV_SHIFT);
accum += analogRead(A0);

output = (uint16_t)(accum >> DIV_SHIFT);


In the above is I have an accumulator variable. There's nothing in it initially but over time there will be. Each time the above code is called, 1/16 of whatever was in the accumulator from the last pass is subtracted, and the latest analog reading is added. Finally the current result in the accumulator is again divided by 16. I usually use powers of 2 for my divisor when I do this, so that I can divide with processor friendly shifts rather than slow floating point math.

Anyway, the result is that over 5 "time constants" of the simulated RC network, the output will very closely equal the input, IF the input remained steady (which you can prove by substituting a number for the analogRead(). So if I'm dividing by 16, 5 time constants would be 5 x 16, or 64 passes, before the output is, for all practical purposes, equal to the input.  But since the input is NOT a steady number, what you have is the equivalent of a low pass filter which should remove random noise for you very well. However, if the noise is periodic (like 60 hZ line noise or other EMI frequencies from nearby electronics) its not likely to be as effective.

If you want a faster response from the filter, cut the DIV_SHIFT to a lower number. Obviously if DIV_SHIFT is ZERO, there is NO filtering being done at all.

When I implement this in a project, I'll usually put this principal into a function call where I allocate a static array of as many accumulators as I have digital inputs to filter. I'll also arrange for an initialization that forces 5 * DIV_SHIFT  (64 in this case) iterations to occur the first time I call the function for a given analog input. That way I have valid filtered readings without waiting for 64 calls to go by, and future calls will only require a single pass.

If the basic idea works for you, and you need help creating such a call, I'll throw something together for you. Obviously instead of a function call, it would be better to implement what I've suggested as a class if you have as many alog inputs as you're dealing with.




ciabio

I don't see the low level library code where the analog readings are actually being taken, but maybe you can apply my solution somehow. I added this to one of my own projects that required smoothing of a few analog inputs in an Arduino NANO, to filter out noise. Basically it filters inputs exponentially, as an RC filter would. This allows the latest readings to have the greatest affect on the final output.  First, the basic idea for a single input works like this..

Code: [Select]
#define DIV_SHIFT 4
static long  accum = 0;
int output;

accum -= (accum >> DIV_SHIFT);
accum += analogRead(A0);

output = (uint16_t)(accum >> DIV_SHIFT);


In the above is I have an accumulator variable. There's nothing in it initially but over time there will be. Each time the above code is called, 1/16 of whatever was in the accumulator from the last pass is subtracted, and the latest analog reading is added. Finally the current result in the accumulator is again divided by 16. I usually use powers of 2 for my divisor when I do this, so that I can divide with processor friendly shifts rather than slow floating point math.

Anyway, the result is that over 5 "time constants" of the simulated RC network, the output will very closely equal the input, IF the input remained steady (which you can prove by substituting a number for the analogRead(). So if I'm dividing by 16, 5 time constants would be 5 x 16, or 64 passes, before the output is, for all practical purposes, equal to the input.  But since the input is NOT a steady number, what you have is the equivalent of a low pass filter which should remove random noise for you very well. However, if the noise is periodic (like 60 hZ line noise or other EMI frequencies from nearby electronics) its not likely to be as effective.

If you want a faster response from the filter, cut the DIV_SHIFT to a lower number. Obviously if DIV_SHIFT is ZERO, there is NO filtering being done at all.

When I implement this in a project, I'll usually put this principal into a function call where I allocate a static array of as many accumulators as I have digital inputs to filter. I'll also arrange for an initialization that forces 5 * DIV_SHIFT  (64 in this case) iterations to occur the first time I call the function for a given analog input. That way I have valid filtered readings without waiting for 64 calls to go by, and future calls will only require a single pass.

If the basic idea works for you, and you need help creating such a call, I'll throw something together for you. Obviously instead of a function call, it would be better to implement what I've suggested as a class if you have as many alog inputs as you're dealing with.




thanks a lot

its realy hard  for me to understand how to incorporate this code in the code that i use..

i have no idea how it works.

:(

PeterPan321

thanks a lot

its realy hard  for me to understand how to incorporate this code in the code that i use..

i have no idea how it works.

:(
The thing is, there are only two ways to filter jittery analogs. One is via software, the other is via electrical/electronic solutions. For me, as I've found that even the simplest tests involving a very well controlled  analog input have shown that the a/d readings are not super stable. That together with all kinds of issues I've read with analogReads and various software tricks to make it better tells me that for the arduino, a software filtering approach is the way to go. And ANY software solution is going to require you to supply input from the a/d ins, and process them. If you have no way to get the raw analog inputs to test any method, a software solution of any kind will be tough. Good luck on this!


6v6gt

If you'd only said that you were going to do that earlier, I just wrote a very similar sketch last week :)

Anyway, thanks a lot for the responses!
I've got some other work right now, but I'll look into it further when  I find the time.
Great minds think alike !
Anyway, I've also created a class based solution which is published here post #25 http://forum.arduino.cc/index.php?topic=526806.25 which scales up better to multiple potentiometers.

ciabio

Great minds think alike !
Anyway, I've also created a class based solution which is published here post #25 http://forum.arduino.cc/index.php?topic=526806.25 which scales up better to multiple potentiometers.
thanks :)

can i copy your code and put it on the bottom of my code ? my pins A0-A10 are all multiplexer it works the same?

thanks

:)

6v6gt

The class I supplied is a generalised solution to minimising 'flicker' in potentiometers (or any other similar analog source).
Since it does not exist as a library, you would have to copy the .h and the .cpp file into your sketch folder and then
in your main sketch have an this statement: #include "HystFilter.h". These new files would be visible in the IDE when the is sketch is reopened.

However, the midi controller library is a complex system and the code would have to be integrated at the point where the potentiometer (or other analog source) is read.
I think the integration has to be left to PieterP or someone with sufficient experience of the midi controller library.
I have quickly looked ( I don't know the library at all) but if there was a means of inputting an analog value instead of a simply specifying a pin to read, then it could be easier.

There would have to be one instance of the HystFilter for each potentiometer.

ciabio

The class I supplied is a generalised solution to minimising 'flicker' in potentiometers (or any other similar analog source).
Since it does not exist as a library, you would have to copy the .h and the .cpp file into your sketch folder and then
in your main sketch have an this statement: #include "HystFilter.h". These new files would be visible in the IDE when the is sketch is reopened.

However, the midi controller library is a complex system and the code would have to be integrated at the point where the potentiometer (or other analog source) is read.
I think the integration has to be left to PieterP or someone with sufficient experience of the midi controller library.
I have quickly looked ( I don't know the library at all) but if there was a means of inputting an analog value instead of a simply specifying a pin to read, then it could be easier.

There would have to be one instance of the HystFilter for each potentiometer.

thanks for the time :)

i wait for other responses thanks again


PieterP

#29
Apr 18, 2018, 05:24 pm Last Edit: Apr 18, 2018, 05:33 pm by PieterP
I don't have much time right now, I'll try to integrate it later.

Analog reading is done in src/MIDI_Outputs/Analog.cpp.

For now, you can use the Analog::map function.

You could write out a different function for all inputs explicitly, but it's better to use lambda functions.
If you want to do it automatically, you have to use the latest code on the lambda branch that supports capturing lambda expressions, and the following code:

Code:
#include <MIDI_Controller.h> // Include the library
#include "HystFilter.h"

Analog potentiometers[] = {
  {A0, MIDI_CC::Channel_Volume, 1},
  {A1, MIDI_CC::Channel_Volume, 2},
  {A2, MIDI_CC::Channel_Volume, 3},
  {A3, MIDI_CC::Channel_Volume, 4},
};

HystFilter hystFilters[] = {
  {1024, 128, 2}, // 10 bit ADC = 1024, 128 discrete output values required, margin = 2 units (of 1024)
  {1024, 128, 2},
  {1024, 128, 2},
  {1024, 128, 2},
};

const size_t nb_pots = sizeof(potentiometers) / sizeof(potentiometers[0]);
const size_t nb_hyst = sizeof(hystFilters) / sizeof(hystFilters[0]);
static_assert(nb_pots == nb_hyst, "Error: number of Analog potentiometers should be the same as the number of HystFilters");

void setup() {
  for (size_t i = 0; i < nb_pots; i++)
    potentiometers[i].map([i](int raw){ return (int) hystFilters[i].getOutputLevel(raw) << 3; });
}

void loop() {
  // Refresh the MIDI controller (check whether the potentiometer's input has changed since last time, if so, send the new value over MIDI)
  MIDI_Controller.refresh();
}

Compiled, but didn't test.


Go Up