Interpolate between elements in an array of floats - python

I'm getting a list of 5 floats which I would like to use as values to send pwm to an LED. I want to ramp smoothly in a variable amount of milliseconds between the elements in the array.
So if this is my array...
list = [1.222, 3.111, 0.456, 9.222, 22.333]
I want to ramp from 1.222 to 3.111 over say 3000 milliseconds, then from 3.111 to 0.456 over the same amount of time, and when it gets to the end of the list I want the 5th element of the list to ramp to the 1st element of the list and continue indefinitely.

do you think about something like that?
import time
l = [1.222, 3.111, 0.456, 9.222, 22.333]
def play_led(value):
#here should be the led- code
print value
def calc_ramp(given_list, interval_count):
new_list = []
len_list = len(given_list)
for i in range(len_list):
first = given_list[i]
second = given_list[(i+1) % len_list]
delta = (second - first) / interval_count
for j in range(interval_count):
new_list.append(first + j * delta)
return new_list
def endless_play_led(ramp_list,count):
endless = count == 0
count = abs(count)
while endless or count!=0:
for i in range(len(ramp_list)):
play_led(ramp_list[i])
#time.sleep(1)
if not endless:
count -= 1
print '##############',count
endless_play_led(calc_ramp(l, 3),2)
endless_play_led(calc_ramp(l, 3),-2)
endless_play_led(calc_ramp(l, 3),0)

another version, similar to the version of dsgdfg (based on his/her idea), but without timing lag:
import time
list_of_ramp = [1.222, 3.111, 0.456, 9.222, 22.333]
def play_LED(value):
s = ''
for i in range(int(value*4)):
s += '*'
print s, value
def interpol(first, second, fract):
return first + (second - first)*fract
def find_borders(list_of_values, total_time, time_per_step):
len_list = len(list_of_values)
total_steps = total_time // time_per_step
fract = (total_time - total_steps * time_per_step) / float(time_per_step)
index1 = int(total_steps % len_list)
return [list_of_values[index1], list_of_values[(index1 + 1) % len_list], fract]
def start_program(list_of_values, time_per_step, relax_time):
total_start = time.time()
while True:
last_time = time.time()
while time.time() - last_time < relax_time:
pass
x = find_borders(list_of_values,time.time(),time_per_step)
play_LED(interpol(x[0],x[1],x[2]))
start_program(list_of_ramp,time_per_step=5,relax_time=0.5)

Related

Why does the volume of a PyAudio stream sometimes 'half', and other times, produce unwanted white noise when 'converted bytes' are divided by 2?

