How to precisly sample a sensor-signal in Python [duplicate] - python

This question already has answers here:
How to repeatedly execute a function every x seconds?
(22 answers)
Closed 4 years ago.
I want to write a Python program that will sample a sensor at a fixed sampling rate. Is there any elegant way of doing this?
Currently, I am using the time.time and time.sleep commands to enforce this manually. While this does work, it is creating a small drift. Also, it seems to be a not very nice way of doing so, and I hope there is a more pythonic way of doing this:
def mock_signal(x):
# Just a random number as the sensor signal
return np.random.random()*x
def sampling(fs=1, x=1):
T = 1/fs # sampling period
t_ground = time.time()
while True:
t_start = time.time()
y = mock_signal(x)
print('%.5f | Sensor Value %.2f' % (t_start - t_ground, y))
t_duration = time.time()
# Sleeping for the remaining period
time.sleep(T - (t_duration-t_start))
Ideally, I would like to have a function or class that would sample the sensor (basically call the 'mock_signal' function) and append the new sample to a list or array. The latest entry in said array should than be accessible by a call similar to the multiprocessings Connection.recv()
Thanks in advance :)

May you can try something like that.
import threading
t_ground = time.time()
def sampling():
t_ground = time.time()
threading.Timer(T, sampling).start()
t_start = time.time()
y = mock_signal(1)
print('%.5f | Sensor Value %.2f' % (t_start - t_ground, y))
It's just an example. You need to change it to your need.

Related

multithreading in python and time module [duplicate]

This question already has an answer here:
perf_counter is returning wrong time
(1 answer)
Closed 5 months ago.
I'm trying to learn multi_threading in python but when I try to print time.perf_counter() in order to see how much time the Main Threading takes to run the program which is in charge the output is a huge number (614691.9609577), but it should not even be 2 seconds. Can you explain the reason of this problem?
Thanks
import threading
import time
def have_breakfast():
time.sleep(3)
print("You had breakfast")
def make_bed():
time.sleep(4)
print("You made your bed")
def study():
time.sleep(5)
print("You finish studying")
x = threading.Thread(target = have_breakfast, args = ())
x.start()
y = threading.Thread(target = make_bed, args = ())
y.start()
z = threading.Thread(target = study, args = ())
z.start()
x.join()
print(threading.active_count())
print(threading.enumerate())
print(time.perf_counter())
From here:
time.perf_counter():
Return the value (in fractional seconds) of a performance counter,
i.e. a clock with the highest available resolution to measure a short
duration. It does include time elapsed during sleep and is
system-wide. The reference point of the returned value is undefined,
so that only the difference between the results of two calls is valid.
Use perf_counter_ns() to avoid the precision loss caused by the float
type.
New in version 3.3.
Changed in version 3.10: On Windows, the function is now system-wide.
In your case if you want to measure time you need to subtract two time intervals. E.g.:
t1_start = time.perf_counter()
# your code...
t2_stop = time.perf_counter()
print("Elapsed time: ", t2_stop - t1_start)

Python how to add another time interval to nested while?

