Checking Measurement Data Error - 'If only Constants arrive' - python

Example:
If the Photovoltaik Number is constant over a certain period, there is something wrong, because Solar Power Irradation fluctuats alot. So One should want to recognize this bevarioul pattern to e.g. restart the system.
old_pv = []
while True:
try:
count = 1
sunny_scraper.driver.current_url
new_pv = sunny_scraper.scrape()
old_pv.append(new_pv)
count += 1
if count in [19, 20]:
if len(list(set(old_pv))) == 1:
sunny_scraper.start_browser()
sunny_scraper.accept_cookies()
sunny_scraper.enter_email_password()
new_pv = sunny_scraper.scrape()
time.sleep(5)
old_pv = []
old_pv.append(new_pv)
else:
time.sleep(10)
except:
time.sleep(120)
sunny_scraper.start_browser()
sunny_scraper.accept_cookies()
sunny_scraper.enter_email_password()
sunny_scraper.scrape()
time.sleep(10)
pv - Photovoltaic (solar power)
the pv value is scraped in high resolution (~ 10s), I work in Solar Industrie for Power Prediction using All Sky Imager. Sometimes the value freezes (reason unclear), so restarting the script is the current idea.
What other implementation options would be conceivable and useful? I would be happy for inspiration.

Related

Comparing the same variable against itself?

thank you in advance for reading and taking the time to troubleshoot this with me!
Let me first start off with the important stuff:
Target Device:
Raspberry Pi 4B
Electronic-Salon Relay Hat
Development Environment:
macOS Catalina
PyCharm
Python 2.7.10
At my home I have a spring that serves my home with water. The solution I came up with to prevent dirty water caused by bad rainy weather loosening up the ground soil from entering my cistern is closing a valve and waiting for about 12 hours for the water to clear back up. Then I open the valve and clear water flows into my cistern providing my home with water, and that solution works really well.
I recently came up with the conclusion that I want to automate this process with a normally open solenoid. I purchased a Raspberry Pi, a Relay Hat, and an Ambient Weather weather station.
What I'm looking to do with Python 2.7.10 is check the same variable against itself after an allotted time. In this example, I'm checking the relative barometric pressure against itself and I'm wanting to look for a significant negative change in that variable.
i.e "What does variable A have? Okay, now wait 3 seconds. What does A have now? How much has it changed?"
This is what I've bodged together so far, how can I improve? Thank you.
At first I was thinking maybe I should plot a chart with the data and compare the difference between the two plot points, but I wasn't sure how to use Matplotlib.
# This is the executing script for the Smart Valve.
# This project is powered by raspberry pi and 120 angry pixies.
import time,imp
from ambient_api.ambientapi import AmbientAPI
# This code will pull the data from the weather computer
api = AmbientAPI()
devices = api.get_devices()
device = devices[0]
time.sleep(1) #pause for a second to avoid API limits
# The code below is meant for telling the python interpreter to behave normally whether or not it's in a RPi env or a
# developer env
try:
imp.find_module('RPi.GPIO')
import RPi.GPIO as GPIO
except ImportError:
"""
import FakeRPi.GPIO as GPIO
OR
import FakeRPi.RPiO as RPiO
"""
import FakeRPi.GPIO as GPIO
# this code compares the rate of change for the barometric pressure over time and checks if rate is negative
a1 = None
a2 = None
while True:
weatherData = device.get_data()
data = dict(weatherData[0])
pressure = data[u'baromrelin']
wind = data[u'windspeedmph']
rain = data[u'hourlyrainin']
a1 = pressure
time.sleep(30)
a2 = pressure
print("A1 is equal to " + str(a1))
print("A2 is equal to " + str(a2))
if a1 > a2:
print("we should close the valve, it'll rain soon")
continue
elif a1 == a2:
print("It's all hunky dory up here!")
break
Firstly i would avoid Python 2. 2020 was the last year to it. Now Python 3 all the way. Also you won't need u'text' as everything is unicode.
The problem with your code is that you reference the same pressure variable twice.
Here's why. You do nothing to change it after the wait. Its effectively:
pressure = 123.4
first = pressure # 123.4
thread.sleep(30)
second = pressure # 123.4
second == first
# True
I would avoid setting two measurements in a single. And I'm going to use previous and current as names as it makes more sense than a1 or first.
Without a loop.
prev = None
# Pass 1
weatherData = device.get_data()
data = dict(weatherData[0])
pressure = data[u'baromrelin']
curr = pressure # e.g. 123.4
if prev is None or curr > prev:
print("Pressure is rising!")
# Current iteration's current pressure will become the next iteration's previous pressure. You could even then see curr = None because we about to overwrite on next iteration.
prev = curr # 123.4
time.sleep(30)
# Pass 2
weatherData = device.get_data()
data = dict(weatherData[0])
pressure = data[u'baromrelin']
curr = pressure # e.g. 234.5
if prev is None or curr > prev:
print("Pressure is rising!")
# 234.5 > 123.4
time.sleep(30)
With a loop:
WAIT = 30
prev = None
while True:
weatherData = device.get_data()
data = dict(weatherData[0])
pressure = data[u'baromrelin']
curr = pressure
if prev is None or curr > prev:
print("Pressure is rising!")
break
print(f"Nothing usual. Waiting {WAIT} seconds...")
time.sleep(WAIT)
The general design pattern for this is:
oldval = 0
while 1:
newval = read_the_value()
if oldval != newval:
take_action()
oldval = newval
sleep(xxx)
I think that will work for you.

