math.sin() not returning proper value - python

Hello I have an equation I am trying to calculate using python. Where
The desired output I am looking for is 1.71528
Below I have my current code with all of the current values d should equal 100 and theta should equal 60.
import math
m = 0.065
g = 9.8
print("Input the distance to professor")
d = 100 # float(input())
k = 25
print("Now input the value for theta")
theta = 60 # float(input())
x = math.sqrt(m*g*d/k*math.sin(2 * theta))
print(x, 'meters')
The output I get when I run this code is 1.2163047715819324 meters
I think my issue is something with math.sin any help would be appreciated thanks.

Convert to theta to radians and put brackets around the denominator.
x = math.sqrt(m*g*d/(k*math.sin(2 * math.radians(theta))))
print(f"{x:.5f} meters")
Will result in
Input the distance to professor
100
Now input the value for theta
60
1.71528 meters

Related

"TypeError: 'float' object is not callable" for artillery script

I decided to try and code ballistic computer. Below is the code i've put together that takes the muzzle velocity, the distance and the elevation bearing of a target and outputs the required angle to shoot so that a shell fired will collide at the desired location. Currently i'm suffering with an error in the second last line and i have no clue how to ammend this error. Any help at all would be appreciated.
import math
print("Note that the platform you are firing off must be perfectly flat to ensure optimal accuracy")
print("---------------------------------------------------------------")
g = (-9.81) **#g is negative in this case**
degrees = float(input("What is the angle from horizon of the spotter? [0-90] "))
radians = math.radians(degrees) **#Sin only works with radians**
U = float(input("What is the muzzle velocity of the gun? "))
Target_distance = float(input("What is the distance to the target in Meters? ")) #direct distance to target
y = float(math.sin(radians))**Target_distance #horizontal distance to target**
x = float(math.cos(radians))**Target_distance #elevation to target from you**
print("the elevation of the target is",y)
print("the distance to the targetenter code here is",x)
print("true distance to target is",Target_distance)
max_angle = math.radians(45)
max_dist = ((U**2)/(2*g))*(1+(math.sqrt(1+((2*g*y)/(U**2)*((math.sin(max_angle)*
(math.sin(max_angle)))))))*math.sin(max_angle))#shows the maximum distance of the shell being fired
print (("max gun range is"),-1*max_dist)
print("---------------------------------------------------------------")
theta = math.degrees((math.asin((g*x)/(U**2)))*-1) #equation needs to be halved to get correct solution
solution1 = (theta *0.5)
solution2 = (90 - solution1)
print(solution1)
print(solution2)
print("---------------------------------------------------------------")
#issue here (TypeError 'float' object is not callable) - variables passed in are U,g,x,y
"TypeError: 'float' object is not callable" for artillery script
solution_3 = math.degrees(math.atan((U*U) + (math.sqrt(U*U*U*U - g ( g * (x * x) + ( 2 * y * (U**2)))))) / ( g * x))
print (solution_3)
Use this instead:
solution_3 = math.degrees(math.atan((U**2) + (math.sqrt(U**4 - g * ( g * (x * x) + ( 2 * y * (U**2)))))) / ( g * x))
A * was missing after "g"
import math
g = -9.81
degrees = float(input("What is the angle from horizon of the spotter? [0-90] "))
radians = math.radians(degrees) #Sin only works with radians
U = int(input("What is the muzzle velocity of the gun? "))
Target_distance = float(input("What is the distance to the target in Meters? ")) #direct distance to target
y = float(math.sin(radians)) #Target_distance #horizontal distance to target
x = float(math.cos(radians)) #Target_distance #elevation to target from you
print("the elevation of the target is",y)
print("the distance to the targetenter code here is",x)
print("true distance to target is",Target_distance)
max_angle = math.radians(45)
max_dist = ((U*2)/(2*g))*(1+(math.sqrt(1+((2*g*y)/(U*2)*((math.sin(max_angle) * (math.sin(max_angle)))))))*math.sin(max_angle)) #shows the maximum distance of the shell being fired
print (("max gun range is"),-1*max_dist)
print("---------------------------------------------------------------")
theta = math.degrees((math.asin((g*x)/(U**2)))-1) #equation needs to be halved to get correct
# solution = ???
solution1 = (theta *0.5)
solution2 = (90 - solution1)
print(solution1)
print(solution2)
print("---------------------------------------------------------------")
The problem is that you forgot about sign between brackets * and varibles *
In python gU not working like g*U, you should specify what you want
I think I've found a common issue here:
...
max_dist = ((U2)/(2g))(1+(math.sqrt(1+((2gy)/(U2)((math.sin(max_angle)
... ^ ^ ^ ^ ^
| | | | |
You're getting a call error simply because you are not using the appropriate multiplication operator * for the variables I've pointed out above. This seems to be a common theme in your Python script as well.
It's great to see you implementing equations into code, and while you continue improving your programming skills you must look into organizing and structuring your code for legibility. That way you, the programming errors will be more apparent.

Determining final velocity at a target distance

In this program I've been working on with Python the goal is to take user inputs on a given initial velocity, angle, and how far away a structure is/how tall it is we're aiming for. I have been able to calculate how long it takes for something to reach a target, but I'm not sure why the final velocity (how fast it is going when it reaches the target) is coming up wrong.
# User inputs
velocity = float(input('Give me a velocity to fire at (in m/s): '))
angle = float(input('Give me an angle to fire at: '))
distance = float(input('Give me how far away you are from the
structure: '))
height = float(input('Give me the height of the structure (in meters):
'))
slingshot = 5 #Height of slingshot in meters
gravity = 9.8 #Earth gravity
# Converting angles to radians
angleRad = math.radians(angle)
# Computing our x and y coordinate
x = math.cos(angleRad)
y = math.sin(angleRad)
# Calculations
time = distance/(velocity * x)
vx = x
vy = y + (-9.8 * time)
finalVelocity = math.sqrt((vx ** 2) + (vy ** 2))
# Output of program
print('It takes your bird' , time , 'seconds to reach the structure')
print('Your velocity at the target distance is' , finalVelocity ,
'meters per second.')
Here is a sample input and what the expected output should be:
Input Velocity: 20
Input Angle: 40
Input Distance: 25
Input Height of Structure: 15
Expected Output:
Time to reach structure: 1.63176 s
Final velocity: 15.6384 s
My Program's Output:
Time to reach structure: 1.63176
Final velocity: 15.36755
At first glance it would appear my program is very close, so I suspected a rounding error, but it is mere coincidence with the chosen numbers that they're close.
You miscalculated the horizontal and vertical components of the final velocity. You only used the cosine and sine of the angle, rather than the (magnitude of the) initial velocity times the cosine and sine, respectively. If you modify the following two lines of code, you will obtain the result you were looking for given the sample input you provided:
vx = velocity * x
vy = velocity * y - 9.8 * time
I rewrote your original code a bit and also computed the final height to check whether the structure was hit or not, so feel free to use it if needed:
import math
# User inputs
# v0 = float(input('Give me a velocity to fire at (in m/s): '))
# angle = float(input('Give me an angle to fire at: '))
# distance = float(input('Give me how far away you are from the structure: '))
# height_structure = float(input('Give me the height of the structure (in meters):'))
# Test inputs
v0 = 20
angle = 40
distance = 25
height_structure = 15
# Constants
height_slingshot = 5 # Height of slingshot in meters
g = 9.8 # Earth gravity
# Converting angle to radians
angleRad = math.radians(angle)
# Computing initial velocity components
vx0 = v0 * math.cos(angleRad)
vy0 = v0 * math.sin(angleRad)
# Computing time to travel horizontal distance
t_x = distance / vx0
# Computing final vertical velocity component
vy_final = vy0 - g * t_x
# Computing magnitude of final velocity
v_final = math.sqrt((vx0 ** 2) + (vy_final ** 2))
# Note: Horizontal component is constant
# Computing final height
y_final = height_slingshot + vy0 * t_x - g / 2 * t_x ** 2
# Verify if t_x was computed correctly
# t_y1 = (vy0 + math.sqrt(vy0 ** 2 - 2 * g * y_final)) / g
# t_y2 = (vy0 - math.sqrt(vy0 ** 2 - 2 * g * y_final)) / g
# Output of program
print('It takes your bird', t_x, 'seconds to reach the structure.')
print('Your velocity at the target distance is', v_final,
'meters per second.')
print('\nFinal height: ', y_final)
print('Structure height:', height_structure)
if 0. <= y_final <= height_structure:
print('\nYou hit the structure!')
elif y_final < 0:
print('\nYou missed. Not far enough!')
else:
print('\nYou missed. Too far!')

Converting latitude & longitude to x & y Mollweide map coordinates using a Newton-Raphson iteration in Python

I'm trying to write a program that will take a set of longitude & latitude coordinates from the user, convert them to x & y coordinates for a Mollweide projection map, and then report the value of the pixel at those coordinates (in this case, a noise temperature).
The map/data I'm using is the Haslam 408 MHz All Sky Survey which is provided as a Mollweide projection map. This data is in .fits format and is a large all-sky survey of noise in the 408 MHz band.
According to the Mollweide projection Wikipedia page, it is possible to use a Newton-Raphson iteration to convert from longitude/latitude to x/y map coordinates. I based the iteration scheme in my program largely on the methods from the Wikipedia page and in this GitHub post.
However, my program does not appear to be reporting the correct values for the longitude and latitude that I'm inputting. I largely suspect that one of two (or both) factors are contributing to this error:
The way that I'm implementing the iteration scheme is incorrect, and thus resulting in incorrect values being reported.
I don't properly understand what the radius value, R, represents in the iteration scheme. I can't find any literature on how to determine the proper R value beyond that "R is the radius of the globe to be projected." I assumed that this would be based upon the size of the map in pixels; in this case, the map image is 4096x2048 pixels, so I've tried using 2048, 1024, and simply 1 as the R values, to no avail.
Below I have provided my code for review:
from math import sin, cos, pi, sqrt, asin
from astropy.io import fits
hdulist = fits.open('data.fits')
hdulist.info()
data = hdulist[1].data
sqrt2 = sqrt(2)
def solveNR(lat, epsilon=1e-6): #this solves the Newton Raphson iteration
if abs(lat) == pi / 2:
return lat # avoid division by zero
theta = lat
while True:
nexttheta = theta - (
(2 * theta + sin(2 * theta) - pi * sin(lat)) /
(2 + 2 * cos(2 * theta))
)
if abs(theta - nexttheta) < epsilon:
break
theta = nexttheta
return nexttheta
def checktheta(theta, lat): #this function is also currently unused while debugging
return (2 * theta + sin(2 * theta), pi * sin(lat))
def mollweide(lat, lon, lon_0=0, R=1024):
lat = lat * pi / 180
lon = lon * pi / 180
lon_0 = lon_0 * pi / 180 # convert to radians
theta = solveNR(lat)
return (R * 2 * sqrt2 * (lon - lon_0) * cos(theta) / pi,
R * sqrt2 * sin(theta))
def inv_mollweide(x, y, lon_0=0, R=1024, degrees=True): # inverse procedure (x, y to lat, long). Currently unused
theta = asin(y / (R * sqrt2))
if degrees:
factor = 180 / pi
else:
factor = 1
return (
asin((2 * theta + sin(2 * theta)) / pi) * factor,
(lon_0 + pi * x / (2 * R * sqrt(2) * cos(theta))) * factor
)
def retrieve_temp(lat, long): #retrieves the noise temp from the data file after calling the mollweide function
lat = int(round(lat))
long = int(round(long))
coords = mollweide(lat, long)
x, y= coords
x = int(round(x))
y= int(round(y))
x = x-1
y = y-1
if x < 0:
x = x*(-1)
if y < 0:
y = y*(-1)
print("The noise temperature is: ",data[y, x],"K")
def prompt(): #this is the terminal UI
cont = 1
while cont == 1:
lat_cont = 1
while lat_cont == 1:
lat = float(input('Please enter the latitude: '))
lat_val = 1
while lat_val == 1:
if lat > 180 or lat < -180:
lat = float(input('Invalid input. Make sure your latitude value is in range -180 to 180 degrees \n'
'Please enter the latitude: '))
else:
lat_val = 0
lat_cont = 0
long_cont = 1
while long_cont == 1:
long = float(input('Please enter the longitude: '))
long_val = 1
while long_val == 1:
if long > 90 or long < -90:
long = float(input('Invalid input. Make sure your latitude value is in range -90 to 90 degrees \n'
'Please enter the latitude: '))
else:
long_val = 0
long_cont = 0
retrieve_temp(lat, long)
valid = 1
while valid == 1:
ans = input('Would you like to continue? Y or N: ').lower()
ans_val = 1
while ans_val ==1:
if not (ans == 'y' or ans == 'n'):
ans = input('Invalid input. Please answer Y or N to continue or exit: ')
elif ans == 'y':
ans_val = 0
cont = 1
valid = 0
elif ans == 'n':
ans_val = 0
cont = 0
valid = 0
prompt()
hdulist.close()
Apologies if I failed to follow typical Python conventions in the above code; I'm new to Python.
Your code looks reasonable. My advice about figuring out what's wrong:
(1) Try evaluating your mollweide and inv_mollweide functions at points for which you know what the results are supposed to be. E.g. points on the equator or prime meridian or something easy like that.
(2) Are your mollweide and inv_mollweide actually inverses? i.e. if you take your output from the one and put it into the other, you should get the original input back again.
(3) How do results change as you move around on the map? Do you get correct results in some areas (e.g. near middle of map) and not others? What happens as you get nearer to the edges? Does it gradually become more inaccurate or is there some threshold, beyond which you get grossly incorrect answers?
I think a feature of Newton's method is that it converges only if you're close enough to a solution to begin with, otherwise you can get anything. I don't know how close you have to be, for this problem.
This seems like a great problem. Good luck and have fun.
so this is going to sound really strange, but as far as I know there aren't actually any good Python libraries for Mollweide conversions, at least for Mollweide maps that span the entire earth. The EPSG system is bizarrely incomplete, which makes Pyproj more or less unusable for this purpose. I plan on using your code as part of a project of my own, but if you'd like to setup a github library and maybe even some kind of pip functionality (I'm fairly new to Python myself, so I'm really not who to ask on how to do that), I'm happy to give you credit.

Trying to generate random x,y coordinates within a ring in python

I am trying to generate random x and y coordinates within a ring, which has an outer radius of 3.5 and an inner radius of 2. Therefor the following must be true for x and y:
x**2 + y**2 < 12.25 and x**2 + y**2 > 4
I wrote the following function:
def meteorites():
circle = False
while circle == False:
r = np.array([uniform(-6., 6.), uniform(-6., 6.)])
# we will regenerate random numbers untill the coordinates
# are within the ring x^2+y^2 < 3,5^2 and x^2+y^2 > 2^2
if (r[0]**2+r[1]**2 < 12.25) and (r[0]**2+r[1]**2 > 4.):
circle = True
else :
circle = False
return r[0], r[1]
x = np.zeros(1000)
y = np.zeros(1000)
for i in range(1000):
x[i] = meteorites()[0]
y[i] = meteorites()[1]
plt.scatter(x,y)
plt.show()
When I plot the resulting coordinates I get a square from -3.5 to 3.5. I can't seem to find the problem. I'm also not sure if it's a coding error, or some dum math problem. Since you guys are usually good at both, can you see what I'm doing wrong here?
To get uniform distribution of random point in the ring, one should take relative areas of thin circular regions into account. How it works for the circle
For your case generate uniform distribution of SquaredR in range of squared inner and outer radii. Pseudocode:
Fi = RandomUniform(0, 2 * Pi)
SquaredR = RandomUniform(inner*inner, outer*outer)
R = Sqrt(SquaredR)
x,y = R * Cos(Fi), R * Sin(Fi)
Take a random angle and a random distance between the two constraints; you'll need to produce a uniform distribution in a circle:
from math import sin, cos, radians, pi, sqrt
def meteorites():
angle = uniform(0, 2 * pi) # in radians
distance = sqrt(uniform(4, 12.25))
return distance * cos(angle), distance * sin(angle)
You're getting random points that don't fall on your ring because these two lines don't do what you want:
x[i] = meteorites()[0]
y[i] = meteorites()[1]
These assign an x value from one point on the ring to x[i], and the y value from a different point on the ring to y[i]. You get coordinates from different points because you're calling meteorites() twice.
Instead, you probably want to call the function once, and then assign to each coordinate, or do an assignment with iterable-unpacking where both targets are on the left side of the equals sign:
x[i], y[i] = meteorites()
Your implementation will also work if you correct one line: insstead of calling meteorites() twice, call just once.
x = np.zeros(1000)
y = np.zeros(1000)
for i in range(1000):
x[i], y[i] = meteorites()
plt.scatter(x,y)
plt.show()
I would also rather run through a loop that picks a random angle and a random distance within your ring range. Then calculate the coords from that.
But in your code the first problem is see is that should write:
x[i],y[i] = meteorites()
instead of
x[i] = meteorites()[0]
y[i] = meteorites()[1]
In your example, you're called meteorites() twice resulting in the x and y two different meteorites.
as #Martijn Pieters suggested, simply draw the polar coordinates uniformly in the range you require.
theta = uniform(0,2*np.pi)
r = uniform(2.,3.5)
x = r*np.cos(theta)
y = r*np.sin(theta)
EDIT: There will be equal probability for every point in the ring to occur.
But practically there will be less pixels for a given theta the closer r is to the lower limit. So "meteorites" with smaller r will occur with larger probability.
I believe this effect is negligeble.
EDIT 2: MBo's answer is better. Code:
theta = uniform(0, 2 * np.pi)
r = np.sqrt(uniform(2.0 ** 2, 3.5 ** 2)) # draw from sqrt distribution
x = r * np.cos(theta)
y = r * np.sin(theta)
You could try the following to generate 1000 samples using numpy:
import numpy
n = 1000
phi = numpy.random.uniform(0, 2*numpy.pi, n)
r = numpy.random.uniform(2, 3.5, n)
Then x, y coordinates can be constructed as follows using the transformation from radial to cartesian coordinates:
x = r * numpy.cos(phi)
y = r * numpy.sin(phi)
This shows the power of numpy, as x and y are now arrays without needing to iterate over n.

Numpy linspace unexpected output

I am running the code below to build a one-dimensional array for each z and t. At the present moment, I am trying to make their sizes equivalent so that they each have a length of 501.
import numpy as np
#constants & parameters
omega = 1.
eps = 1.
c = 3.*(10.**8.)
hbar = 1.
eta = 0.01
nn = 10.**7.
n = eta*nn
lambdaOH = c/(1612.*10.**(6.))
gamma = 1.282*(10.**(-11.))
Tsp = 1./gamma
TR = 604800.
L = (Tsp/TR)*(np.pi)/((3.*(lambdaOH**2.))*n)
#time
Ngridt = 500.
tmax = 1.
dt = tmax/Ngridt
intervalt = tmax/dt + 1
t = np.linspace(0.01,tmax,intervalt)
#z space
Ngridz = 500.
zmax = L
dz = zmax/Ngridz
intervalz = zmax/dz + 1
z = np.linspace(0.01,zmax,intervalz)
When running the code, both intervalt and intervalz equal 501.0, but when checking the length of both z and t, len(z) = 500 while len(t) = 501. I have played around with the code above to yield len(z) = 501 by modifying certain parts. For example, if I insert the code
zmax = int(zmax)
then len(z) = 501. But I am wondering why the initial code, exactly as written, does not yield an array z with length 501?
(I am using Python 2.7.)
It is a problem of rounding. If you try to subtract 501 from intervalz you will find a very small negative number, -5.68e-14; linspace just takes the integer part of it, that is 500, and provides a 500-long list.
Notice two other problems with your code:
dt does not provide the correct spacing because you don't remove the initial t (same for dz)
Ngridt and Ngridz are conceptually integers, while you initialize them as floats. Just remove the dot at the end.
I think that your code could be simplified by writing (notice that Ngridt and Ngridz are initialized to 501)
#time
Ngridt = 501
tmax = 1.
t, dt = np.linspace(0.01,tmax,Ngridt,retstep=True)
#z space
Ngridz = 501
zmax = L
z, dz = np.linspace(0.01,zmax,Ngridz,retstep=True)
This is related to float arithmetic inaccuracy. It so happens that the formula for intervalz yields 500.99999999999994. This is just floating accuracy issue you can find all over SO. The np.linspace command then takes this number as 500 and not as 501.
Since linspace expects an int it is better to make sure you give it one.
BTW: mathematically speaking I don't see why you don't set
intervalz = Ngridz + 1
since intervalz = zmax/dz + 1 = zmax/(zmax/Ngridz) + 1 = Ngridz + 1

Categories

Resources