I am 'new' to using the PyAudio module in Python 3.7, and have already done a few 'neat' things with the PyAudio interface. I have figured out how to generate and play some 'custom pitches' bunched together in sequences where the data first gets converted to a -32768 to +32768 range (using int(n).to_bytes() and then n = data.from_bytes()to convert back and forth from bytes to integer, alter the values, and then convert back to bytes again for the stream).
While my values are integers, I can divide by 2 to 'halve' my volume for the 'custom pitches', but, when I divide by 2 if I make 'n' (the integer variable used for the integer values) equal to the converted data of the 'sounds\hello.wav' file, it doesn't 'halve' the volume, but it creates unwanted white noise instead. If I don’t divide by 2, my 'sounds\hello.wav' file plays fine.
Where my comments are in 'all caps', that is where the 'problem' is. The 'capitalized comment section' shows four different 'options' that can be used for the value of 'n', before n gets converted back to bytes, and gets written to the stream. Three of those four 'options' work, but I have been trying to figure out why 'the fourth option' is giving me a 'problem'. The 'four options' that 'reproduces the problem' is why my code generates two warnings, and is not a 'programmatical problem'. What I am working on, might one day help create a whole new technology for sound and music. Here is my code...
import math
import time
import wave
import pyaudio
pitches = 0
position = []
start = time.time()
started = True
oldTime = 0
delta = 0
run_time = 0
val = []
lastVal = []
lastVal2 = []
count = 0
def get_pitches():
global val
global run_time
global lastVal
global lastVal2
global position
global pitches
n = 0
val = []
pitches = 0
# Store the offset and the increment (through time) into result.
run_time += delta
# PITCHES GO HERE.
n += add_pitch_with_time_stamp(offset = 0.0, increment = 0.0, volume = 0.5, pitch_stamp=[0.01, 0.015, 0.02, 0.015], time_stamp=[.5, .5, .5, .5], transition_time_stamp = [10, 10, 10, 10], voice = "sounds\\ah.wav")
n += add_pitch_with_time_stamp(offset = 0.0, increment = 0.0, volume = 0.5, pitch_stamp=[0.01, 0.02, 0.03, 0.02], time_stamp=[1, 1, 1, 1], transition_time_stamp = [10, 10, 10, 10], voice = "sounds\\ah.wav")
#n += add_pitch(offset = .01, increment = .1, volume = 1)
#n += add_pitch(offset = 0.015, increment = -.001, volume = 1)
#n += add_pitch(offset = 0.04, increment = 0, volume = 1)
# Average out the pitches before returning n.
if pitches != 0:
n /= pitches
return n
def add_pitch(offset, increment, volume):
global pitches
global delta
global run_time
global val
global lastVal
global lastVal2
global position
# Match the size of arrays for positions and last recorded values.
if pitches >= len(position):
position.append(0)
if pitches >= len(lastVal):
lastVal.append(0)
if pitches >= len(lastVal2):
lastVal2.append(0)
# Get the calculated pitch for the wave.
pitch = ((run_time - start) * increment) + offset
# If the pitch is out of range set the result to 0.
if 0.3 > pitch >= 0:
if pitches < len(lastVal):
lastVal2[pitches] = lastVal[pitches]
val.append((1 + math.sin(((position[len(val) - 1]) * pitch) * math.pi * 2) * 0.5 * volume) - 0.5)
if pitches < len(lastVal):
lastVal[pitches] = val[len(val) - 1]
result = ((val[len(val) - 1] * 0x7f) + 0x80)
else:
result = 0
# Increase pitches per function call to determine the average value for n.
pitches += 1
else:
result = 0
return result
def add_pitch_with_time_stamp(offset, increment, volume, pitch_stamp, time_stamp=None, transition_time_stamp=None, voice=None):
global pitches
global delta
global run_time
global val
global lastVal
global lastVal2
global position
# Match size for time stamp.
for i in range(0, len(time_stamp)):
if (i + 1) > len(time_stamp):
time_stamp.append(1)
# Match size for transition time stamp.
for i in range(0, len(pitch_stamp)):
if (i + 1) > len(transition_time_stamp):
transition_time_stamp.append(1)
# Get a total time modulation from the time stamp.
time_modulation = 0
for i in range(0, len(time_stamp)):
time_modulation += time_stamp[i]
# Get the time index.
time_flow = (time.time() - start) % time_modulation
# Store the time transitions into f.
f = get_transition_value(pitch_stamp, transition_time_stamp, time_stamp, time_flow)
# Match the size of arrays for positions and last recorded values.
if pitches >= len(position):
position.append(0)
if pitches >= len(lastVal):
lastVal.append(0)
if pitches >= len(lastVal2):
lastVal2.append(0)
# Get the calculated pitch for the wave.
pitch = (((run_time - start) * increment) + (f + offset))
# If the pitch is out of range set the result to 0.
if 0.3 > pitch >= 0:
if pitches < len(lastVal):
lastVal2[pitches] = lastVal[pitches]
#print (data2)
if voice is None:
val.append((1 + math.sin(((position[len(val) - 1]) * pitch) * math.pi * 2) * 0.5 * volume) - 0.5)
else:
val.append((1 + math.sin(((position[len(val) - 1]) * pitch) * math.pi * 2) * 0.5 * volume) - 0.5)
if pitches < len(lastVal):
lastVal[pitches] = val[len(val) - 1]
result = ((val[len(val) - 1] * 0x7f) + 0x80)
else:
result = 0
# Increase pitches per function call to determine the average value for n.
pitches += 1
else:
result = 0
return result
def get_transition_value(value_list, transition_list, t_stamp, t_flow):
t_total = 0
t_position = t_flow
t_index = 0
for i in range(0, len(t_stamp)):
t_total += t_stamp[i]
if t_flow >= t_total:
t_position -= t_stamp[i]
t_index = i + 1
#t_process is the fraction of time between each transition.
t_process = t_position / t_stamp[t_index]
# Get the current value from the time stamp.
v_floor = value_list[t_index % len(value_list)]
# Get the next value from the time stamp.
v_ceil = value_list[(t_index + 1) % len(value_list)]
# Determine the 'power' between each transition
transform_power = transition_list[int(t_flow) % len(value_list)]
return transition(v_floor, v_ceil, math.pow(t_process % 1, transform_power))
def transition (down, up, mid):
# Another function for finding in between values.
return (down * (1 - mid)) + (up * mid)
def get_delta_time():
# Store the delta time into a delta variable.
global delta
global oldTime
delta = time.time()-oldTime
oldTime = time.time()
def do_pitches():
global pitches
global position
global started
global lastVal
global lastVal2
global count
global delta
# Create an interface to PortAudio
p = pyaudio.PyAudio()
wf = wave.open("sounds\\hello.wav", 'rb')
# Open a .Stream object to write the WAV file to
# 'output = True' indicates that the sound will be played rather than recorded
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), # 8bit
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
try:
while True:
# Make a variable called 'n', and set it to 'silent' (0).
pitches = 0
# Store pitches in n.
n: int = 0
if started:
position = []
lastVal = []
lastVal2 = []
#n = get_pitches()
for i in range(0, pitches):
position.append(0)
lastVal.append(0)
lastVal2.append(0)
started = False
# Read the voice data 1 frame at a time.
data2 = wf.readframes(1)
# Convert the data from byte format, into an integer value ranging from -32768 to 32768.
v = int.from_bytes(data2, 'big')
# NOTE:
#
# If I use this line only, without dividing the value of n by 2,
# it works fine.
#
# This line takes the values of all the pitches (averaged) placed
# in the get_pitches() function before later converting 'n' to a
# byte value (called 'data') and then writing 'data' to the stream.
#
n = (transition(n, get_pitches(), 1))
# NOTE:
#
# If I use this line only, without dividing the value of n by 2,
# it works fine.
#
# This line will play a .wav file called 'sound\hello.wav' before
# later converting n to a byte value (called data) and writing
# data to the stream.
#
n = v
# NOTE:
#
# If I use this line only, dividing the value of n by 2, it
# works fine.
#
# This line takes the values of all the pitches (averaged) in
# the get_pitches() function ... and will 'halve' the volume
# (as it is supposed to do since i 'half-ed' the value).
#
# The value of n later gets converted to a byte value (called
# 'data') and gets written to the stream.
#
n = (transition(n, get_pitches(), 1)) / 2
# NOTE:
#
# ***problem***: if I use this line only, and dividing the value
# of n by 2, this produces unwanted white noise instead of
# 'halving' the volume, even though i divided the value
# of n by 2.
#
# This line should play a .wav file called 'sound\hello.wav'
# before later converting n to a byte value (called data)
# and writing data to the stream.
#
n = int(v / 2)
# Convert the value of 'n' into bytes.
data = int(n).to_bytes(2, 'big')
#wf.setpos(int((time.time() - start) % wf.getsampwidth()))
#print (int(time.time() % wf.getsampwidth()))
# Writing data to stream makes the sound.
stream.write(data)
# Write voice to voice stream.
#stream2.write(data2)
# Increment position so that the 'n' result (from getPitches)
# produces a sine-wave.
for i in range (0, len(position)):
position[i] += 1
# Limit each position to 1000 chunks to prevent popping.
if count % 1000 == 0:
position[i] = 0
get_delta_time()
count += 1
except KeyboardInterrupt:
pass
# In the case the while loop breaks.
stream.close()
p.terminate()
do_pitches()
I found the problem... I took a .wav file called 'top.wav', which had 1 second of the maximum possible positive value that a wav can contain, and another .wav file called 'bottom.wav', which had 1 second of the maximum negative possible value (to see what values those 2 .wav files generate, so I could fully understand how the 'byte system' works).
Instead of converting the byte value of 'data' into an integer (using int.from_bytes()), I discovered a function called struct.unpack(), that takes the byte data, and converts it the RIGHT way, into a tuple with the value (<integer data value>, 0)
I got the real value from using...
decoded[0]
when using the code...
...
fmt = "<" + "h"
if data != b'' and data != b'\x00\x00\x00\x00':
decoded = struct.unpack(fmt, data)
if data == b'\x00\x00\x00\x00':
decoded = (0, )
...
Then, I noticed that the value are 'scrambled' to where anything that 'ranges' from 0 to 128, needs to be converted to 128 - (value - 1), and anything that ranges from 129 to 256 needs to be converted to (256 - (value - 128)) - 1... so I had to write a function called 'invert values'...
...
#This function makes values 0 to 128, 128 to 0 and values 129 to 256, 256 to 129.
def invert_values(n):
if n < 128:
n = 128 - (n - 1)
if 128 <= n < 256:
n = (256 - (n - 128)) - 1
return n
...
do my arithmetic afterwards,
use...
n = invert_values(n)
before converting n back to a byte value, and my wavs play fine. When I divide by 2, my volume 'halves'.

