Vary bleed amount based on population density

There are basically two kinds of 4G masts:

Frequency | Range       | Bandwidth
----------|-------------|----------------------------------
800MHz    | Long (500m) | Low (can handle a bit of traffic)
1800Mhz   | Short (5km) | High (can handle lots of traffic)

The 1800Mhz masts are better in terms of how much traffic they can
handle and how fast a connection they provide. But because they have
quite short range, it’s only economical to install them in very built up
areas†.

In more rural areas the 800MHz masts are better because they cover a
wider area, and have enough bandwidth for the lower population density.

The net effect of this is that cell broadcasts in rural areas are likely
to bleed further, because the masts they are being broadcast from are
less precise.

We can use population density as a proxy for how likely it is to be
covered by 1800Mhz masts, and therefore how much bleed we should expect.
So this commit varies the amount of bleed shown based on the population
density.

I came up with the formula based on 3 fixed points:
- The most remote areas (for example the Scottish Highlands) should have
  the highest average bleed, estimated at 5km
- An town, like Crewe, should have about the same bleed as we were
  estimating before (1.5km) – Pete D thinks this is about right based on
  his knowledge of the area around his office in Crewe
- The most built up areas, like London boroughs, could have as little as
  500m of bleed

Based on these three figures I came up with the following formula, which
roughly gives the right bleed distance (`b`) for each of their population
densities (`d`):
```
b = 5900 - (log10(d) × 1_250)
```

Plotted on a curve it looks like this:

This is based on averages – remember that the UI shows where is _likely_
to receive the alert, based on bleed, not where it’s _possible_ to
receive the alert.

Here’s what it looks like on the map:

---

†There are some additional subtleties which make this not strictly true:
- The 800Mhz masts are also used in built up areas to fill in the gaps
  between the areas covered by the 1800Mhz masts
- Switching between masts is inefficient, so if you’re moving fast
  through a built up area (for example on a train) your phone will only
  use the 800MHz masts so that you have to handoff from one mast to
  another less often
This commit is contained in:
Chris Hill-Scott
2021-03-12 09:17:42 +00:00
parent fb1345494c
commit 738ac1d818
8 changed files with 130 additions and 9 deletions

View File

@@ -1,3 +1,5 @@
from math import isclose
import pytest
from app.broadcast_areas import (
@@ -10,6 +12,10 @@ from app.broadcast_areas.populations import (
)
def close_enough(a, b):
return isclose(a, b, rel_tol=0.001) # Within 0.1% difference
def test_loads_libraries():
assert [
(library.id, library.name, library.is_group) for library in sorted(broadcast_area_libraries)
@@ -272,3 +278,71 @@ def test_estimate_number_of_smartphones_for_population(
assert estimate_number_of_smartphones_for_population(
population
) == expected_estimate
@pytest.mark.parametrize('area, expected_phones_per_square_mile', (
(
# Islington (most dense in UK)
'lad20-E09000019', 21_348
),
(
# Cordwainer Ward (City of London)
# This is higher than Islington because we inflate the
# popualtion to account for daytime workers
'wd20-E05009300', 310_674
),
(
# Crewe East
'wd20-E05008621', 2_078),
(
# Eden (Cumbria, least dense in England)
'lad20-E07000030', 25.57
),
(
# Highland (least dense in UK)
'lad20-S12000017', 4.40
),
))
def test_phone_density(
area, expected_phones_per_square_mile,
):
assert close_enough(
broadcast_area_libraries.get_areas(area)[0].phone_density,
expected_phones_per_square_mile,
)
@pytest.mark.parametrize('area, expected_bleed_in_m, expected_bleed_in_degrees', (
(
# Islington (most dense in UK)
'lad20-E09000019', 488, 0.00439
),
(
# Cordwainer Ward (City of London)
# Special case because of inflated daytime population
'wd20-E05009300', 500, 0.00449
),
(
# Crewe East
'wd20-E05008621', 1_752, 0.01574
),
(
# Eden (Cumbria, least dense in England)
'lad20-E07000030', 4_140, 0.0372
),
(
# Highland (least dense in UK)
'lad20-S12000017', 5_095, 0.0458
),
))
def test_estimated_bleed(
area, expected_bleed_in_m, expected_bleed_in_degrees,
):
assert close_enough(
broadcast_area_libraries.get_areas(area)[0].estimated_bleed_in_m,
expected_bleed_in_m,
)
assert close_enough(
broadcast_area_libraries.get_areas(area)[0].estimated_bleed_in_degrees,
expected_bleed_in_degrees,
)

View File

@@ -623,7 +623,7 @@ def test_broadcast_page(
'Scotland remove',
], [
'An area of 177,439.8 square miles Will get the alert',
'An extra area of 3,058.9 square miles is Likely to get the alert',
'An extra area of 6,392.3 square miles is Likely to get the alert',
'40,000,000 phones estimated',
]),
([
@@ -640,8 +640,17 @@ def test_broadcast_page(
'Penrith West remove',
], [
'An area of 6.3 square miles Will get the alert',
'An extra area of 14.4 square miles is Likely to get the alert',
'9,000 to 30,000 phones',
'An extra area of 22.6 square miles is Likely to get the alert',
'9,000 to 40,000 phones',
]),
([
'lad20-E09000019',
], [
'Islington remove',
], [
'An area of 9.7 square miles Will get the alert',
'An extra area of 4.6 square miles is Likely to get the alert',
'200,000 to 300,000 phones',
]),
))
def test_preview_broadcast_areas_page(
@@ -726,7 +735,7 @@ def test_preview_broadcast_areas_page_with_custom_polygons(
for item in page.select('ul li.area-list-key')
] == [
'An area of 722.3 square miles Will get the alert',
'An extra area of 1,402.5 square miles is Likely to get the alert',
'An extra area of 1,498.5 square miles is Likely to get the alert',
'Unknown number of phones',
]