Calibrating resistive weight sensors

Hi everyone,
I am trying to use some simple thin film resistive weight sensors. These sensors output a certain voltage given the pressure applied. However, the pressure/voltage curve is not linear, it is a 2nd degree polynomial function with a flat beginning of the curve (see picture below). I am using two sensors (their average voltage) to weight one shelf.

immagine

I have chosen a very stable high quality power supply for my circuit so that the voltage is quite stable.

Now comes the issue: estimating the weight based on the voltage. At first I have tried to use the filter calibrate_linear, with very scarce results. Then I remembered that the most similar approximation of the curve is a 2nd or 3rd degree polynomial function (see pic below), and I have tried that as a filter. The results, however, are very poor especially with low weights (the initial part of the curve).
500px-PolynomialFunctionsGraph

This is the latest code I have tried:

i2c:
  sda: 4
  scl: 5

ads1115:
  - address: 0x48
    id: ads1115_1
  - address: 0x49
    id: ads1115_2

sensor:
  - platform: ads1115
    ads1115_id: ads1115_1
    multiplexer: 'A0_GND'
    gain: 6.144
    name: "Rack1_Sensor1"
    update_interval: 1s
    id: "Rack1_Sensor1"
  - platform: ads1115
    ads1115_id: ads1115_2
    multiplexer: 'A0_GND'
    gain: 6.144
    name: "Rack1_Sensor2"
    update_interval: 1s
    id: "Rack1_Sensor2"
  - platform: template
    name: "Rack1 sensors average"
    id: "Rack1_Sensors_Average"
    lambda: |-
      return (id(Rack1_Sensor1).state + id(Rack1_Sensor2).state) / 2.000;
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: V
  - platform: template
    name: Rack1 weight
    id: "Rack1_Weight"
    lambda: |-
      return (id(Rack1_Sensor1).state + id(Rack1_Sensor2).state) / 2.000;
    update_interval: 5s
    accuracy_decimals: 3
    unit_of_measurement: kg
    filters:
      - calibrate_polynomial:
          degree: 3
          datapoints:
            # Map 0.0 (from sensor) to 0.0 (true value)
            - 4.775 -> 12.785
            - 4.768 -> 11.476
            - 4.757 -> 10.124
            - 4.742 -> 8.772
            - 4.723 -> 7.31
            - 4.711 -> 5.848
            - 4.638 -> 4.386
            - 4.57 -> 2.924
            - 4.44 -> 1.462

I tried using ranges (I could estimate the # of items placed on the sensor instead of their weight, since they are standard bottles), but it doesn’t allow me to differentiate if the bottles are full or not, so I really need to measure the weight.

What else can i try to approximate the curve better? Is there a way to define a more accurate f(x) and describe it in a lambda filter (I would actually like to write the mathematical equation in the lambda filter)?
Here’s the curve the computer calculated:

3rd degree polynomial function:
immagine

4th degree polynomial function:
immagine

Exponential function:
immagine

That’s going to be the same equation that ESPHome uses for it’s 3rd order approximation.

1 Like

Would it be feasible to use numerous smaller linear regressions that connect each point?

1 Like

I was just going to say maybe some kind of “piecewise linear interpolation” might fit ok.

images

Oh cool, thanks! I just found this thanks to you:

Configuration variables:

* method (*Optional*, string): The method for calculating the linear function(s). One of `least_squares` or `exact`. Defaults to `least_squares`.
1 Like

I didn’t realise you could use it like that. Nice.

It might be worth sampling more points just to be clear you do actually have a good representation of the underlying distribution?

    filters:
      - calibrate_linear:
        method: exact ## <--- This will use linear functions between your data points ###
          datapoints:
            # Map 0.0 (from sensor) to 0.0 (true value)
            - 4.775 -> 12.785
            - 4.768 -> 11.476
            - 4.757 -> 10.124
            - 4.742 -> 8.772
            - 4.723 -> 7.31
            - 4.711 -> 5.848
            - 4.638 -> 4.386
            - 4.57 -> 2.924
            - 4.44 -> 1.462

https://esphome.io/components/sensor/#calibrate-linear

2 Likes

I can sample as many datapoints as I want!
Actually, I don’t have many configurations.
I have 9 bottles, they could be empty or full. Given that I will always replace the full ones with empty ones (the bottles rack will never be empty), I can perform as many discreet measurements as I want!

1 Like