Get seperate two values and add together in every hour when the code is running using python

Here I have two values 40 and 50 in the csv file. Then I want to decrement the value in every hour separately and this will continuously running the code up to 24 hours.
So what I need to do is , I want to read that two changing values in every hour and do summation and read it as one output. I need this happened in every hour up to 24 hours.
So here I wrote the code for to read that two values and decrement in every one hour upto 24 hours.
50 will decrement in every hour 2.567
40 will decrement in every hour 1.234
Here is the code for the decrement process of two values. But unfortunately I have no idea how I can add that two values from taking that running code and read it as one input .
Can anyone help me to solve this process?
x = data[data['a'] == 50]
x now = x.iloc[0].loc['a']
last_x_value = 0
current_time = x.iloc[0].loc['date']
x_decrement_constant = math.exp((-2.567 * 1))
required_hours_of_generated_data = 24 # Generate data for this many hours.
X' = [{'date':current_time, 'a':x now }]
while True:
next_record_time = current_time + timedelta(0,3600)
if(last_x_value < len(x)-1):
if(next_record_time < x.iloc[last_x_value + 1].loc['date']):
new_x = (x_now* x_decrement_constant)
else:
new_x = (x_now* x_decrement_constant) + x.iloc[last_x_value + 1].loc['a']
last_x_value = last_x_value + 1
else:
break
y = data[data['b'] == 40]
y now = x.iloc[0].loc['b']
last_y_value = 0
current_time = x.iloc[0].loc['date']
x_decrement_constant = math.exp((-1.234* 1))
required_hours_of_generated_data = 24 # Generate data for this many hours.
Y' = [{'date':current_time, 'b':y now }]
while True:
next_record_time = current_time + timedelta(0,3600)
if(last_y_value < len(y)-1):
if(next_record_time < y.iloc[last_y_value + 1].loc['date']):
new_y = (y_now* y_decrement_constant)
else:
new_y = (y_now* y_decrement_constant) + y.iloc[last_y_value + 1].loc['b']
last_y_value = last_y_value + 1
else:
break

