I am trying to write a code that takes a list flow_rate, changes it into a segmented list list_segmented of length segment_len. Then with that segmented list, I take each index and make it a list of data_segment.
I am getting stuck trying to figure out how to make each list_segmented[i] = data_segment. The last part of the code calls another function for data_segment in which I have previously written and can import it.
Appreciate your help.
def flow_rate_to_disorder_status(flow_rate,segment_len,interval,threshold):
inlist = flow_rate[:]
list_segmented = []
disorder_status = []
while inlist:
list_segmented.append(inlist[0 : segment_len])
inlist[0 : segment_len] = []
for i in range(0, len(list_segmented)):
data_segment = list_segmented[i]
condition = sym.has_symptom(data_segment, interval, threshold)
disorder_status.append(condition)
Initial function:
def has_symptom(data_segment,interval,threshold):
max_ratio = 1 # maximum ratio allowed when dividing
# data points in interval by len data_segment
# for our example it is 1
# NOTE: max_ratio can NOT be less than threshold
# to define the range of the given interval:
min_interval = interval[0]
max_interval = interval[1]
# create an empty list to add to data points that fall in the interval
symptom_yes = []
# create a loop function to read every point in data_segment
# and compare wether or not it falls in the interval
for i in range(0, len(data_segment)):
if min_interval <= data_segment[i] <= max_interval:
# if the data falls in interval, add it to list symptom_yes
symptom_yes.append(data_segment[i])
# to get the fraction ration between interval points and total data points
fraction_ratio = len(symptom_yes) / len(data_segment)
# if the ratio of data points that fall in interval to total points in
# data segments is more than or equal to threshold and less than or equal
# to max_ratio (1 in our case) then apply condition
if threshold <= fraction_ratio <= max_ratio:
condition = True # entire segment has the symptom
else:
condition = False # entire segment does NOT have the symptom
return condition
You nearly did it:
for i in range(0, len(data_segment)): # <-- looping thru data_segment
# data_segment = list_segmented[i] <-- this was back to front.
list_segmented[i] = data_segment # <-- this will work
note: there are cleaner ways of doing this in python (like list comprehension).
Anyway, good question. Hope that helps.
It looks like the lines
condition = sym.has_symptom(data_segment, interval, threshold)
disorder_status.append(condition)
should each be indented by one more level to be inside the for loop, so that they are executed for each data segment.
You presumably also want to return disorder_status at the end of the function.
I need to read a temperature reading from a DS18B20 sensor using Raspberry Pi 3 and Python.
The problem is the refresh rate of the sensor (~1 sec)
I need to read from sys/bus/w1/devices/28-041670f43bff/w1_slave and use the integer i get to display a temperature on a 7 segment display connected directly to my GPIOs (not using any hardware multiplexing - i2c....etc)
In order to display a two digit temperature, I need to turn on and off the digits really fast (faster than the sensor refreshes)
This is the small piece of code used to get the integer temperature:
def temperature():
with open ("/sys/bus/w1/devices/28-041670f43bff/w1_slave") as q:
r=q.read()
temp=r[69:71]
t=int (temp)
return t
But i need to call this function many times per second in order to get a good display on the 7 segment display.
This is how i thought of doing it:
#the temperature() function returns a two digit int
while True:
GPIO.output(31,0)
GPIO.output(temp[temperature()/10], 1) # temp is a dictionary used to know which segments to light up to show numbers
time.sleep(0.0005)
GPIO.output(31,1)
GPIO.output(37,0)
GPIO.output(temp[temperature()%10], 1)
time.sleep(0.0005)
GPIO.output(37,1)
But this code just makes one digit light up, wait ~1sec, light up the other digit, wait ~1sec.....and so on.
Any ideas of how to do this are very appreciated.
Rather than implement this functionality on your own, you should instead use the libraries out there that address this particular bit of your code inherently. In this case, I'd suggest you use W1ThermSensor. You can find the documentation at:
https://github.com/timofurrer/w1thermsensor
and you can install it using:
pip install w1thermsensor
It does support the DS18B20, and offers an exact analogue to your use case in the README.
From the docs for the package:
from w1thermsensor import W1ThermSensor
sensor = W1ThermSensor()
temperature_in_celsius = sensor.get_temperature()
temperature_in_fahrenheit = sensor.get_temperature(W1ThermSensor.DEGREES_F)
temperature_in_all_units = sensor.get_temperatures([
W1ThermSensor.DEGREES_C,
W1ThermSensor.DEGREES_F,
W1ThermSensor.KELVIN
])
In many cases, particularly for popular hardware devices, you'll find that there are libraries already available to use within python, and that will all you to quickly move on to writing the bits of code unique to your own particular needs.
Note: According to the technical discussion in the following link, if the DS18B20 is set to 12-bit temperature resolution, the temperature conversion will take 750 ms, or 3/4 of a second. If you set the hardware to do 9-bit resolution, the conversion time in hardware is 93.75 ms. I suspect this is the root of your once-per-second issue.
https://www.maximintegrated.com/en/app-notes/index.mvp/id/4377
There is some discussion of this issue in this Question:
https://raspberrypi.stackexchange.com/questions/14278/how-to-change-ds18b20-reading-resolution
See the second Answer, regarding the configDS18B20 utility.
With the resolution set to 9-bit, you may be able to adjust the w1thermsensor RETRY_DELAY_SECONDS / RETRY_ATTEMPTS value combination in the source code and get what you need. It's unclear to me if the retry delay has any affect on the actual polling of the device. It looks like it is there for device finding. Though, as I said, that interval may impact polling a single device. I simply didn't read through the source code enough to see when and where it comes into play.
Happy New Year!
I'd throw the display routine into its own thread so that you don't have to think about it in your main loop. The code below should demonstrate this concept. Set "testing" to False to see if it works with your hardware.
#!/usr/bin/python
import time
import threading
import Queue
import random
# Set this to False to read the temperature from a real sensor and display it on a 7-digit display.
testing = True
def temperature_read(q):
# Read the temperature at one second intervals.
while True:
if testing:
r = '-' * 69 + '%02d' % (random.randrange(100)) + 'blahblah' * 4
else:
r = open('/sys/bus/w1/devices/28-041670f43bff/w1_slave', 'r').read()
print r
# The temperature is represented as two digits in a long string.
# Push the digits into the queue as a tuple of integers (one per digit).
q.put((int(r[69]), int(r[70])))
# Wait for next reading.
# (Will w1_slave block until the next reading? If so, this could be eliminated.)
time.sleep(1.0)
def temperature_display(q):
# Display the temperature.
# Temperature is two digits, stored separately (high/low) for more efficient handling.
temperature_h = temperature_l = 0
while True:
# Is there a new temperature reading waiting for us?
if not q.empty():
temperature = q.get()
# If it's None, we're done.
if temperature is None:
break
# Load the two digits (high and low) representing the temperature.
(temperature_h, temperature_l) = temperature
if testing:
print 'displayH', temperature_h
time.sleep(0.05)
print 'displayL', temperature_l
time.sleep(0.05)
else:
GPIO.output(31,0)
GPIO.output(temperature_h, 1) # temp is a dictionary used to know which segments to light up to show numbers
time.sleep(0.0005)
GPIO.output(31,1)
GPIO.output(37,0)
GPIO.output(temperature_l, 1)
time.sleep(0.0005)
GPIO.output(37,1)
# Clean up here. Turn off all pins?
# Make a queue to communicate with the display thread.
temperature_queue = Queue.Queue()
# Run the display in a separate thread.
temperature_display_thread = threading.Thread(target=temperature_display, args=(temperature_queue,))
temperature_display_thread.start()
# Run the reader.
try:
temperature_read(temperature_queue)
except:
# An uncaught exception happened. (It could be a keyboard interrupt.)
None
# Tell the display thread to stop.
temperature_queue.put(None)
# Wait for the thread to end.
temperature_display_thread.join()
To support another reading (transmission), I just put it in the read loop rather than adding another thread for it. I changed the queue so that you could easily move it to another thread but I suspect you'll add more inputs so this is probably a reasonable way to do it unless the read frequency of one needs to be much different. (Even then, you could do things with counters in the loop.)
#!/usr/bin/python
import time
import threading
import Queue
import random
# Set this to False to read the temperature from a real sensor and display it on a 7-digit display.
testing = True
def observe(q):
while True:
# Make a temperature reading.
if testing:
r = '-' * 69 + '%02d' % (random.randrange(100)) + 'blahblah' * 4
else:
r = open('/sys/bus/w1/devices/28-041670f43bff/w1_slave', 'r').read()
print 'temperature ->', r
# The temperature is represented as two digits in a long string.
# Push the digits into the queue as a tuple of integers (one per digit).
q.put(('temperature', int(r[69]), int(r[70])))
# Make a transmission reading.
if testing:
r = random.randrange(1,6)
else:
r = 0 # Put your transmission reading code here.
print 'transmission ->', r
q.put(('transmission', r))
# Wait for next reading.
# (Will w1_slave block until the next reading? If so, this could be eliminated.)
time.sleep(1.0)
def display(q):
# Display the temperature.
# Temperature is two digits, stored separately (high/low) for more efficient handling.
temperature_h = temperature_l = transmission = 0
while True:
# Is there a new temperature reading waiting for us?
if not q.empty():
reading = q.get()
# If it's None, we're done.
if reading is None:
break
elif reading[0] == 'temperature':
# Load the two digits (high and low) representing the temperature.
(x, temperature_h, temperature_l) = reading
elif reading[0] == 'transmission':
(x, transmission) = reading
if testing:
print 'displayH', temperature_h
time.sleep(0.05)
print 'displayL', temperature_l
time.sleep(0.05)
print 'transmission', transmission
time.sleep(0.05)
else:
GPIO.output(31,0)
GPIO.output(temperature_h, 1) # temp is a dictionary used to know which segments to light up to show numbers
time.sleep(0.0005)
GPIO.output(31,1)
GPIO.output(37,0)
GPIO.output(temperature_l, 1)
time.sleep(0.0005)
GPIO.output(37,1)
# Clean up here. Turn off all pins?
# Make a queue to communicate with the display thread.
readings_queue = Queue.Queue()
# Run the display in a separate thread.
display_thread = threading.Thread(target=display, args=(readings_queue,))
display_thread.start()
# Observe the inputs.
try:
observe(readings_queue)
except:
# An uncaught exception happened. (It could be a keyboard interrupt.)
None
# Tell the display thread to stop.
readings_queue.put(None)
# Wait for the thread to end.
display_thread.join()
Here's a version which only reads the temperature every tenth time but reads the transmission every time. I think you'll see how to easily tweak this to meet your needs.
I would make separate threads for each reader but it would complicate the thread management quite a bit.
#!/usr/bin/python
import time
import threading
import Queue
import random
# Set this to False to read the temperature from a real sensor and display it on a 7-digit display.
testing = True
def observe(q):
count = 0
while True:
# Only read the temperature every tenth time.
if (count % 10 == 0):
# Make a temperature reading.
if testing:
r = '-' * 69 + '%02d' % (random.randrange(100)) + 'blahblah' * 4
else:
r = open('/sys/bus/w1/devices/28-041670f43bff/w1_slave', 'r').read()
print 'temperature ->', r
# The temperature is represented as two digits in a long string.
# Push the digits into the queue as a tuple of integers (one per digit).
q.put(('temperature', int(r[69]), int(r[70])))
# Make a transmission reading.
if testing:
r = random.randrange(1,6)
else:
r = 0 # Put your transmission reading code here.
print 'transmission ->', r
q.put(('transmission', r))
# Wait for next reading.
if testing:
time.sleep(0.5)
else:
time.sleep(0.1)
count += 1
def display(q):
# Display the temperature.
# Temperature is two digits, stored separately (high/low) for more efficient handling.
temperature_h = temperature_l = transmission = 0
while True:
# Is there a new temperature reading waiting for us?
if not q.empty():
reading = q.get()
# If it's None, we're done.
if reading is None:
break
elif reading[0] == 'temperature':
# Load the two digits (high and low) representing the temperature.
(x, temperature_h, temperature_l) = reading
elif reading[0] == 'transmission':
(x, transmission) = reading
if testing:
print 'displayH', temperature_h
time.sleep(0.05)
print 'displayL', temperature_l
time.sleep(0.05)
print 'transmission', transmission
time.sleep(0.05)
else:
GPIO.output(31,0)
GPIO.output(temperature_h, 1) # temp is a dictionary used to know which segments to light up to show numbers
time.sleep(0.0005)
GPIO.output(31,1)
GPIO.output(37,0)
GPIO.output(temperature_l, 1)
time.sleep(0.0005)
GPIO.output(37,1)
# Clean up here. Turn off all pins?
# Make a queue to communicate with the display thread.
readings_queue = Queue.Queue()
# Run the display in a separate thread.
display_thread = threading.Thread(target=display, args=(readings_queue,))
display_thread.start()
# Observe the inputs.
try:
observe(readings_queue)
except:
# An uncaught exception happened. (It could be a keyboard interrupt.)
None
# Tell the display thread to stop.
readings_queue.put(None)
# Wait for the thread to end.
display_thread.join()
Below is a short piece of python code.. it's for a sensor reading light or darkness. What I want it to do when the value drops below 500 print "light" and when it's above 500 print "Dark". This pretty much works but the text is repeated for every reading.. while I only want it to be printed upon a change.. anyone has any idea how to do this? I did quite a bit of shell programming.. but somehow this simple issue I can't get it done in python..
#!/usr/bin/python
import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BCM)
# Define function to measure charge time
def RCtime (PiPin):
measurement = 0
# Discharge capacitor
GPIO.setup(PiPin, GPIO.OUT)
GPIO.output(PiPin, GPIO.LOW)
time.sleep(0.1)
GPIO.setup(PiPin, GPIO.IN)
# Count loops until voltage across
# capacitor reads high on GPIO
last = 9
while (GPIO.input(PiPin) == GPIO.LOW):
measurement += 1
if measurement < 500:
print last
if last == 0:
print "light"
last = 1
if measurement >500:
print "dark"
last = 0
print last
return measurement
# Main program loop
while True:
print RCtime(4) # Measure timing using GPIO4
I think you have the idea right in the if measurement < 500: condition, printing "light" only when last was different. You just have to repeat similar logic in the > 500 condition. But the real problem is that last here is a local variable, so the value will get reset to 9 on every call. So you need to remove the last=9, and define last outside of the function and declare it as global inside the function:
#in main program
last = 9
def RCTime ...:
global last
....
Since you're returning value on each function execution I think the best idea would be to compare it in the while loop and keep the function only for getting the data.
Something along these lines:
previous, current = None, None
def RCtime (PiPin):
[...]
while True:
measurement = RCtime(4)
previous, current = current, measurement<500
if current != previous:
# value changed...
# `current` is bool and True if there is light.
# or you can just deal with the value itself for logic
print measurement
Otherwise returning the value of last and then passing it on when function is next time called is also an acceptable solution.
I simulate the sensor's readings using a list named readings, the rest of the code can be directly translated to your use case
readings = [ 600, 600, 550, 501, 450, 400, 400, 460, 520, 600, 600]
dark = None
for i, reading in enumerate(readings):
dark_now = 'Dark' if reading < 500 else 'Light'
if dark_now != dark:
dark = dark_now
print i, reading, dark
Output
0 600 Light
4 450 Dark
8 520 Light
I am working on a small proof of concept and using python to illustrate the idea. The idea is the program will run in a loop and will check for input. Now if the input falls under a threshold then it sends a notification. But I am trying to restrict the notification at an interval of 4 sec. And thats where I am loosing either with the logic or with some syntax. Either way It is doing some unexpected things
1: keep on entering 0 and it will display the below threshold message until it reaches a 4 sec mark and then it just prints out the message 4 times in a single line. I want them to show after every 4 seconds. The idea is (A)the input might change in that 4 sec and the notification switches. (B)I want the notification to play out as a reminder with a recurrence of 4 sec every time the script hits the condition if weightIn < 0.5..if it is true then the notification goes out after 4 sec from the first time it was sent
Sorry if I tried over explaining it. I am pretty new to python
import threading
def main():
while True:
weightIn = float(input("Get value: "))
threshold = .5
def operation():
if weightIn < 0.5:
#send notification at an interval of 4 sec
threading.Timer(4.0, operation).start()
print("Below weight threshhold...send notification")
else:
print("You are good")
if threshold is not None:
operation()
main()
First avoid declaring functions in a loop. Then ask yourself, if an object would not be appropriate, because it properly encloses state attributes.
But for the algorithmic part, it is simple (if I have correctly understood the problem ...). Store the timestamp of last notification and send a new one if more the 4 seconds have elapsed. In pseudo-code :
last_notification_time = 0
threshold = 0.5
loop:
weighIn = get_new_value()
if weightIn < threshold:
time = get_time_in_seconds()
if (time > last_notification_time + 4):
last_notification_time = time
send_notification()
# actual processing
In Python, it could look like :
#import time
def main():
last_notification_time = 0
threshold = 0.5
while True:
weighIn = float(input("Get value: "))
if weightIn < threshold:
cur_time = time.time()
if (cur_time > last_notification_time + 4):
last_notification_time = time
print("Below weight threshhold...send notification")
# actual processing
main()
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST,PORT))
screen_width = 0
screen_height = 0
while True:
client_socket.send("loc\n")
data = client_socket.recv(8192)
pos_coordinates = data.split()
if(not(pos_coordinates[-1] == "eom" and pos_coordinates[0] == "start")):
continue
if (screenw != int(pos_coordinates[2])):
screenw = int(pos_coordinates[2])
screenh = int(pos_coordinates[3])
blalba(pos_coordinates)
How can i get the average of 3 pos_coordinates list values ?
For example if pos_coordinates[8] contains the value 345, i want to get the average of that value and use the averaged value. the reason i want to do this, is because i am getting noise from the image detected through the camera and i thought the best way to go about this is to get the average of the values in order to get the value that i want. Any examples on how to do this?
For getting the average of the whole list;
average = float(sum(pos_coordinates))/len(pos_coordinates)
If you just want to get the average of a subset, use a slice;
subset = pos_coordinates[3:9]
average = float(sum(subset))/len(subset)
In python 3.x the explicit float conversion is not necessary anymore to get accurate division.