wollewald/ADS1115_WE

Hysteresis

Closed this issue · 27 comments

Sometimes the analog potentiometer keeps jumping between to values without me moving the potentiometer, e.g. (first column are millis(), last column values):

117311 - Panel 3: potentiometer: 116
117336 - Panel 3: potentiometer: 117
117436 - Panel 3: potentiometer: 116
117461 - Panel 3: potentiometer: 117
117511 - Panel 3: potentiometer: 116
117536 - Panel 3: potentiometer: 117
117636 - Panel 3: potentiometer: 116
117661 - Panel 3: potentiometer: 117
117711 - Panel 3: potentiometer: 116
117736 - Panel 3: potentiometer: 117
117911 - Panel 3: potentiometer: 116
117936 - Panel 3: potentiometer: 117
117986 - Panel 3: potentiometer: 116
118011 - Panel 3: potentiometer: 117
118061 - Panel 3: potentiometer: 116
118086 - Panel 3: potentiometer: 117
118161 - Panel 3: potentiometer: 118
118211 - Panel 3: potentiometer: 119
118236 - Panel 3: potentiometer: 121
118261 - Panel 3: potentiometer: 122
118286 - Panel 3: potentiometer: 123
118436 - Panel 3: potentiometer: 124
118461 - Panel 3: potentiometer: 123
118486 - Panel 3: potentiometer: 124
118536 - Panel 3: potentiometer: 123
118561 - Panel 3: potentiometer: 124
118586 - Panel 3: potentiometer: 123
118711 - Panel 3: potentiometer: 124
118736 - Panel 3: potentiometer: 123
118761 - Panel 3: potentiometer: 124
118786 - Panel 3: potentiometer: 123
118836 - Panel 3: potentiometer: 124

After some reading it seems some 'Hysteresis' needs to be added. Do you have any suggestions/ideas about this? Maybe you already use something similar yourself already?

There are only a handful of arduino libraries that I can find that provide this, e.g. https://github.com/cellularmitosis/Deadband

I'll give that one a try.

Well that was simple to implement, https://github.com/cellularmitosis/Deadband/blob/master/Deadband/examples/Knob/Knob.ino works fine combined with this library. Having something like that in this library would be nice but not essential I guess. Let's discuss or feel free to close this issue.

works fine combined with this library.

Hmm, I spoke too soon, it's quite unresponsive in the first and last range of the potentiometer. Bleh.

it's quite unresponsive in the first and last range of the potentiometer. Bleh

Testing with no hysteresis and just getResult_mV also shows a small 'gap' at the start and end of my potentiometers. It's like the starting point of the potentiometer is not completely at the beginning, I only see values coming in after rotating it a little. Same applies to the end section of the potentiometer.

Is this normal and related to the fact I have cheapo potentiometers or could it be library related? Should I use a hex schmitt trigger for debouncing, as talked about here: http://www.ganssle.com/debouncing-pt2.htm

With getResultWithRange function returns int values so it might be that if you use a range of 0 to 127 you might have problems to get to 127. This line
result = (int16_t) (1.0 * result * voltageRange / maxMillivolt);
would cut a 126.9 to 126. Maybe a "round" would have been better. But this explains only a gap of 1 unit. And getResult_mV should show no gap at all. In theory it could be related with the ADS1115, but I don't think so, because its precision is much higher than 5V/127.
And usually even cheap potis should be good enough the relatively rough range of 0 - 127. I just checked some potis I found in my drawer with my multimeter. If I turn them from one limit to another I get values from very near to 0 Ohm to the max limit and the max limit is very much reproducible. Maybe you can check your potis in a similar way. I have not read yet the article behind the link in detail, but I have the feeling it should work without this.
Do you have a curcuit diagram for your project which you could send? Is it maybe an issue with the power supply (is it stable)?

here's the circuit diagram (using an ESP32 instead of UNO though):
esp32-ADS1115-potentiometer

Could it be that 100nF capacitor?

Maybe you can check your potis in a similar way.

I will.

Is it maybe an issue with the power supply (is it stable)?

I'm using an USB cable for now from my Macbook to ESP32.

would cut a 126.9 to 126. Maybe a "round" would have been better.

Think so too...