How to optimize an O(N*M) to be O(n**2)?

I am trying to solve USACO's Milking Cows problem. The problem statement is here: https://train.usaco.org/usacoprob2?S=milk2&a=n3lMlotUxJ1
Given a series of intervals in the form of a 2d array, I have to find the longest interval and the longest interval in which no milking was occurring.
Ex. Given the array [[500,1200],[200,900],[100,1200]], the longest interval would be 1100 as there is continuous milking and the longest interval without milking would be 0 as there are no rest periods.
I have tried looking at whether utilizing a dictionary would decrease run times but I haven't had much success.
f = open('milk2.in', 'r')
w = open('milk2.out', 'w')
#getting the input
farmers = int(f.readline().strip())
schedule = []
for i in range(farmers):
schedule.append(f.readline().strip().split())
#schedule = data
minvalue = 0
maxvalue = 0
#getting the minimums and maximums of the data
for time in range(farmers):
schedule[time][0] = int(schedule[time][0])
schedule[time][1] = int(schedule[time][1])
if (minvalue == 0):
minvalue = schedule[time][0]
if (maxvalue == 0):
maxvalue = schedule[time][1]
minvalue = min(schedule[time][0], minvalue)
maxvalue = max(schedule[time][1], maxvalue)
filled_thistime = 0
filled_max = 0
empty_max = 0
empty_thistime = 0
#goes through all the possible items in between the minimum and the maximum
for point in range(minvalue, maxvalue):
isfilled = False
#goes through all the data for each point value in order to find the best values
for check in range(farmers):
if point >= schedule[check][0] and point < schedule[check][1]:
filled_thistime += 1
empty_thistime = 0
isfilled = True
break
if isfilled == False:
filled_thistime = 0
empty_thistime += 1
if (filled_max < filled_thistime) :
filled_max = filled_thistime
if (empty_max < empty_thistime) :
empty_max = empty_thistime
print(filled_max)
print(empty_max)
if (filled_max < filled_thistime):
filled_max = filled_thistime
w.write(str(filled_max) + " " + str(empty_max) + "\n")
f.close()
w.close()
The program works fine, but I need to decrease the time it takes to run.
A less pretty but more efficient approach would be to solve this like a free list, though it is a bit more tricky since the ranges can overlap. This method only requires looping through the input list a single time.
def insert(start, end):
for existing in times:
existing_start, existing_end = existing
# New time is a subset of existing time
if start >= existing_start and end <= existing_end:
return
# New time ends during existing time
elif end >= existing_start and end <= existing_end:
times.remove(existing)
return insert(start, existing_end)
# New time starts during existing time
elif start >= existing_start and start <= existing_end:
# existing[1] = max(existing_end, end)
times.remove(existing)
return insert(existing_start, end)
# New time is superset of existing time
elif start <= existing_start and end >= existing_end:
times.remove(existing)
return insert(start, end)
times.append([start, end])
data = [
[500,1200],
[200,900],
[100,1200]
]
times = [data[0]]
for start, end in data[1:]:
insert(start, end)
longest_milk = 0
longest_gap = 0
for i, time in enumerate(times):
duration = time[1] - time[0]
if duration > longest_milk:
longest_milk = duration
if i != len(times) - 1 and times[i+1][0] - times[i][1] > longest_gap:
longes_gap = times[i+1][0] - times[i][1]
print(longest_milk, longest_gap)
As stated in the comments, if the input is sorted, the complexity could be O(n), if that's not the case we need to sort it first and the complexity is O(nlog n):
lst = [ [300,1000],
[700,1200],
[1500,2100] ]
from itertools import groupby
longest_milking = 0
longest_idle = 0
l = sorted(lst, key=lambda k: k[0])
for v, g in groupby(zip(l[::1], l[1::1]), lambda k: k[1][0] <= k[0][1]):
l = [*g][0]
if v:
mn, mx = min(i[0] for i in l), max(i[1] for i in l)
if mx-mn > longest_milking:
longest_milking = mx-mn
else:
mx = max((i2[0] - i1[1] for i1, i2 in zip(l[::1], l[1::1])))
if mx > longest_idle:
longest_idle = mx
# corner case, N=1 (only one interval)
if len(lst) == 1:
longest_milking = lst[0][1] - lst[0][0]
print(longest_milking)
print(longest_idle)
Prints:
900
300
For input:
lst = [ [500,1200],
[200,900],
[100,1200] ]
Prints:
1100
0