for measurement from my custom weather station I'm currently using two nested while loops to gather measuremet in 5seconds during 5min period as follows:
interval = 300
short_interval = 5
while True:
start_time = time.time()
while time.time() - start_time <= interval:
measurement_start = time.time()
reset_counter()
while time.time() - measurement_start <= short_interval:
store_directions.append(wind_direction.get_value())
final_speed = calculate_speed(wind_interval)
store_speeds.append(final_speed)
measure_rain()
do other stuff, mqtt etc.
which works fine - storing every 5seconds and sending everything out every 5mins
What I'm bit struggling is to accomodate another timeinterval of 60mins to gather rainfall.
Now it's measured every 5mins with measure_rain()
What would be best way how to keep 5min measurements for wind and another one for rainfall which will take 60min?
Another while? I was trying that, but ended up messing everything up ;)
Thank you for any help!
That's a task for concurrent programming. Luckily, Python has native support for it using Coroutines and Tasks. You can either roll your own based on the event loop and the example given there, or, look at what's out there already. Two quick picks:
asyncio-periodic looks minimal; less than 200 LoC class; seems to do one thing (execute periodic tasks every N seconds). Not actively developed (but why would it need to?)
schedule: much larger, but expressive syntax (schedule.every(10).minutes.do(job)) and looking well maintained. Bigger codebase, but advertised as having no further dependencies.
you can define each sensor as class and assign short and long intervals for each sensor. However this is CPU intensive work because of while loop without sleep.
import time
class wind:
big_interval=10
short_interval=2
st_bigInterval=time.time()
st_shortInterval=time.time()
class rain:
big_interval=10
short_interval=2
st_bigInterval=time.time()
st_shortInterval=time.time()
while True:
if(time.time()-wind.st_shortInterval>wind.short_interval):
print("collect wind data")
wind.st_shortInterval = time.time()
if(time.time()-rain.st_shortInterval>rain.short_interval):
print("collect rain data")
rain.st_shortInterval = time.time()
if(time.time()-wind.st_bigInterval>wind.big_interval):
print("send wind data")
wind.st_bigInterval = time.time()
wind.st_shortInterval = time.time()
if(time.time()-rain.st_bigInterval>rain.big_interval):
print("send rain data")
rain.st_bigInterval = time.time()
rain.st_shortInterval = time.time()
More better approach is to use timeloop as below.
import time
from timeloop import Timeloop
from datetime import timedelta
tl = Timeloop()
#tl.job(interval=timedelta(seconds=2))
def collectWindData():
print( "2s job current time : {}".format(time.ctime()), "collect wind data")
#tl.job(interval=timedelta(seconds=5))
def sendWindData():
print ("5s job current time : {}".format(time.ctime()), "send wind data")
#tl.job(interval=timedelta(seconds=2))
def collectRainData():
print( "2s job current time : {}".format(time.ctime()), "collect rain data")
#tl.job(interval=timedelta(seconds=5))
def sendRainData():
print ("5s job current time : {}".format(time.ctime()), "send rain data")
tl.start()
while True:
time.sleep(10)
a roll your own using the built in asyncio module. It's a strange new way of thinking about programming and can be quite challenge to get your head around. Below is a niave implementation if you don't need to be precise on when you measured. You can make a precise version using a priority queue to put the next measurement first. A common approach to this problem is used in collision mechanics for games programming.
import asyncio
import random
async def measure_rain():
while True:
print(f'rainfall {random.randint(0,100)}') #measure rainfall
await asyncio.sleep(1)
return True
async def measure_wind():
while True:
print(f'windspeed: {float(random.randint(0, 100)/10)} m/s') #measure windspeed
await asyncio.sleep(3)
return True
async def main():
tasks = []
tasks.append(asyncio.create_task(measure_rain()))
tasks.append(asyncio.create_task(measure_wind()))
await *tasks
asyncio.run(main())

Python - How to Increment A Value As Time Passes [duplicate]