And usually even cheap potis should be good enough the relatively rough range of 0 - 127.

So you've never seen an analog input signal from a potentiomter, fed through ADS1115, constantly change slightly?

The capacitor should only have only a positive influence. The only load on the power supply is the ADS1115, which is very small, so the supply should be stable. Which leads leads to the question what else it could be. I will test the same circuit later, since I have not tried a potentiometer with the ADS1115 yet - to answer your last question.

There's actually a lot more running on the power supply, but I used that circuit diagram to show how I hooked up the ADS1115 potentiometers. A picture of the actual project (for which I don't have a proper diagram) because pictures are always nice right ;) It's a midi controller starting to take shape:

midi-controller

So yea I guess it could be anything. I have a second ADS1115 lying around, and if necessary, I'll test with that one as well. But I remember seeing this 'hysteresis' issue before, with other potentiometers, with no other devices connected. Oh well, I hope your research comes up with something, thanks!

since I have not tried a potentiometer with the ADS1115 yet -

It's interesting you say this, because there's a fritizing sketch in this repository that uses potentiometers ;)

I have just checked what I get when I use the Result_Format_Options.ino sketch with a poti and a wiring according to your simplified fritzing scheme. I used getResultWithRange(-127, 127, 5000). For the limits I get 0 and 126. 0 and 126 is reproducible. below you find the screen shots. What I can't check is if the values in between are reproducible since I can't ensure I get exactly the same position.
Zero
Full

Do you have the chance to check if your power supply is stable? Just with a simple multimeter or a free channel of the ADS1115?

@thijstriemstra :
I think that the hysteresis or any filter should be in another Lib. And since the 127 is the max value you want to use, to get to it i would use -128 to 128 as the range since the number is truncated.

Some tips that could help you:
1 - You can try to put a 100n capacitor between the channels and GND, maybe even a 10k series resistor between the potentiometer and the capacitor (making a simple RC filter, with 1ms time constant, that would get 99% of a step in 5ms).
2 - You can also filter in your code. Make your range go from 0 to 1280 (to gain some precision), and you can either make a IIR or FIR filter, and divide the result by 10 before using it. You could also implement the hysteresis before the division (see code later).
3 - Use the biggest range you can (0-4.096V) so that your circuit will be less sensitive to input voltage variation. You could also use a dedicated 3.3V voltage regulator (an LDO) for the pots (but than your getResultWithRange would have maxVoltage=3300mV).
4 - As of now, your potentiometer can probably rotate around 265~300 degrees. That's almost only 2degrees per midi value you want. That's requires some steady hands. You could use a multiturn potentiometer (more expensive, but easier to set, normally they are 10turns from min to max so would give you 20 degrees per midi value, at the expense of taking some time to travel around).

It's nice to see a project getting done. Chapeau! Respekt!

idea for 2)
IIR setup (newer values have lower weigth):
damping = 0.9; // too higher a value (closer to 1) can make some unreachable values.
at every ad conversion:
midi10 = midi10 * damping + getResultWithRange(-1280,1280) * (1-damping);

FIR setup (for the average of the last n samples, better for n=power of 2):

count = 0;
results[n] = {0};
midi10 = 0;
sum_results = 0; //to keep track of the sum, avoiding to sum the full array every time.

at every ad conversion:

sum_results -= results[count];
results[count] = getResultWithRange(-1280,1280);
sum_results += results[count];
count += 1;
if(count >= n) count = 0; 
midi10 = sum_results/n; //if n is power of two the division can be replaced by a right shift.

for the histeresis:

if((midi10+5)>(midi*10) || (midi10-5)<(midi*10)) {
     midi = midi10 / 10;
}

oh, and the schmit trigger would not work... it cleans "digital" signals, not analogs. It would change your range to only two values...

the deadband lib seems nice to be used. It's a more elaborated version of the hysteresis concept i wrote above, but it would only help on the cases where your "stable" input changes between only two values.

@thijstriemstra , I just had some other insights:

  • put the +5V and the gnd of the potentiometer as close as possible to the ADS1115 pins to avoid supply noise (as opposed to the power rail of the breadboard).

  • the time constant of the RC filter I specified above also depends on the potentiometer equivalent resistance (thevenin theorem).