How python [internally] retrieves elements from array and finds minimum

For this question http://www.spoj.com/problems/ACPC10D/ on SPOJ, I wrote a python solution as below:
count = 1
while True:
no_rows = int(raw_input())
if no_rows == 0:
break
grid = [[None for x in range(3)] for y in range(2)]
input_arr = map(int, raw_input().split())
grid[0][0] = 10000000
grid[0][1] = input_arr[1]
grid[0][2] = input_arr[1] + input_arr[2]
r = 1
for i in range(0, no_rows-1):
input_arr = map(int, raw_input().split())
_r = r ^ 1
grid[r][0] = input_arr[0] + min(grid[_r][0], grid[_r][1])
grid[r][1] = input_arr[1] + min(min(grid[_r][0], grid[r][0]), min(grid[_r][1], grid[_r][2]))
grid[r][2] = input_arr[2] + min(min(grid[_r][1], grid[r][1]), grid[_r][2])
r = _r
print str(count) + ". " + str(grid[(no_rows -1) & 1][1])
count += 1
The above code exceeds time limit. However, when I change the line
grid[r][2] = input_arr[2] + min(min(grid[_r][1], grid[r][1]), grid[_r][2])
to
grid[r][2] = input_arr[2] + min(min(grid[_r][1], grid[_r][2]), grid[r][1])
the solution is accepted. If you notice the difference, the first line compares, grid[_r][1], grid[r][1] for minimum (i.e. the row number are different) and second line compares grid[_r][1], grid[_r][2] for minimum(i.e. the row number are same)
This is a consistent behaviour. I want to understand, how python is processing those two lines - so that one results in exceeding time limit, while other is fine.

