Search code examples
pythonloopsmultidimensional-arraynested-loopsadc

Python array elements append from ADS1115


I wanted to measure voltage with command chan = and write the voltage value to array which has dimensions 128x128 and contains 16384 voltage values. I set ADS1115 sample rate to 128 samples per second. The time of data acquisition should be 128 seconds x 128 samples = 16384 total samples.

The problem is that the program is not working for 128 seconds and it stops much earlier. I suppose, there are some problems elsewhere.

The code look like this:

import numpy as np
import time
from matplotlib import pyplot as plt

import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
from timeit import default_timer as timer


i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS.ADS1115(i2c)
ads.gain = 8
ads.mode = ADS.Mode.CONTINUOUS
ads.data_rate = 128
chan = AnalogIn(ads, ADS.P0, ADS.P1)

trig = AnalogIn(ads, ADS.P2, ADS.P3)


level = 192 # trigger level

totalElapsed = 0

buffer = []

while True:

     if (trig.value > level):
     
         start = timer()
         thisTime =  timer() - start

         while(len(buffer) < 16384):
 
              buffer.append(chan.value)
              
              totalElapsed += thisTime
              
              print(">>>>>>>>>>>> Total Elapsed: " + str(totalElapsed) + "s")

         # Make into numpy array and reshape to (128,128)
         a = np.array(buffer).reshape((128,128))

         # Reverse alternate rows
         for r in range(1,128,2):
            a[r] = a[r][::-1]


         #Generate image
         plt.imsave('/home/rpi/Downloads/mystm_pic.tiff', a, cmap='afmhot') # file location

         plt.imshow(a, cmap='afmhot')

         plt.show()

To sum up, I want to measure voltage and write its value to array until the array is fully filled, i. e. 16384 written measured voltages in time 128 seconds, assuming speed of 128 samples/second.

Thank you very much for help and your suggestions.

Edit:

The correct code should like this?

import numpy as np
import time
from matplotlib import pyplot as plt

import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
from timeit import default_timer as timer

RATE = 128
SAMPLES = 16384    

i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS.ADS1115(i2c)
ads.gain = 8
ads.mode = ADS.Mode.CONTINUOUS
ads.data_rate = RATE
chan = AnalogIn(ads, ADS.P0, ADS.P1)

trig = AnalogIn(ads, ADS.P2, ADS.P3)


level = 192 # trigger level

sample_interval = 1.0 / ads.data_rate

repeats = 0
skips = 0

data = [None] * SAMPLES

start = time.monotonic()
time_next_sample = start + sample_interval



if (trig.value > level):
     

    for i in range(SAMPLES):
 
         while time.monotonic() < (time_next_sample): 
              pass

         data[i] = chan.value

         # Loop timing
         time_last_sample = time.monotonic()
         time_next_sample = time_next_sample + sample_interval
         if time_last_sample > (time_next_sample + sample_interval):
            skips += 1
            time_next_sample = time.monotonic() + sample_interval

         # Detect repeated values due to over polling
         if data[i] == data[i - 1]:
            repeats += 1

    end = time.monotonic()
    total_time = end - start


    # Make into numpy array and reshape to (128,128)
    a = np.array(data).reshape((128,128))

    # Reverse alternate rows
    for r in range(1,128,2):
       a[r] = a[r][::-1]

    print(">>>>>>>>>>>> Total Elapsed: " + str(total_time) + "s")    

         #Generate image
    plt.imsave('/home/rpi/Downloads/mystm_pic.tiff', a, cmap='afmhot') # file location

    plt.imshow(a, cmap='afmhot')

    plt.show()

Solution

  • When you request AnalogIn.value, you’ll get the latest measured value. If you call this in quick succession, you’ll simply repeatedly get the same measurement - it does not automatically wait for the ADC to finish reading. Thus, by calling it in a loop, you’re just going to fill the buffer as quickly as the Pi can perform 16384 I2C reads to your ADC.

    As far as I can tell, the AdaFruit drivers don’t have any mechanism to properly synchronize with the ADC. Thus, you’ll have to implement your own timing setup: in each loop, you will want to delay for 1/128 seconds before the next read. You can do this by checking time.monotonic() in a loop; that will be more reliable than using time.sleep().

    See https://github.com/adafruit/Adafruit_CircuitPython_ADS1x15/blob/main/examples/ads1x15_fast_read.py for a complete example of the timing loop in action.