Here is my code:
import random
import numpy as np
import matplotlib.pyplot as plt
import agent
deer = agent.Agent()
print(deer.x,deer.y)
deer.step()
print(deer.x,deer.y)
def walk(length):
for i in range(length):
#while deer.x <= i:
deer.step()
countx= deer.x + 1
county=deer.y +1
#print(countx,county)
x= countx
y= county
return deer.step()
walk(100)
walker = walk(100)
plt.plot(walk[0],walk[1],label= 'Random walk')
plt.scatter(walk[0],walk[1],s=50,c=range(101))
plt.show()
I'm trying to get the count step of x and y to be graphed.But I don't understand why it wont recognize the x and y values within the function. The goal is to plot the 100 random steps taken.
After there is a plot from the 100 steps taken, I'm trying to create a second Method for taking a step. Instead of choosing a random new angle and moving, the current orientation of the agent should change by a random amount chosen from a normal distribution with mean 0 and standard deviation Sigma=1 (self.orientation = self.orientation + np.random.normal(0,Sigma)).
It's also suppose to walk 100 steps, and show the trajectory using matplolib, and show the distance between the agent and it's starting point.
I used the class Agent:
class Agent:
# initializer with default argument value
def __init__(self,sigma=0.5):
self.x = 0.0 # agent's x position
self.y = 0.0 # agent's y position
self.o = 0.0 # agent's orientation
self.v = 1.0 # agent's velocity
self.sigma = sigma
def step(self):
self.o = random.random()*2*np.pi
self.x +=self.v*np.cos(self.o)
self.y += self.v*np.sin(self.o)
def turn(self):
self.o += np.random.normal(0,self.sigma)
self.x += self.v*np.cos(self.o)
self.y += self.v*np.sin(self.o)
def distance(self):
return np.sqrt(self.x**2 + self.y**2)
Related
I am writing a code to update a position of a ball after it being kicked at a given angle and velocity after a certain time passed. Does the results indicate that the list(position) is not updated or there is something wrong with the equation?
import numpy as np
class Ball():
def __init__(self, theta, v):
self.position = [0, 0] # Position at ground is (0,0)
self.theta = 0
self.v = 0
def step(self, delta_t = .1):
ball.position[0] = ball.v*np.cos(ball.theta)*t
ball.position[1] = (ball.v**2*np.sin(ball.theta))/9.81
return ball.position
ball = Ball(theta = 30, v = 100)
for t in range(200):
ball.step(delta_t = 0.05)
print(f'Ball is at x={ball.position[0]:.2f}m, y={ball.position[1]:.2f}m') # Check position
Output =
Ball is at x=0.00m, y=0.00m
There were a few bugs in your code, I've altered it to do what I believe you intend it to do below:
import numpy as np
class Ball():
def __init__(self, theta, v):
self.position = [0, 0] # Position at ground is (0,0)
self.theta = theta
self.v = v
def step(self, delta_t = .1):
self.position[0] = self.v*np.cos(self.theta)*delta_t
self.position[1] = (self.v**2*np.sin(self.theta))/9.81
return self.position
ball = Ball(theta = 30, v = 100)
for t in range(200):
ball.step(delta_t = 0.05)
print(f'Ball is at x={ball.position[0]:.2f}m, y={ball.position[1]:.2f}m') # Check position
With the result:
Ball is at x=0.77m, y=-1007.17m
Explanation
First, your __init__ method simply set self.theta and self.v to 0, instead of setting them equal to the values provided when initialising the ball object.
Second, your step method relied upon something called t, instead of delta_t which is what you actually rely upon in your defintion of step.
Finally, in your step method, you seem to be relying on ball.XYZ instead of self.XYZ.
Correcting all of these, I believe, makes the class function as you wish it to - whether the calculation is correct, I'll leave to you to determine.
Note
If what you're trying to do is plot the trajectory of a ball in free fall, you should probably update self.v and self.theta with every call of self.step(). Currently, self.step() returns where the ball will be after a given interval of time from its initial condition. If you're trying to step incrementally - with every call of self.step(), the current self.v and current self.theta of the ball will be different after every call of self.step() - but your self.step() definition currently takes no account of this.
I am in the middle of making a program that simulates chemical equilibrium. In theory, it is simple, it takes in initial concentrations of A (B is size of grid-A) and a probability of having A (B's probability is 1-A). Then it sets up an n by n grid with the initial conditions; randomly distributing each A. It then simulates what would occur to the concentration over time, but it disregards the initial conditions and calculates from a 1:0 ratio of A:B. I know why it does that, but I do not know how to make my program consider the initial conditions. My code is the following:
n = 100
A=3000
B=(n*n)-A
time = 25
probA = 70 #where probability of getting A is probA/prob
prob = 100
#Specifications
width = 5
height = width
x_position = width
y_position = height
#Functions
concA = []
concB = []
time1 = []
color1=[170,10,0]
color2=[0,170,170]
So far these are just empty lists and constants I need to run the program and display the data I want at the end.
def draw_initial(n):
countA_int=0
countB_int=0
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,int(A+B))
if r<A:
clr=color1
countA_int +=1
else:
clr=color2
countB_int +=1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_int/(n*n))
concB.append(100*countB_int/(n*n))
time1.append(0)
print('Initial concentrations:')
print('A = {} and B = {}'.format(concA[-1],concB[-1]))
wait_mouse_press()
clear()
So far I have made the initial grid. However, I know how to randomly distribute n amount of A in the grid. I just know how to make it so that roughly n percentage of the grid is A. Please instruct me here.
def start_reaction(n):
t = 1
while True:
countA_final = 0
countB_final = 0
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,prob)
v=(-math.e**(-(1/math.e)*t))+1
if r <= v*probA:
clr = color1
countA_final += 1
else:
clr = color2
countB_final += 1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_final/(n*n))
concB.append(100*countB_final/(n*n))
t += 1
time1.append(t-1)
print ('New round, time ={}'.format(t-1))
print('A = {}'.format(concA[-1]))
print('B = {}'.format(concB[-1]))
wait_mouse_press()
if t > time:
break
print(concA)
print(concB)
print(time1)
This next bit calculates how the grid looks for each iteration. It uses an odd formula to model the probability accurately. By the end it shows you this graph:
Clearly, there is an issue. At the very beginning, the data points jump instantly and then are modeled as they should be. The jump occurs because the second function doesn't know how the grid started and instead calculates a grid with only A at first and then does the iterations. I want my program to reach equilibrium from any given concentration, not only from 100% A. Can someone please help me?
Well, maybe it isn't of much interest for people, but I've managed to fix the issue. I won't bother explaining in detail but the issue had to do with the formula I used that modeled the increase or decrease in probability. I created another equation that would yield a variable that would shift the curve to the left in order to match the current concentration. If anyone wants the medialib file in order to run the code yourself, please write it in the comments. The code is the following:
from medialib import *
from random import randint # import randint() function
import matplotlib.pyplot as plt
import math
#Input variables
n = 100
A=1000 #must be between 0 and n*n
B=(n*n)-A
time = 25
probA = 50 #where probability of getting A is probA/prob
prob = 100
#Specifications
width = 5
height = width
x_position = width
y_position = height
#Functions
concA = []
concB = []
time1 = []
color2=[170,10,0]
color1=[0,170,170]
def draw_initial(n):
countA_int=0
countB_int=0
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,int(A+B))
if r<A:
clr=color1
countA_int +=1
else:
clr=color2
countB_int +=1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_int/(n*n))
concB.append(100*countB_int/(n*n))
time1.append(0)
print('Initial concentrations:')
print('A = {} and B = {}'.format(concA[-1],concB[-1]))
wait_mouse_press()
clear()
def start_reaction(n):
t = 1
while True:
countA_final = 0
countB_final = 0
if concA[-1]<probA:
l=math.e*math.log(1/(abs(1-(concA[-1]/probA))))
v=(-math.e**((-1/math.e)*(t+l)))+1
elif concA[-1]==probA:
l=math.e*math.log(1/(abs(1-((concA[-1]+0.1)/probA))))
v=(-math.e**((-1/math.e)*(t+l)))+1
elif concA[-1]>probA:
l=math.e*math.log(1/(abs(1-(concA[-1]/probA))))
v=(math.e**((-1/math.e)*(t+l)))+1
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,prob)
if r < v*probA:
clr = color1
countA_final += 1
else:
clr = color2
countB_final += 1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_final/(n*n))
concB.append(100*countB_final/(n*n))
t += 1
time1.append(t-1)
print ('New round, time ={}'.format(t-1))
print('A = {}'.format(concA[-1]))
print('B = {}'.format(concB[-1]))
wait_mouse_press()
if t > time:
break
print(concA)
print(concB)
print(time1)
draw_initial(n)
start_reaction(n)
wait_mouse_press()
import matplotlib.pyplot as plt
axes = plt.axes()
axes.set_ylim([0, 100])
plt.plot(time1,concA, label="Conc.A")
plt.plot(time1,concB, label="Conc.B")
plt.ylabel('% concentration')
plt.xlabel('time')
plt.show()
wait_mouse_press()
all_done() # always the last instruction of the program
That's the graph, see how the concentrations do not have to begin at 100:0 anymore.
Then with this velocity and acceleration and initial position find the next position(2D). The only tricky part is the creation of the vector!
Just use standard vector math. Distance is the Pythagorean theorem and magnitude is trigonometry:
from math import *
class Vector2D:
def __init__(self, x, y):
self.x = float(x)
self.y = float(y)
def direction(self):
return degrees(atan(self.y / self.x))
def magnitude(self):
return sqrt(self.x ** 2 + self.y ** 2)
You can create a class , then each instance (object) of that class would be a velocity object (vector) . A very simple example is -
class Velocity:
def __init__(self, mag, direction):
self.mag = mag
self.direction = direction
Then you can create velocity objects like -
v1 = Velocity(5,5)
v2 = Velocity(10,15)
You can access the magnitude and direction of each velocity as -
print(v1.mag)
>> 5
print(v1.direction)
>> 5
The above is a minimalistic example , you will need to add whatever operations (read functions) you want our velocity object to support.
You could create a velocity tuple, where magnitude is at index 0 and direction is at index 1. Then define acceleration as a float and a startingPos where x is at index 0 and y is at index 1.
#0: magnitude 1: direction (degrees above x axis)
velocity = (2.3, 55)
acceleration = 3.2
#0: x 1: y
startingPos = (-10, 0)
I have some code and I think it mostly works. I am supposed to be modelling the way two particles interact under gravity in 2D. It works until the second loop over the update function, so I think there is something wrong with the update function but I can't see it.
from __future__ import print_function, division
import numpy as np # imports the scientific computing package
G = 10 # of course G is not really 10 but this make it easier to track the accuracy of calculations.
t=5 # defines the timestep
class Particle:
def __init__(self,mass):
self.mass = mass # gives the particle mass
self.position = np.array([0,0],int) # gives the particle a position defined by a vector. Therefore all answers will now be given as vectors.
def calculateForce(self,other):
'''
this function calculates the force acting on the particles
'''
force = (G*self.mass*other.mass)/(other.position - self.position)**2
print('The force acting on the particles is', force)
return(force)
def calculateAcceleration(self,force):
'''
calculates the acceleration of the first particle
'''
acceleration = (force/self.mass)
print('Acceleration of particle is', acceleration)
return acceleration
def calculateAcceleration1(other, force):
'''
calculates the acceleration of the second particle
'''
acceleration1 = (force/other.mass)
print('Acceleration of particle1 is', acceleration1)
return acceleration1
def calculateVelocity(self, acceleration):
'''
calculates the velocity of the first particle
'''
velocity = (acceleration*t)
print('Velocity of particle is', velocity)
return velocity
def calculateVelocity1(self, acceleration1):
'''
calculates the velocity of the second particle
'''
velocity1 = (acceleration1*t)
print('Velocity of particle1 is', velocity1)
return velocity1
def calculatePosition(self, velocity):
'''
calculates the position of the first particle
'''
position = (velocity*t)
print('Position of particle is', position)
return position
def calculatePosition1(self,velocity1):
'''
calculates the position of the second particle
'''
position1 = (velocity1*t)
print('Position of particle1 is', position1)
return position1
def update(self,other):
# for x in range(0,1):
self.position = position
other.position = position1
print(self.position)
print(other.position)
return self.position
return other.position
def repeat(self,other):
for x in range(0,5):
force = p.calculateForce(p1)
acceleration = p.calculateAcceleration(force)
acceleration1 = p1.calculateAcceleration1(force)
velocity = p.calculateVelocity(acceleration)
velocity1 = p1.calculateVelocity1(acceleration1)
position = p.calculatePosition(velocity)
position1 = p1.calculatePosition1(velocity1)
p.update(p1)
p = Particle(10) # gives first particle a mass of 10
p1 = Particle(20) # gives second particle a mass of 20
p1.position[0] = 5 # x coordinate of second particle is 5
p1.position[1] = 5 # y coordinate of second particle is 5
print(p1.position)
force = p.calculateForce(p1)
acceleration = p.calculateAcceleration(force)
acceleration1 = p1.calculateAcceleration1(force)
velocity = p.calculateVelocity(acceleration)
velocity1 = p1.calculateVelocity1(acceleration1)
position = p.calculatePosition(velocity)
position1 = p1.calculatePosition1(velocity1)
p.update(p1)
p.repeat(p1)
Your second return is unreachable in update:
def update(self,other):
# for x in range(0,1):
self.position = position
other.position = position1
print(self.position)
print(other.position)
return self.position
return other.position <- unreachable
If you wanted to return two values you could return a tuple of both and change your code appropriately to use the values:
return self.position, other.position
If either one or the other should be returned then you need to add some logic.
What the problem is
I have to simulate balls in a box of 1 by 1.
i have to give the ball a random speed and a random angle it takes off in.
however when i plot the balls they go straight and have an asymptote at 0.25.
i double cheked my math but i cant find the problem?
My code
import numpy
import matplotlib.pyplot as plt
import math
import random
def rand_tuples(aantalballen): # here i make a function that randomly makes a list with lists in #
list_balls = [] # the list, every index is a ball with x_pos , y_pos , speed , rotation #
for i in range(aantalballen):
list_balls.append([0.25, 0.75,0.1* random.random(), 2* math.pi*random.random()])
return list_balls
def ball_step(list_balls, dt): # this function calculates the steps the balls takes #
x = list_balls[0]
y = list_balls[1]
vx = math.cos(list_balls[3]) * list_balls[2] # speed in the x direction #
vy = math.sin(list_balls[3]) * list_balls[2] # speed in the y direction #
dt = dt
x_pos = x + (vx * dt) # calculates the actual positions #
y_pos = y + (vy * dt)
if x_pos <= 0 or x_pos >= 1: # collision detection #
vx = -vx
if y_pos <= 0 or y_pos >= 1:
vy = -vy
return x_pos, y_pos, vx , vy # returns the new positions but the same speed so that they can be used again#
def move_ball(ballen, tijd, dt): # takes a list of balls, time they move and the time steps they take#
positions_balls = { } # hold my position in {0:{'x':[positions}, 'y':{...}}}
time_1 = 0
for i in range(len(ballen)) :
positions_balls[i] = None # make a key with empty value #
time_1 = 0
cordinates = {'x':[], 'y':[]} # make the dictionary where my values go into #
while time_1 < tijd:
bal = ball_step(ballen[i] , dt) # call bal step to calculate my x and y position #
ballen[i] = bal
cordinates['x'].append(bal[0])
cordinates['y'].append(bal[1])
time_1 += dt
if int(time_1) == tijd:
positions_balls[i] = cordinates # finally add the dictionary to my main dictionary #
print positions_balls
return positions_balls
dic = move_ball(rand_tuples(30), 3, 0.01)
plt.plot(dic[0]['x'], dic[0]['y'])
plt.show()
i do not have enough reputation to post a picture of the plot :(
ball_step() takes in (I think; comments are your friend) x, y, speed, rotation. It outputs x, y, speed x, speed y. That's assigned back to the original list.