Time measurement - function with an input inside

My task is to measure time of a function which contains an input inside (the user is to input a list).
There is the code:
import numpy
import itertools
def amount(C):
N = numpy.array(input().strip().split(" "),int)
N = list(N)
N = sorted(N)
while C < max(N):
N.remove(max(N))
res = []
for i in range(1, C):
for j in list(itertools.combinations_with_replacement(N, i)):
res.append(sum(list(j)))
m = 0
for z in range (0, len(res)):
if res[z] == C:
m += 1
if N[0] == 1:
return m + 1
else:
return m
Of course it is not optimized (but it's not the case now).
Because of the "list" standard way by which I mean:
import time
start = time.time()
amount(10)
end = time.time()
print(end - start)
does not work.
How can I measure the time? For example for:
C in range [0, 11]
N = [1, 2 , 5]
I would be grateful for any help! :)
You want somethig like this?
import time
# measure process time
t0 = time.clock()
amount(10)
print time.clock() - t0, "seconds process time"
# measure wall time
t0 = time.time()
amount(10)
print time.time() - t0, "seconds wall time"
UPDATE : The soulution maybe could be this :
times=[]
for x in range(12):
t0 = time.time()
amount(x)
times.append( time.time() - t0);
or better if you use timeit : here
What do you think about this:
import time
def time_counter(amount, n=100, M=100):
res = list(range(n))
def count_once():
start = time.perf_counter()
amount(res)
return time.perf_counter() - start
return [count_once() for m in range(M)]
It is to make M = 1000 measurements and for C in range(0, n). Is it alright?

Categories

Resources