This question already has answers here:
How to create a python loop that allows other code to run as well
(3 answers)
Closed 1 year ago.
I'm trying to do something simple here, i want to increase my cost variable which is (100.00) by .01 every 5 minutes, so after every 5 minutes my new value/variable should be, 100.01, then 100.02, then 100.03 and so on..
but i can't figure out how to add it to my existing value.
Here is what i've tried so far, i've reduced the 300 seconds to 10 seconds to speed things up.
import time
import datetime
tracking = time.time()
def values():
global tracking
now = datetime.datetime.now()
cost = 100.00
increase = .01
newvalue = []
for x in range(1,1000):
print(x)
time.sleep(2)
if time.time() - 10 > tracking:
newvalue.append(float(increase))
print(newvalue)
print(now)
tracking = time.time()
values()
any help appreciated.
It seems like you want the += operator. This adds the right-hand value to the value to the value stored in the left-hand variable.
import time
import datetime
tracking = time.time()
def values():
global tracking
now = datetime.datetime.now()
cost = 100.00
increase = .01
for x in range(1,1000):
print(x)
time.sleep(2)
if time.time() - 10 > tracking:
cost += increase
print('Cost: {}'.format(cost))
print(now)
tracking = time.time()
values()
There are other issues to consider:
Floats are not a good way to store currency values. Because they store binary fractions, they cannot represent all decimal fractions. Consider using decimal.Decimal instead.
To track elapsed time, it's best to use time.monotonic. datetime.now() can be adjusted externally (e.g. by ntpdate), so you cannot assume a change in datetime.now represents elapsed time.
There doesn't seem to be a need to store tracking as a global.
In a single-threaded program, values will not exit until 1000 is reached, which means you can't have other program logic running while the cost is incrementing. Calculating the cost on-demand (as others have suggested) will allow you to run other program logic instead of just looping.
Try this
import time
def increase_value_evrey_t_sec(initail_value, interval, increase_by,stop_after = -1):
counter = 0
values = []
while counter < stop_after or stop_after == -1:
time.sleep(interval)
initail_value += increase_by
print(initail_value)
values.append(initail_value)
counter += 1
increase_value_evrey_t_sec(2,2,3,4)
increase_value_evrey_t_sec(2,2,3,4)

Implementing a timer(countdown) that runs pararell with the game logic [duplicate]

This question already has answers here:
How to set time limit on raw_input
(7 answers)
Closed 6 years ago.
I have created a mathematical quiz game that prints and equation to the user like, 5 + 3 = ?, and waits for the result. If the answer is right the user wins if not the user loses. I want to extend the game and add a feature that places a time limit of 3 seconds for the user to answer, if he don't the he loses.
At the beggining I tried using the time module and the time.sleep() function but this also delayed the whole program's logic.
Here is an idea with pseudo code:
if (answer = wrong || time = 0)
lost...
if you want to check if the user took to long when he answered you can use the time module to calculate the diffrence:
start_time = time.time()
show_question()
answer = get_answer()
end_time = time.time()
if (answer = wrong || end_time - start_time > 3)
lose()
if you want the user to loose when 3 seconds as passed (without waiting for them to input a answer) you will have to use threading, like this:
timer = threading.Timer(3, lose)
show_question()
answer = get_answer()
timer.cancel()
if (answer = wrong)
lose()

What's the proper way to write a game loop in Python?

I'm trying to write a python game loop that hopefully takes into account FPS. What is the correct way to call the loop? Some of the possibilities I've considered are below. I'm trying not to use a library like pygame.
1.
while True:
mainLoop()
2.
def mainLoop():
# run some game code
time.sleep(Interval)
mainLoop()
3.
def mainLoop():
# run some game code
threading.timer(Interval, mainLoop).start()
4.
Use sched.scheduler?
If I understood correctly you want to base your game logic on a time delta.
Try getting a time delta between every frame and then have your objects move with respect to that time delta.
import time
while True:
# dt is the time delta in seconds (float).
currentTime = time.time()
dt = currentTime - lastFrameTime
lastFrameTime = currentTime
game_logic(dt)
def game_logic(dt):
# Where speed might be a vector. E.g speed.x = 1 means
# you will move by 1 unit per second on x's direction.
plane.position += speed * dt;
If you also want to limit your frames per second, an easy way would be sleeping the appropriate amount of time after every update.
FPS = 60
while True:
sleepTime = 1./FPS - (currentTime - lastFrameTime)
if sleepTime > 0:
time.sleep(sleepTime)
Be aware thought that this will only work if your hardware is more than fast enough for your game. For more information about game loops check this.
PS) Sorry for the Javaish variable names... Just took a break from some Java coding.

Categories

Resources