Reputation: 29
I am currently taking my first Python coding course and I am very stuck on this assignment. The goal is to define a function 'F(t)' using a piecewise function that would make a graph of a triangle wave that looks identical to:
This is what I have tried:
def F(t):
if (t >= 0) & (t <= 1/2):
return 4*t
elif (t >= 1/2) & (t < 1):
return -4*t
else:
return 0
f = np.vectorize(F)
t = np.linspace(0,4,num=8)
plt.plot(t,f(t))
Obviously, to no luck. The above code matches the ideal graph from 0 to 1 so I'm really just struggling with how to make the graph a continuous triangle wave for all t > 0.
Any tips or suggestions are much appreciated
Upvotes: 1
Views: 881
Reputation: 25489
Your function is wrong. If you want the troughs to be at odd multiples of 0.5
and the peaks to be at even multiples of 0.5
, and you want the value to be 1
and -1
, your function needs to be -4 * t + 1
between 0
and 0.5
, and 4 * t - 3
between 0.5
and 1
.
Also, your function returns 0
for t < 0
and for t > 1
, so your output doesn't match the expected output outside those bounds.
Since your if
conditions describe the correct behavior when you have only the part of the input after the decimal point, you can extract that part and use it instead of t
:
def F(t):
decimal_part = t % 1
if 0 <= decimal_part <= 0.5:
return -4*decimal_part + 1
else:
return 4*decimal_part - 3
Which gives this:
Remember to discretize the x-axis so it has enough points. I plotted the blue line with t = np.linspace(0, 4, 1000)
, and the red line with t = np.linspace(0, 4, 10)
and everything else remained the same.
The np.vectorize()
function doesn't really vectorize a function though. If you want to actually see speed improvements, you're going to have to vectorize the function yourself by expressing its logic as a vector operation.
def g(t):
dec = (t % 1) - 0.5
return (np.abs(dec) - 0.25) * 4
Both give the same plots, but timing the execution shows the difference:
import timeit
t1 = timeit.timeit('f(t)', setup='from __main__ import np, f, t', number=10000)
t2 = timeit.timeit('g(t)', setup='from __main__ import np, g, t', number=10000)
# t1 = 3.322270042001037
# t2 = 0.17450489799375646
print(t1 / t2)
# 19.038262422410074
The actually vectorized function is ~19x faster on my computer (Intel Python 3.7 with numpy+MKL on Macbook Air)
Upvotes: 2
Reputation: 142651
First you could use print()
to see what you have in variables.
In F()
you get t
like 0.5714285714285714
, 1.1428571428571428
but if you would use num=9
instead of num=8
then you would get exactly 0.5
, 1.0
and it would be much easier to draw it.
And using print()
to display results for different combinations I created
def F(t):
return 1 - ((t*2) % 2)
Which can be reduced to
def F(t):
return 1 - (t % 1)
How I get it:
You have y
in range (-1, 1) which gives length 2
so I started with y = t % 2
to get values in range (0, 2) which also gives length 2
. Because for 0
I got 0
and I needed 1
so next I used 1 - ...
to get a "mirror image". So I get y=1 for x=0 but next top was for y=2 but I needed for y=1 so I had to use *2
to get it. And finally I released that (t*2) % 2
can be (t % 2) * (2 % 2)
so it gives (t % 2) * 1
and this gives (t % 2)
Minimal working code
import numpy as np
import matplotlib.pyplot as plt
def F(t):
#y = t % 2
#y = 1 - (t % 2)
#y = 1 - ((t*2) % 2)
y = 1 - (t % 1)
print(t, y)
return y
f = np.vectorize(F)
t = np.linspace(0, 4, num=9)
plt.plot(t, f(t))
plt.show()
Upvotes: 0