@thijstriemstra , you could also monitor the power supply voltage if you have a free ADS1115 channel and use this value like this getResultWithRange(-127,127, powerSupplyVoltage) . Then you are independent from deviations from the 5V.

@thijstriemstra , wrt my last comment: it won't help with noise of course, but the influence of varying loads on the supply voltage could be eliminated.

@thijstriemstra
Since we are sharing our setups, mine is a ESP8266+ADS1115, powered by the usb cable:
pot

My voltage reading was pretty stable, without caps, RCs or software filters... (but very hard to make a single step), I'm printing "CH0", but it was actually the Ch3 that i was reading:
midi.

You will probably need an voltage regulator for the potentiometers reading. The voltage source in your picture is not very "stable".

Wow, thanks for all the feedback guys, that's a lot to digest. I will try all of it on the weekend. I must note that for most of the time the value is stable, but sometimes suddenly one or more potentiometers start spewing values that are 1, sometimes 2, apart. To be continued..

ps. I picked a ADS1115 for the potentiometers because I thought they would be extremely accurate compared to a normal analog pin but maybe I'm exaggerating. In any case, my project ran out of pins and I2C is only option I see available, hence something like ADS1115.

The voltage source in your picture is not very "stable".

About the power supply, it's another cheapo ebay thing. A handful of B0505S-1W's arrived this week, it seemed to me those would make a stable output combined with that cheapo power supply? See https://datasheetspdf.com/pdf-file/1320473/REICU/B0505S-1W/1

oh, and the schmit trigger would not work... it cleans "digital" signals, not analogs. It would change your range to only two values...

Thanks, I wasn't sure about that. They helped a lot with rotary encoders but these are digital of course.

Do you have the chance to check if your power supply is stable?

By the way, what is considered stable? In the screenshots you both posted I see about 1 to 2 mV variance?

Yes, good point, stability is relative. I mean can your power supply drop so much that your values drop 1 or more units on your range of 0 to 127? 1 unit in your range would be 5V / 127 = ~39 mV.

I have changed the mapping. Now it's rounding and therefore, as an example, a 126.50 in the intermediate calculations will deliver a 127.

@thijstriemstra I am so much focussed on the power supply, because I made some bad experience with the 5 Volt delivered by an Arduino UNO. If I only attach an LED of few mA to it the voltage drops by some Millivolt. So if you use getResultWithRange(-127, 127, 5000) you might not get 127 when you are at the upper limit of the potentiometer. If you check the power supply voltage in parallel to your measurements and it's always at 5 Volt even if you observe values of below 127 then just forget everything I mentioned.

I had some good hope that the latest release with rounding would fix the issue but it didn't so I'll take a look at the other suggestions, starting with the power supply.

@thijstriemstra, I too would focus on the power supply, but apparently the B0505S-1W are not very stable either, and since it's a switched power supply, it is noisy... Give it a shot. Maybe putting an 1k series resistor from it's power supply and a buffer capacitor (electrolitic 100uF/10uF + 100n/10n ceramic in parallel) before the pots to filter out this noise (well, you could try this without the B0505S too). Be aware that it's a isolated voltage source, so if you power only part of your circuit with this, you will need to tie the input and outputs GND's together.

image
image

I would suggest using an 0.5% linear voltage regulator to reduce from 5V to 3.3 to power the pots, or an LM431C, which is not as simple to use (but cheaper) and has 0,5% precision, probably just around what you need. You won't need high precision resistors, but you are going to need to calibrate your input.
image
You will need to calculate R1 and R2 (2k2 and 10k) so that Vz is around 4V, and put a 1k series resistor (top resistor),

Or you could take a totally different approach: Instead of using the pot position to set the midi value, you could use it to set the midi value change...
Like if pot is from 40-60% doesn't change the midi value.
From 60-80% increases it slowly
80-100 increases fast.
20-40% decreases slowly
0-20% decreases fast.
Or make the speed related to the position, and keep a large deadband so that it won't change at random.

@thijstriemstra, @martinbra, I am reviewing open issues and I am a bit lost in this one. Can I close it?

Ok for me. 👍

Yes, I'll open a new one or add to this ticket when I get back to the particular project that uses this library.