As a shoal of fish moves it can seem to respond to its environment as a single entity, particularly when a predator approaches. This behaviour puzzled biologists for some time, but behavioural biologist Iain Couzin among others recently began to unlock some of the mechanics behind their movement. A model of it can be made by setting out the movement of individual members – no overarching mechanisms across the shoal are needed. Members of the shoal will roughly move as follows:
1) Each member tends to keep a set distance from their neighbours.
2) Each member keeps a similar orientation to that of their neighbours.
3) Each member is only aware of their closest neighbours.
Of course there are other ways of moving depending on what is in their environment, for example if a predator approaches they’ll scram! The shoal’s basic movement can be described with the three principles above though, and a model following it will have movement similar to that of a shoal. So what do members need to do to stay part of the shoal? If they’re to keep a set distance from their neighbours then moving in a similar direction to them will help. They can look at how their neighbours are moving on average and adjust their own movement accordingly.
If a neighbour is too close they can also change their movement away from that neighbour.
And if a neighbour is too far away they can move closer to them.
An algorithm describing the movement of a shoal member might look something like the following.
neighbour_movement_vector = 0 for each close neighbour: add that neighbour's movement vector to neighbour_movement_vector closest_neighbour = 0 closest_distance = -1 for each close neighbour: neighbour_distance = distance to neighbour if neighbour_distance < ideal neighbour distance: if neighbour_distance < closest_distance or closest_distance is -1: closest_neighbour = neighbour closest_distance = neighbour_distance if closest_neighbour is not 0: collision_correction_vector = member's position - neighbour's position else: collision_correction_vector = 0 furthest_neighbour = 0 furthest_distance = -1 for each close neighbour: neighbour_distance = distance to neighbour if neighbour_distance > ideal neighbour distance: if neighbour_distance > furthest_distance or furthest_distance is -1: furthest_neighbour = neighbour furthest_distance = neighbour_distance if furthest_neighbour is not 0: cohesion_correction_vector = neighbour's position - member's position else: cohesion_correction_vector = 0 normalise and scale neighbour_movement_vector normalise and scale collision_correction_vector normalise and scale cohesion_correction_vector add neighbour_movement_vector to the member's movement vector add collision_correction_vector to the member's movement vector add cohesion_correction_vector to the member's movement vector
This algorithm was used to generate the movement in the video below.
Adding in predators and food and doing some general tinkering around, it’s possible to get more complex movement, as can be seen in the video below.
In the video below the shoal’s movement is reflected with sound. Each member makes a sound at a tone dependant on the closeness of their neighbours. The combination of all members doing this at once gives the sound depth.
The fact that shoal movement can be modelled using the actions of individual members in relation to a few close neighbours raises interesting questions about how we see the shoal. From the perspective of a shoal member it’s a fairly simple thing – all they have to do is keep track of how their immediate neighbours are moving and adjust their own movement accordingly. Yet we tend to see it as something broader and at times it can seem to react as a single entity. This disparity between the perspectives of an outside observer of the shoal and that of a member of it leads into an interesting area known as ’emergence’ which spans across several branches of science and philosophy.
Leave a comment
Comments feed for this article