Simple python script using 100% CPU on rPi3B+

I have raspberry pi model 3b+ with a HC-SR04 ultrasonic distance sensor (there is also a couple of ds18b20 and a DHT21 but I think they're unrelated to my problem).
I have found a python script to make measurements from it and modified it to my needs - mostly to take a couple of reading spanned in time, take an average from it and map the value to range from 0 to 100, as the percentage and commit it to the influx database for grafana and domoticz.
The code:
#source: https://tutorials-raspberrypi.com/raspberry-pi-ultrasonic-sensor-hc-sr04/
#Libraries
import RPi.GPIO as GPIO
import time
from influxdb import InfluxDBClient
import sys
# https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Python
import requests
client = InfluxDBClient(database='pellet')
series = []
#GPIO Mode (BOARD / BCM)
GPIO.setmode(GPIO.BCM)
#set GPIO Pins
GPIO_TRIGGER = 23
GPIO_ECHO = 22
#set GPIO direction (IN / OUT)
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)
def distance():
# set Trigger to HIGH
GPIO.output(GPIO_TRIGGER, True)
# set Trigger after 0.01ms to LOW
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
StartTime = time.time()
StopTime = time.time()
# save StartTime
while GPIO.input(GPIO_ECHO) == 0:
StartTime = time.time()
# save time of arrival
while GPIO.input(GPIO_ECHO) == 1:
StopTime = time.time()
# time difference between start and arrival
TimeElapsed = StopTime - StartTime
# multiply with the sonic speed (34300 cm/s)
# and divide by 2, because there and back
distance = (TimeElapsed * 34300) / 2
return distance
def pellet(dist):
# zmierzona odleglosc
# dist = distance()
# do zmierzenia poziom maksymalny
# 63 - do pokrywy
in_min = 63
# do zmierzenia poziom minimalny
in_max = in_min + 100
#wyjscie jako procent, od 0 do 100
out_min = 100
out_max = 0
# map z arduino: https://www.arduino.cc/reference/en/language/functions/math/map/
return (dist - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
def loop():
# nie wiecej jak 200 iteracji
loop = 200
# suma
total = 0
# tabelka z pojedynczmi wynikami
measurements = []
# liczba pomiarow do zrobienia
counter = 10
counter1 = 0
# czas pomiedzy pomiarami
sleep =30
#
while loop > 0:
loop -= 1
time.sleep(sleep)
# koniec, jesli wykonano liczbe pomiarow
if counter == 0:
#print(total/10)
return pellet(total/10), measurements
break
if loop == 0 and counter1 != 0:
return pellet(total/counter1), measurements
break
if loop == 0 and (counter1 == 0 or total == 0):
GPIO.cleanup()
sys.exit()
dist = distance()
# jesli wynik jest zly
if dist < 63 or dist > 163:
print("nie ok")
continue
counter -= 1
measurements.append(dist)
counter1 += 1
total += dist
print("total po ",counter1 , "sek: ", total, "dist: ", dist)
print(total/10)
#return total/10
if __name__ == '__main__':
try:
#dist = distance()
#print ("Measured Distance = %.1f cm" % dist)
#print (pellet(dist))
loop=loop()
print("avg :", loop[0])
#print("measurs :", loop[1])
#print("test :", loop[1][2])
if (1):
point = {
"measurement": "pellet",
"tags": {
"location": "piwnica",
"type": "hc-sr04"
},
"fields": {
"value": loop[0],
"raw_measurement1": loop[1][0],
"raw_measurement2": loop[1][1],
"raw_measurement3": loop[1][2],
"raw_measurement4": loop[1][3],
"raw_measurement5": loop[1][4],
"raw_measurement6": loop[1][5],
"raw_measurement7": loop[1][6],
"raw_measurement8": loop[1][7],
"raw_measurement9": loop[1][8],
"raw_measurement10": loop[1][9]
}
}
series.append(point)
client.write_points(series)
url = 'http://localhost:8080/json.htm?type=command&param=udevice&nvalue=0&idx=13&svalue='+str(loop[0])
r = requests.get(url)
GPIO.cleanup()
# Reset by pressing CTRL + C
except KeyboardInterrupt:
print("Measurement stopped by User")
GPIO.cleanup()
The problem is I noticed that the CPU temperature graph was elevated, with many short valleys to the about correct temperature.
When I ssh'd to the pi and run htop I saw that it was this script that is using 100% cpu.
But the weirdest thing is that the script is running in crontab every 15 minutes since yesterday, from about 14:30 and raise CPU temp started today at around 11:00.
I'm not a developer or a programmer and I just mostly copied the code from around the web so I don't know if this is some part of the code that did this (but why after 21 hours?) or what and why, and how to debug and fix it.
so it isn't just enviromental thing as the pi is in the attic where is about 5C to 10C.
Thank you for your help.
Here:
while GPIO.input(GPIO_ECHO) == 0:
StartTime = time.time()
this says "if the pin is 0, save the time, if the pin is zero, save the time, if the pin...." incessantly. You'll want to wait a little time after each check
while GPIO.input(GPIO_ECHO) == 0:
time.sleep(0.001) # 1 ms
StartTime = time.time()
The check itself probably takes ~us, so this will reduce CPU usage by 99%. You might want to do the same for the pin==1 case, depending on how accurate you need the times to be.
While it is impossible to know for sure where the issue lies without debugging directly on your system, and a glance at the code reveals several possible bugs in the logic, the one place that is most likely to cause the issue is the distance function.
As #mdurant already pointed out, your read loops will jump the CPU usage to 100%, but I suspect there is also another issue:
The trigger code and the read code are time sensitive!
The problem is, we don't know how much time actually passes between
# set Trigger to HIGH
GPIO.output(GPIO_TRIGGER, True)
# set Trigger after 0.01ms to LOW
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
and:
# save StartTime
while GPIO.input(GPIO_ECHO) == 0:
StartTime = time.time()
# save time of arrival
while GPIO.input(GPIO_ECHO) == 1:
StopTime = time.time()
While this simple algorithm - pulse trigger, count return interval will work on a microcontroller like Arduino, it is not reliable on a full blown computer like Raspberry Pi.
Microcontrollers run a single thread, with no OS or task scheduling, so they run code in real time or as close to it as possible (borrowing a few interrupts here and there).
But in your case you are running an interpreted language on a multitasking operating system, without explicitly giving it any high priority.
This means, your process could be suspended just enough time to miss the return "ping" and get stuck in the first loop.
This may only happen rarely when something else puts a load on the Pi, which would explain why you only noticed the issue after 21 hours running.
You should implement some form of timeout for GPIO reading loops and return an error value from the distance function if that timeout is reached to ensure you do not have an infinite loop when something goes wrong with the hardware, or you miss the return ping due to scheduling issues.
I suggest something like this:
def distance():
MAX_READ_ATTEMPTS = 10000 #this is a random value I chose. You will need to fine-tune it based on actual hardware performance
# set Trigger to HIGH
GPIO.output(GPIO_TRIGGER, True)
# set Trigger after 0.01ms to LOW
time.sleep(0.00001)
GPIO.output(GPIO_TRIGGER, False)
# lets not have any unneeded code here, just in case
# save StartTime
while GPIO.input(GPIO_ECHO) == 0 and retry_counter < MAX_READ_ATTEMPTS:
retry_counter += 1
StartTime = time.time()
# maximum number of retries reached, returning with error condition
if retry_counter == MAX_READ_ATTEMPTS:
return -1
reatry_counter = 0
# save time of arrival
while GPIO.input(GPIO_ECHO) == 1 and retry_counter < MAX_READ_ATTEMPTS:
retry_counter += 1
StopTime = time.time()
# maximum number of retries reached, returning with error condition
if retry_counter == MAX_READ_ATTEMPTS:
return -1
# time difference between start and arrival
TimeElapsed = StopTime - StartTime
# multiply with the sonic speed (34300 cm/s)
# and divide by 2, because there and back
distance = (TimeElapsed * 34300) / 2
return distance
I am intentionally not adding a delay between reads, because I am not sure what the tolerance for this measurement is in terms of timing, and sleep functions can't guarantee an exact delay (again, due to OS / CPU scheduling).
A brief 100% CPU load should be worth it to ensure accurate and valid measurements, as long as it is not kept up for too long, which our retry counting method should prevent.
Note that my only experience with ultrasonic sensors is using Arduino where a special pulseIn function is used that takes care of the implementation details of measurement so this solution is mostly an educated guess and I have no way of testing it.

Calculate probability of a flush in poker

I have the code to keep going through a loop until a flush is made.
now I am trying to make it where I use count to show how many hands are dealt then divide by one to get the probability.
For the code i have right now using count it returns it as 0
from collections import namedtuple
from random import shuffle
Card = namedtuple("Card", "suit, rank")
class Deck:
suits = '♦♥♠♣'
ranks = '23456789JQKA'
def __init__(self):
self.cards = [Card(suit, rank) for suit in self.suits for rank in self.ranks]
shuffle(self.cards)
def deal(self, amount):
return tuple(self.cards.pop() for _ in range(amount))
flush = False
count = 0
while not flush:
deck = Deck()
stop = False
while len(deck.cards) > 5:
hand = deck.deal(5)
# (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))
if len(set(card.suit for card in hand)) > 1:
#print(f"No Flush: {hand}")
continue
print(f"Yay, it's a Flush: {hand}")
flush = True
break
if flush:
break
else:
count +=1
print(f'Count is {count}')
There is a little more code at the top used for init methods if you need that too let me know
Your code (and what is available in #Mason's answer) will estimate the probability of eventually getting your first flush. To estimate the probability of getting a flush in general, which I believe is what you're after, you have to run that experiment many thousands of times over. In practice this is called a Monte Carlo simulation.
Side note: When I began learning about Monte Carlos I thought they were a sort of "magical", mysteriously complex thing... mostly because their name sounds so exotic. Don't be fooled. "Monte Carlo" is just an overly fancy and arbitrary name for "simulation". They can be quite elementary.
Even so, simulations are kind of magical because you can use them to brute force a solution out of a complex system even when a mathematical model of that system is hard to come by. Say, for example, you don't have a firm understanding of combination or permutation math - which would produce the exact answer to your question "What are the odds of getting a flush?". We can run many simulations of your card game to figure out what that probability would be to a high degree of certainty. I've done that below (commented out parts of your original code that weren't needed):
from collections import namedtuple
from random import shuffle
import pandas as pd
#%% What is the likelyhood of getting flush? Mathematical derivation
""" A flush consists of five cards which are all of the same suit.
We must remember that there are four suits each with a total of 13 cards.
Thus a flush is a combination of five cards from a total of 13 of the same suit.
This is done in C(13, 5) = 1287 ways.
Since there are four different suits, there are a total of 4 x 1287 = 5148 flushes possible.
Some of these flushes have already been counted as higher ranked hands.
We must subtract the number of straight flushes and royal flushes from 5148 in order to
obtain flushes that are not of a higher rank.
There are 36 straight flushes and 4 royal flushes.
We must make sure not to double count these hands.
This means that there are 5148 – 40 = 5108 flushes that are not of a higher rank.
We can now calculate the probability of a flush as 5108/2,598,960 = 0.1965%.
This probability is approximately 1/509. So in the long run, one out of every 509 hands is a flush."""
"SOURCE: https://www.thoughtco.com/probability-of-a-flush-3126591"
mathematically_derived_flush_probability = 5108/2598960 * 100
#%% What is the likelyhood of getting flush? Monte Carlo derivation
Card = namedtuple("Card", "suit, rank")
class Deck:
suits = '♦♥♠♣'
ranks = '23456789JQKA'
def __init__(self):
self.cards = [Card(suit, rank) for suit in self.suits for rank in self.ranks]
shuffle(self.cards)
def deal(self, amount):
return tuple(self.cards.pop() for _ in range(amount))
#flush = False
hand_count = 0
flush_count = 0
flush_cutoff = 150 # Increase this number to run the simulation over more hands.
column_names = ['hand_count', 'flush_count', 'flush_probability', 'estimation_error']
hand_results = pd.DataFrame(columns=column_names)
while flush_count < flush_cutoff:
deck = Deck()
while len(deck.cards) > 5:
hand_count +=1
hand = deck.deal(5)
# (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))
if len(set(card.suit for card in hand)) == 1:
# print(f"Yay, it's a Flush: {hand}")
flush_count +=1
# break
# else:
# print(f"No Flush: {hand}")
monte_carlo_derived_flush_probability = flush_count / hand_count * 100
estimation_error = (monte_carlo_derived_flush_probability - mathematically_derived_flush_probability) / mathematically_derived_flush_probability * 100
hand_df = pd.DataFrame([[hand_count,flush_count,monte_carlo_derived_flush_probability, estimation_error]], columns=column_names)
hand_results = hand_results.append(hand_df)
#%% Analyze results
# Show how each consecutive hand helps us estimate the flush probability
hand_results.plot.line('hand_count','flush_probability').axhline(y=mathematically_derived_flush_probability,color='r')
# As the number of hands (experiments) increases, our estimation of the actual probability gets better.
# Below the error gets closer to 0 percent as the number of hands increases.
hand_results.plot.line('hand_count','estimation_error').axhline(y=0,color='black')
#%% Memory usage
print("Memory used to store all %s runs: %s megabytes" % (len(hand_results),round(hand_results.memory_usage(index=True,deep=True).sum()/1000000, 1)))
In this particular case, thanks to math, we could have just confidently derived the probability of getting a flush as 0.1965%. To prove that our simulation arrived at the correct answer we can compare its output after 80,000 hands:
As you can see, our simulated flush_probability (in blue) approaches the mathematically derived probability (in black).
Similarly, below is a plot of the estimation_error between the simulated probability and the mathematically derived value. As you can see, the estimation error was more than 100% off in the early runs of the simulation but gradually rose to within 5% of the error.
If you were to run the simulation for, say, twice the number of hands, then we would see that the blue and red lines eventually overlap with the black horizontal line in both charts - signifying that the simulated answer becomes equivalent to the mathematically derived answer.
To simulate or not to simulate?
Finally, you might wonder,
"If I can generate a precise answer to a problem by simulating it, then why bother with all the complicated math in the first place?"
The answer is, as with just about any decision in life, "trade offs".
In our example, we could run the simulation over enough hands to get a precise answer with a high degree of confidence. However, if one is running a simulation because they don't know the answer (which is often the case), then one needs to answer another question,
"How long do I run the simulation to be confident I have the right answer?"
The answer to that seems simple:
"Run it for a long time."
Eventually your estimated outputs could converge to a single value such that outputs from additional simulations don't drastically change from prior runs. The problem here is that in some cases, depending on the complexity of the system you're simulating, seemingly convergent output may be a temporary phenomena. That is, if you ran a hundred thousand more simulations, you might begin to see your outputs diverge from what you thought was your stable answer. In a different scenario, despite having run tens of millions of simulations, it could happen that an output still hasn't converged. Do you have the time to program and run the simulation? Or would a mathematical approximation get you there sooner?
There is yet another concern:
*"What is the cost?"
Consumer computers are relatively cheap today but 30 years ago they cost $4,000 to $9,000 in 2019 dollars. In comparison, a TI89 only cost $215 (again, in 2019 dollars). So if you were asking this question back in 1990 and you were good with probability math, you could have saved $3,800 by using a TI89. Cost is just as important today: simulating self-driving cars and protein folding can burn many millions of dollars.
Finally, mission critical applications may require both a simulation and a mathematical model to cross check the results of both approaches. A tidy example of this is when Matt Parker of StandUpMaths calculated the odds of landing on any property in the game of Monopoly by simulation and confirmed those results with Hannah Fry's mathematical model of the same game.
I think this should work for you. It depends on how your Deck() is defined though, I guess. I tried to leave your code in a similar state to how you had written it, but had to make some changes so you wouldn't get errors. I also didn't actually run it, since I don't have Deck defined.
flush = False
count = 0
while not flush:
deck = Deck()
stop = False
while len(deck.cards) > 5:
hand = deck.deal(5)
# (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))
if len(set(card.suit for card in hand)) > 1:
print(f"No Flush: {hand}")
else:
print(f"Yay, it's a Flush: {hand}")
flush = True
break
count +=1
print(f'Count is {count}')
But it will not give you the probability of getting a flush, and you'll honestly probably run out of cards in deck before you get a flush in almost every run...
I would consider changing the code to this so, to take out some redundancies.
flush = False
count = 0
while not flush:
deck = Deck()
while len(deck.cards) > 5:
hand = deck.deal(5)
# (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))
if len(set(card.suit for card in hand)) == 1:
print(f"Yay, it's a Flush: {hand}")
flush = True
break
else:
print(f"No Flush: {hand}")
count +=1
print(f'Count is {count}')

How do I speed up incredibly slow iteration through pandas dataframe?

I have collected 500ms stock data for several weeks. No I am wanting to go through each days data an iterate through it to determine at any given last price value, how many times a specific lowerbound would be passed followed by a specific upperbound being passed for the rest of the day. The lowerbound has to be passed before the script starts searching for whether the upperbound will be reached.
So essentially if the last price at row i is 10 and the lowerbound then is 9 and 11. The code will first try to find a moment when the remaining rows i+1...i+2... are reach the lowerbound, as soon as the lower bound is reached the code switches into looking for when the upperbound is reached. If the upperbound is reached then the success will add 1 and the code starts looking for the lowerbound again, doing this whole process again.
This entire process occurs for every single row, so essentially for each row we will have a column for how many times a successful lower and upper bound reach occurred in the rows following that given row.
The problem I am having is that I have about 14400 rows per day, and about 40 days so around 576000 rows of data. The iteration takes absolutely forever, and in order for me to do this across all of my data I will need my computer to run a few days. Surely I am not doing this in the most efficient way possible am I? Can anybody maybe point to a concept that I can rewrite this code in a much more effective way? Or am I just stuck waiting for ever for it to prepare my data?
range_per = .00069 #the percentage determining lower and upper bound
data['Success?']=np.nan
data['Success? Count']=np.nan
#For every row count how many times the trade in the range would be successful
for i in range(0,len(data)):
last_price = data.at[i,'lastPrice']
lower_bound = last_price - last_price*range_per
upper_bound = last_price + last_price*range_per
lower_bound_reached = False
upper_bound_reached = False
success=0
for b in range(i+1,len(data)):
last_price = data.at[b,'lastPrice']
while lower_bound_reached == False:
if lower_bound - last_price >=0:
upper_bound_reached = False
lower_bound_reached = True
else:
break
while (upper_bound_reached == False and lower_bound_reached ==True):
if upper_bound - last_price <=0:
success+=1
lower_bound_reached = False
upper_bound_reached = True
else:
break
print('row %s: %s times' %(i, success))
data['Success? Count'][i] = success
if success>0:
data['Success?'][i] = True
else:
data['Success?'][i] = False

Stuff isn't appending to my list

I'm trying to create a simulation where there are two printers and I find the average wait time for each. I'm using a class for the printer and task in my program. Basically, I'm adding the wait time to each of each simulation to a list and calculating the average time. My issue is that I'm getting a division by 0 error so nothing is being appended. When I try it with 1 printer (Which is the same thing essentially) I have no issues. Here is the code I have for the second printer. I'm using a queue for this.
if printers == 2:
for currentSecond in range(numSeconds):
if newPrintTask():
task = Task(currentSecond,minSize,maxSize)
printQueue.enqueue(task)
if (not labPrinter1.busy()) and (not labPrinter2.busy()) and \
(not printQueue.is_empty()):
nexttask = printQueue.dequeue()
waitingtimes.append(nexttask.waitTime(currentSecond))
labPrinter1.startNext(nexttask)
elif (not labPrinter1.busy()) and (labPrinter2.busy()) and \
(not printQueue.is_empty()):
nexttask = printQueue.dequeue()
waitingtimes.append(nexttask.waitTime(currentSecond))
labPrinter1.startNext(nexttask)
elif (not labPrinter2.busy()) and (labPrinter1.busy()) and \
(not printQueue.is_empty()):
nexttask = printQueue.dequeue()
waitingtimes.append(nexttask.waitTime(currentSecond))
labPrinter2.startNext(nexttask)
labPrinter1.tick()
labPrinter2.tick()
averageWait = sum(waitingtimes)/len(waitingtimes)
outfile.write("Average Wait %6.2f secs %3d tasks remaining." \
%(averageWait,printQueue.size()))
Any assistance would be great!
Edit: I should mention that this happens no matter the values. I could have a page range of 99-100 and a PPM of 1 yet I still get divided by 0.
I think your problem stems from an empty waitingtimes on the first iteration or so. If there is no print job in the queue, and there has never been a waiting time inserted, you are going to reach the bottom of the loop with waitingtimes==[] (empty), and then do:
sum(waitingtimes) / len(waitingtimes)
Which will be
sum([]) / len([])
Which is
0 / 0
The easiest way to deal with this would just be to check for it, or catch it:
if not waitingtimes:
averageWait = 0
else:
averageWait = sum(waitingtimes)/len(waitingtimes)
Or:
try:
averageWait = sum(waitingtimes)/len(waitingtimes)
except ZeroDivisionError:
averageWait = 0

Categories