ObjectNat 1.2.2__py3-none-any.whl → 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ObjectNat might be problematic. Click here for more details.
- objectnat/_api.py +14 -14
- objectnat/_config.py +43 -47
- objectnat/_version.py +1 -1
- objectnat/methods/coverage_zones/__init__.py +3 -3
- objectnat/methods/coverage_zones/graph_coverage.py +11 -4
- objectnat/methods/coverage_zones/radius_voronoi_coverage.py +4 -2
- objectnat/methods/coverage_zones/stepped_coverage.py +20 -10
- objectnat/methods/isochrones/__init__.py +1 -1
- objectnat/methods/isochrones/isochrone_utils.py +167 -167
- objectnat/methods/isochrones/isochrones.py +31 -11
- objectnat/methods/noise/__init__.py +3 -3
- objectnat/methods/noise/noise_init_data.py +10 -10
- objectnat/methods/noise/noise_reduce.py +155 -155
- objectnat/methods/noise/noise_simulation.py +14 -13
- objectnat/methods/noise/noise_simulation_simplified.py +10 -9
- objectnat/methods/point_clustering/__init__.py +1 -1
- objectnat/methods/point_clustering/cluster_points_in_polygons.py +3 -3
- objectnat/methods/provision/__init__.py +1 -1
- objectnat/methods/provision/provision.py +112 -20
- objectnat/methods/provision/provision_exceptions.py +59 -59
- objectnat/methods/provision/provision_model.py +323 -348
- objectnat/methods/utils/__init__.py +1 -1
- objectnat/methods/utils/geom_utils.py +173 -173
- objectnat/methods/utils/graph_utils.py +5 -5
- objectnat/methods/utils/math_utils.py +32 -32
- objectnat/methods/visibility/__init__.py +6 -6
- objectnat/methods/visibility/visibility_analysis.py +9 -17
- objectnat-1.3.0.dist-info/METADATA +201 -0
- objectnat-1.3.0.dist-info/RECORD +33 -0
- {objectnat-1.2.2.dist-info → objectnat-1.3.0.dist-info}/WHEEL +1 -1
- objectnat-1.2.2.dist-info/METADATA +0 -116
- objectnat-1.2.2.dist-info/RECORD +0 -33
- {objectnat-1.2.2.dist-info/licenses → objectnat-1.3.0.dist-info}/LICENSE.txt +0 -0
|
@@ -31,33 +31,44 @@ def get_accessibility_isochrone_stepped(
|
|
|
31
31
|
"""
|
|
32
32
|
Calculate stepped accessibility isochrones for a single point with specified intervals.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
isochrone_type
|
|
34
|
+
Args:
|
|
35
|
+
isochrone_type:
|
|
36
36
|
Visualization method for stepped isochrones:
|
|
37
|
-
|
|
38
|
-
- "
|
|
39
|
-
- "
|
|
37
|
+
|
|
38
|
+
- ``"radius"``: Voronoi-based in circular buffers
|
|
39
|
+
- ``"ways"``: Voronoi-based in road network polygons
|
|
40
|
+
- ``"separate"``: Circular buffers for each step
|
|
41
|
+
|
|
40
42
|
point (gpd.GeoDataFrame):
|
|
41
43
|
Single source point for isochrone calculation (uses first geometry if multiple provided).
|
|
44
|
+
|
|
42
45
|
weight_value (float):
|
|
43
46
|
Maximum travel time (minutes) or distance (meters) threshold.
|
|
44
|
-
|
|
47
|
+
|
|
48
|
+
weight_type:
|
|
45
49
|
Type of weight calculation:
|
|
50
|
+
|
|
46
51
|
- "time_min": Time-based in minutes
|
|
47
52
|
- "length_meter": Distance-based in meters
|
|
53
|
+
|
|
48
54
|
nx_graph (nx.Graph):
|
|
49
55
|
NetworkX graph representing the transportation network.
|
|
56
|
+
|
|
50
57
|
step (float, optional):
|
|
51
58
|
Interval between isochrone steps. Defaults to:
|
|
59
|
+
|
|
52
60
|
- 100 meters for distance-based
|
|
53
61
|
- 1 minute for time-based
|
|
62
|
+
|
|
54
63
|
**kwargs: Additional parameters:
|
|
64
|
+
|
|
55
65
|
- buffer_factor: Size multiplier for buffers (default: 0.7)
|
|
56
66
|
- road_buffer_size: Buffer size for road edges in meters (default: 5)
|
|
57
67
|
|
|
58
68
|
Returns:
|
|
59
|
-
|
|
69
|
+
tuple[gpd.GeoDataFrame, gpd.GeoDataFrame | None, gpd.GeoDataFrame | None]:
|
|
60
70
|
Tuple containing:
|
|
71
|
+
|
|
61
72
|
- stepped_isochrones: GeoDataFrame with stepped polygons and distance/time attributes
|
|
62
73
|
- pt_stops: Public transport stops within isochrones (if available)
|
|
63
74
|
- pt_routes: Public transport routes within isochrones (if available)
|
|
@@ -150,29 +161,38 @@ def get_accessibility_isochrones(
|
|
|
150
161
|
- 'radius': Circular buffer-based isochrones
|
|
151
162
|
- 'ways': Road network-based isochrones
|
|
152
163
|
|
|
153
|
-
|
|
154
|
-
isochrone_type
|
|
164
|
+
Args:
|
|
165
|
+
isochrone_type:
|
|
155
166
|
Type of isochrone to calculate:
|
|
167
|
+
|
|
156
168
|
- "radius": Creates circular buffers around reachable nodes
|
|
157
169
|
- "ways": Creates polygons based on reachable road network
|
|
170
|
+
|
|
158
171
|
points (gpd.GeoDataFrame):
|
|
159
172
|
GeoDataFrame containing source points for isochrone calculation.
|
|
173
|
+
|
|
160
174
|
weight_value (float):
|
|
161
175
|
Maximum travel time (minutes) or distance (meters) threshold.
|
|
162
|
-
|
|
176
|
+
|
|
177
|
+
weight_type:
|
|
163
178
|
Type of weight calculation:
|
|
179
|
+
|
|
164
180
|
- "time_min": Time-based accessibility in minutes
|
|
165
181
|
- "length_meter": Distance-based accessibility in meters
|
|
182
|
+
|
|
166
183
|
nx_graph (nx.Graph):
|
|
167
184
|
NetworkX graph representing the transportation network.
|
|
168
185
|
Must contain CRS and speed attributes for time calculations.
|
|
186
|
+
|
|
169
187
|
**kwargs: Additional parameters:
|
|
188
|
+
|
|
170
189
|
- buffer_factor: Size multiplier for buffers (default: 0.7)
|
|
171
190
|
- road_buffer_size: Buffer size for road edges in meters (default: 5)
|
|
172
191
|
|
|
173
192
|
Returns:
|
|
174
|
-
|
|
193
|
+
tuple[gpd.GeoDataFrame, gpd.GeoDataFrame | None, gpd.GeoDataFrame | None]:
|
|
175
194
|
Tuple containing:
|
|
195
|
+
|
|
176
196
|
- isochrones: GeoDataFrame with calculated isochrone polygons
|
|
177
197
|
- pt_stops: Public transport stops within isochrones (if available)
|
|
178
198
|
- pt_routes: Public transport routes within isochrones (if available)
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .noise_simulation import simulate_noise
|
|
2
|
-
from .noise_reduce import dist_to_target_db, green_noise_reduce_db
|
|
3
|
-
from .noise_simulation_simplified import calculate_simplified_noise_frame
|
|
1
|
+
from .noise_simulation import simulate_noise
|
|
2
|
+
from .noise_reduce import dist_to_target_db, green_noise_reduce_db
|
|
3
|
+
from .noise_simulation_simplified import calculate_simplified_noise_frame
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
|
|
3
|
-
data = {
|
|
4
|
-
30: {63: 0, 125: 0.0002, 250: 0.0009, 500: 0.003, 1000: 0.0075, 2000: 0.014, 4000: 0.025, 8000: 0.064},
|
|
5
|
-
20: {63: 0, 125: 0.0003, 250: 0.0011, 500: 0.0028, 1000: 0.0052, 2000: 0.0096, 4000: 0.025, 8000: 0.083},
|
|
6
|
-
10: {63: 0, 125: 0.0004, 250: 0.001, 500: 0.002, 1000: 0.0039, 2000: 0.01, 4000: 0.035, 8000: 0.125},
|
|
7
|
-
0: {63: 0, 125: 0.0004, 250: 0.0008, 500: 0.0017, 1000: 0.0049, 2000: 0.017, 4000: 0.058, 8000: 0.156},
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
air_resist_ratio = pd.DataFrame(data)
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
data = {
|
|
4
|
+
30: {63: 0, 125: 0.0002, 250: 0.0009, 500: 0.003, 1000: 0.0075, 2000: 0.014, 4000: 0.025, 8000: 0.064},
|
|
5
|
+
20: {63: 0, 125: 0.0003, 250: 0.0011, 500: 0.0028, 1000: 0.0052, 2000: 0.0096, 4000: 0.025, 8000: 0.083},
|
|
6
|
+
10: {63: 0, 125: 0.0004, 250: 0.001, 500: 0.002, 1000: 0.0039, 2000: 0.01, 4000: 0.035, 8000: 0.125},
|
|
7
|
+
0: {63: 0, 125: 0.0004, 250: 0.0008, 500: 0.0017, 1000: 0.0049, 2000: 0.017, 4000: 0.058, 8000: 0.156},
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
air_resist_ratio = pd.DataFrame(data)
|
|
@@ -1,155 +1,155 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from scipy.optimize import fsolve
|
|
3
|
-
|
|
4
|
-
from objectnat import config
|
|
5
|
-
|
|
6
|
-
from .noise_init_data import air_resist_ratio
|
|
7
|
-
|
|
8
|
-
logger = config.logger
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def get_air_resist_ratio(temp, freq, check_temp_freq=False):
|
|
12
|
-
if check_temp_freq:
|
|
13
|
-
if temp > max(air_resist_ratio.columns) or temp < min(air_resist_ratio.columns):
|
|
14
|
-
logger.warning(
|
|
15
|
-
f"The specified temperature of {temp}°C is outside the tabulated data range. "
|
|
16
|
-
f"The air resistance coefficient for these values may be inaccurate. "
|
|
17
|
-
f"Recommended temperature range: {min(air_resist_ratio.columns)}°C "
|
|
18
|
-
f"to {max(air_resist_ratio.columns)}°C."
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
if freq > max(air_resist_ratio.index) or freq < min(air_resist_ratio.index):
|
|
22
|
-
logger.warning(
|
|
23
|
-
f"The specified geometric mean frequency of {freq} Hz is outside the tabulated data range."
|
|
24
|
-
f" The air resistance coefficient for these values may be inaccurate."
|
|
25
|
-
f" Recommended frequency range: {min(air_resist_ratio.index)} Hz to {max(air_resist_ratio.index)} Hz."
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
def get_nearest_values(array, value):
|
|
29
|
-
sorted_array = sorted(array)
|
|
30
|
-
if value in sorted_array:
|
|
31
|
-
return [value]
|
|
32
|
-
if value > max(sorted_array):
|
|
33
|
-
return [sorted_array[-1]]
|
|
34
|
-
if value < min(sorted_array):
|
|
35
|
-
return [sorted_array[0]]
|
|
36
|
-
|
|
37
|
-
for i, val in enumerate(sorted_array):
|
|
38
|
-
if value < val:
|
|
39
|
-
return sorted_array[max(i - 1, 0)], sorted_array[i]
|
|
40
|
-
return sorted_array[-2], sorted_array[-1]
|
|
41
|
-
|
|
42
|
-
nearest_temp = get_nearest_values(air_resist_ratio.columns, temp)
|
|
43
|
-
nearest_freq = get_nearest_values(air_resist_ratio.index, freq)
|
|
44
|
-
|
|
45
|
-
if len(nearest_temp) == 1 and len(nearest_freq) == 1:
|
|
46
|
-
return air_resist_ratio.loc[nearest_freq[0], nearest_temp[0]]
|
|
47
|
-
|
|
48
|
-
if len(nearest_temp) == 2 and len(nearest_freq) == 2:
|
|
49
|
-
freq1, freq2 = nearest_freq
|
|
50
|
-
temp1, temp2 = nearest_temp
|
|
51
|
-
|
|
52
|
-
coef_temp1_freq1 = air_resist_ratio.loc[freq1, temp1]
|
|
53
|
-
coef_temp1_freq2 = air_resist_ratio.loc[freq2, temp1]
|
|
54
|
-
coef_temp2_freq1 = air_resist_ratio.loc[freq1, temp2]
|
|
55
|
-
coef_temp2_freq2 = air_resist_ratio.loc[freq2, temp2]
|
|
56
|
-
|
|
57
|
-
weight_temp1 = (temp2 - temp) / (temp2 - temp1)
|
|
58
|
-
weight_temp2 = (temp - temp1) / (temp2 - temp1)
|
|
59
|
-
weight_freq1 = (freq2 - freq) / (freq2 - freq1)
|
|
60
|
-
weight_freq2 = (freq - freq1) / (freq2 - freq1)
|
|
61
|
-
|
|
62
|
-
coef_freq1 = coef_temp1_freq1 * weight_temp1 + coef_temp2_freq1 * weight_temp2
|
|
63
|
-
coef_freq2 = coef_temp1_freq2 * weight_temp1 + coef_temp2_freq2 * weight_temp2
|
|
64
|
-
|
|
65
|
-
final_coef = coef_freq1 * weight_freq1 + coef_freq2 * weight_freq2
|
|
66
|
-
|
|
67
|
-
return final_coef
|
|
68
|
-
|
|
69
|
-
if len(nearest_temp) == 2 and len(nearest_freq) == 1:
|
|
70
|
-
temp1, temp2 = nearest_temp
|
|
71
|
-
freq1 = nearest_freq[0]
|
|
72
|
-
|
|
73
|
-
coef_temp1 = air_resist_ratio.loc[freq1, temp1]
|
|
74
|
-
coef_temp2 = air_resist_ratio.loc[freq1, temp2]
|
|
75
|
-
|
|
76
|
-
weight_temp1 = (temp2 - temp) / (temp2 - temp1)
|
|
77
|
-
weight_temp2 = (temp - temp1) / (temp2 - temp1)
|
|
78
|
-
|
|
79
|
-
return coef_temp1 * weight_temp1 + coef_temp2 * weight_temp2
|
|
80
|
-
|
|
81
|
-
if len(nearest_temp) == 1 and len(nearest_freq) == 2:
|
|
82
|
-
temp1 = nearest_temp[0]
|
|
83
|
-
freq1, freq2 = nearest_freq
|
|
84
|
-
|
|
85
|
-
coef_freq1 = air_resist_ratio.loc[freq1, temp1]
|
|
86
|
-
coef_freq2 = air_resist_ratio.loc[freq2, temp1]
|
|
87
|
-
|
|
88
|
-
weight_freq1 = (freq2 - freq) / (freq2 - freq1)
|
|
89
|
-
weight_freq2 = (freq - freq1) / (freq2 - freq1)
|
|
90
|
-
|
|
91
|
-
return coef_freq1 * weight_freq1 + coef_freq2 * weight_freq2
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def dist_to_target_db(
|
|
95
|
-
init_noise_db, target_noise_db, geometric_mean_freq_hz, air_temperature, return_desc=False, check_temp_freq=False
|
|
96
|
-
) -> float | str:
|
|
97
|
-
"""
|
|
98
|
-
Calculates the distance required for a sound wave to decay from an initial noise level to a target noise level,
|
|
99
|
-
based on the geometric mean frequency of the sound and the air temperature. Optionally, can return a description
|
|
100
|
-
of the sound propagation behavior.
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
init_noise_db (float): The initial noise level of the source in decibels (dB). This is the starting sound
|
|
104
|
-
intensity.
|
|
105
|
-
target_noise_db (float): The target noise level in decibels (dB), representing the level to which the sound
|
|
106
|
-
decays over distance.
|
|
107
|
-
geometric_mean_freq_hz (float): The geometric mean frequency of the sound (in Hz). This frequency influences
|
|
108
|
-
the attenuation of sound over distance. Higher frequencies decay faster than lower ones.
|
|
109
|
-
air_temperature (float): The temperature of the air in degrees Celsius. This influences the air's resistance
|
|
110
|
-
to sound propagation.
|
|
111
|
-
return_desc (bool, optional): If set to `True`, the function will return a description of the sound decay
|
|
112
|
-
process instead of the calculated distance.
|
|
113
|
-
check_temp_freq (bool, optional): If `True`, the function will check whether the temperature and frequency
|
|
114
|
-
are within valid ranges.
|
|
115
|
-
|
|
116
|
-
Returns:
|
|
117
|
-
float or str: If `return_desc` is `False`, the function returns the distance (in meters) over which the sound
|
|
118
|
-
decays from `init_noise_db` to `target_noise_db`. If `return_desc` is `True`, a descriptive string is returned
|
|
119
|
-
explaining the calculation and the conditions.
|
|
120
|
-
"""
|
|
121
|
-
|
|
122
|
-
def equation(r):
|
|
123
|
-
return l - l_ist + 20 * np.log10(r) + k * r
|
|
124
|
-
|
|
125
|
-
l_ist = init_noise_db
|
|
126
|
-
l = target_noise_db
|
|
127
|
-
k = get_air_resist_ratio(air_temperature, geometric_mean_freq_hz, check_temp_freq)
|
|
128
|
-
initial_guess = 1
|
|
129
|
-
r_solution = fsolve(equation, initial_guess)
|
|
130
|
-
if return_desc:
|
|
131
|
-
string = (
|
|
132
|
-
f"Noise level of {init_noise_db} dB "
|
|
133
|
-
f"with a geometric mean frequency of {geometric_mean_freq_hz} Hz "
|
|
134
|
-
f"at an air temperature of {air_temperature}°C decays to {target_noise_db} dB "
|
|
135
|
-
f"over a distance of {r_solution[0]} meters. Air resistance coefficient: {k}."
|
|
136
|
-
)
|
|
137
|
-
return string
|
|
138
|
-
return r_solution[0]
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def green_noise_reduce_db(geometric_mean_freq_hz, r_tree) -> float:
|
|
142
|
-
"""
|
|
143
|
-
Calculates the amount of noise reduction (in dB) provided by vegetation of a given thickness at a specified
|
|
144
|
-
geometric mean frequency. The function models the reduction based on the interaction of the sound with trees or
|
|
145
|
-
vegetation.
|
|
146
|
-
|
|
147
|
-
Args:
|
|
148
|
-
geometric_mean_freq_hz (float): The geometric mean frequency of the sound (in Hz).
|
|
149
|
-
r_tree (float): The thickness or density of the vegetation (in meters).
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
float: The noise reduction (in dB) achieved by the vegetation. This value indicates how much quieter the sound
|
|
153
|
-
will be after passing through or interacting with the vegetation of the specified thickness.
|
|
154
|
-
"""
|
|
155
|
-
return round(0.08 * r_tree * ((geometric_mean_freq_hz ** (1 / 3)) / 8), 1)
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy.optimize import fsolve
|
|
3
|
+
|
|
4
|
+
from objectnat import config
|
|
5
|
+
|
|
6
|
+
from .noise_init_data import air_resist_ratio
|
|
7
|
+
|
|
8
|
+
logger = config.logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_air_resist_ratio(temp, freq, check_temp_freq=False):
|
|
12
|
+
if check_temp_freq:
|
|
13
|
+
if temp > max(air_resist_ratio.columns) or temp < min(air_resist_ratio.columns):
|
|
14
|
+
logger.warning(
|
|
15
|
+
f"The specified temperature of {temp}°C is outside the tabulated data range. "
|
|
16
|
+
f"The air resistance coefficient for these values may be inaccurate. "
|
|
17
|
+
f"Recommended temperature range: {min(air_resist_ratio.columns)}°C "
|
|
18
|
+
f"to {max(air_resist_ratio.columns)}°C."
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if freq > max(air_resist_ratio.index) or freq < min(air_resist_ratio.index):
|
|
22
|
+
logger.warning(
|
|
23
|
+
f"The specified geometric mean frequency of {freq} Hz is outside the tabulated data range."
|
|
24
|
+
f" The air resistance coefficient for these values may be inaccurate."
|
|
25
|
+
f" Recommended frequency range: {min(air_resist_ratio.index)} Hz to {max(air_resist_ratio.index)} Hz."
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def get_nearest_values(array, value):
|
|
29
|
+
sorted_array = sorted(array)
|
|
30
|
+
if value in sorted_array:
|
|
31
|
+
return [value]
|
|
32
|
+
if value > max(sorted_array):
|
|
33
|
+
return [sorted_array[-1]]
|
|
34
|
+
if value < min(sorted_array):
|
|
35
|
+
return [sorted_array[0]]
|
|
36
|
+
|
|
37
|
+
for i, val in enumerate(sorted_array):
|
|
38
|
+
if value < val:
|
|
39
|
+
return sorted_array[max(i - 1, 0)], sorted_array[i]
|
|
40
|
+
return sorted_array[-2], sorted_array[-1]
|
|
41
|
+
|
|
42
|
+
nearest_temp = get_nearest_values(air_resist_ratio.columns, temp)
|
|
43
|
+
nearest_freq = get_nearest_values(air_resist_ratio.index, freq)
|
|
44
|
+
|
|
45
|
+
if len(nearest_temp) == 1 and len(nearest_freq) == 1:
|
|
46
|
+
return air_resist_ratio.loc[nearest_freq[0], nearest_temp[0]]
|
|
47
|
+
|
|
48
|
+
if len(nearest_temp) == 2 and len(nearest_freq) == 2:
|
|
49
|
+
freq1, freq2 = nearest_freq
|
|
50
|
+
temp1, temp2 = nearest_temp
|
|
51
|
+
|
|
52
|
+
coef_temp1_freq1 = air_resist_ratio.loc[freq1, temp1]
|
|
53
|
+
coef_temp1_freq2 = air_resist_ratio.loc[freq2, temp1]
|
|
54
|
+
coef_temp2_freq1 = air_resist_ratio.loc[freq1, temp2]
|
|
55
|
+
coef_temp2_freq2 = air_resist_ratio.loc[freq2, temp2]
|
|
56
|
+
|
|
57
|
+
weight_temp1 = (temp2 - temp) / (temp2 - temp1)
|
|
58
|
+
weight_temp2 = (temp - temp1) / (temp2 - temp1)
|
|
59
|
+
weight_freq1 = (freq2 - freq) / (freq2 - freq1)
|
|
60
|
+
weight_freq2 = (freq - freq1) / (freq2 - freq1)
|
|
61
|
+
|
|
62
|
+
coef_freq1 = coef_temp1_freq1 * weight_temp1 + coef_temp2_freq1 * weight_temp2
|
|
63
|
+
coef_freq2 = coef_temp1_freq2 * weight_temp1 + coef_temp2_freq2 * weight_temp2
|
|
64
|
+
|
|
65
|
+
final_coef = coef_freq1 * weight_freq1 + coef_freq2 * weight_freq2
|
|
66
|
+
|
|
67
|
+
return final_coef
|
|
68
|
+
|
|
69
|
+
if len(nearest_temp) == 2 and len(nearest_freq) == 1:
|
|
70
|
+
temp1, temp2 = nearest_temp
|
|
71
|
+
freq1 = nearest_freq[0]
|
|
72
|
+
|
|
73
|
+
coef_temp1 = air_resist_ratio.loc[freq1, temp1]
|
|
74
|
+
coef_temp2 = air_resist_ratio.loc[freq1, temp2]
|
|
75
|
+
|
|
76
|
+
weight_temp1 = (temp2 - temp) / (temp2 - temp1)
|
|
77
|
+
weight_temp2 = (temp - temp1) / (temp2 - temp1)
|
|
78
|
+
|
|
79
|
+
return coef_temp1 * weight_temp1 + coef_temp2 * weight_temp2
|
|
80
|
+
|
|
81
|
+
if len(nearest_temp) == 1 and len(nearest_freq) == 2:
|
|
82
|
+
temp1 = nearest_temp[0]
|
|
83
|
+
freq1, freq2 = nearest_freq
|
|
84
|
+
|
|
85
|
+
coef_freq1 = air_resist_ratio.loc[freq1, temp1]
|
|
86
|
+
coef_freq2 = air_resist_ratio.loc[freq2, temp1]
|
|
87
|
+
|
|
88
|
+
weight_freq1 = (freq2 - freq) / (freq2 - freq1)
|
|
89
|
+
weight_freq2 = (freq - freq1) / (freq2 - freq1)
|
|
90
|
+
|
|
91
|
+
return coef_freq1 * weight_freq1 + coef_freq2 * weight_freq2
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def dist_to_target_db(
|
|
95
|
+
init_noise_db, target_noise_db, geometric_mean_freq_hz, air_temperature, return_desc=False, check_temp_freq=False
|
|
96
|
+
) -> float | str:
|
|
97
|
+
"""
|
|
98
|
+
Calculates the distance required for a sound wave to decay from an initial noise level to a target noise level,
|
|
99
|
+
based on the geometric mean frequency of the sound and the air temperature. Optionally, can return a description
|
|
100
|
+
of the sound propagation behavior.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
init_noise_db (float): The initial noise level of the source in decibels (dB). This is the starting sound
|
|
104
|
+
intensity.
|
|
105
|
+
target_noise_db (float): The target noise level in decibels (dB), representing the level to which the sound
|
|
106
|
+
decays over distance.
|
|
107
|
+
geometric_mean_freq_hz (float): The geometric mean frequency of the sound (in Hz). This frequency influences
|
|
108
|
+
the attenuation of sound over distance. Higher frequencies decay faster than lower ones.
|
|
109
|
+
air_temperature (float): The temperature of the air in degrees Celsius. This influences the air's resistance
|
|
110
|
+
to sound propagation.
|
|
111
|
+
return_desc (bool, optional): If set to `True`, the function will return a description of the sound decay
|
|
112
|
+
process instead of the calculated distance.
|
|
113
|
+
check_temp_freq (bool, optional): If `True`, the function will check whether the temperature and frequency
|
|
114
|
+
are within valid ranges.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
float or str: If `return_desc` is `False`, the function returns the distance (in meters) over which the sound
|
|
118
|
+
decays from `init_noise_db` to `target_noise_db`. If `return_desc` is `True`, a descriptive string is returned
|
|
119
|
+
explaining the calculation and the conditions.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
def equation(r):
|
|
123
|
+
return l - l_ist + 20 * np.log10(r) + k * r
|
|
124
|
+
|
|
125
|
+
l_ist = init_noise_db
|
|
126
|
+
l = target_noise_db
|
|
127
|
+
k = get_air_resist_ratio(air_temperature, geometric_mean_freq_hz, check_temp_freq)
|
|
128
|
+
initial_guess = 1
|
|
129
|
+
r_solution = fsolve(equation, initial_guess)
|
|
130
|
+
if return_desc:
|
|
131
|
+
string = (
|
|
132
|
+
f"Noise level of {init_noise_db} dB "
|
|
133
|
+
f"with a geometric mean frequency of {geometric_mean_freq_hz} Hz "
|
|
134
|
+
f"at an air temperature of {air_temperature}°C decays to {target_noise_db} dB "
|
|
135
|
+
f"over a distance of {r_solution[0]} meters. Air resistance coefficient: {k}."
|
|
136
|
+
)
|
|
137
|
+
return string
|
|
138
|
+
return r_solution[0]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def green_noise_reduce_db(geometric_mean_freq_hz, r_tree) -> float:
|
|
142
|
+
"""
|
|
143
|
+
Calculates the amount of noise reduction (in dB) provided by vegetation of a given thickness at a specified
|
|
144
|
+
geometric mean frequency. The function models the reduction based on the interaction of the sound with trees or
|
|
145
|
+
vegetation.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
geometric_mean_freq_hz (float): The geometric mean frequency of the sound (in Hz).
|
|
149
|
+
r_tree (float): The thickness or density of the vegetation (in meters).
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
float: The noise reduction (in dB) achieved by the vegetation. This value indicates how much quieter the sound
|
|
153
|
+
will be after passing through or interacting with the vegetation of the specified thickness.
|
|
154
|
+
"""
|
|
155
|
+
return round(0.08 * r_tree * ((geometric_mean_freq_hz ** (1 / 3)) / 8), 1)
|
|
@@ -35,7 +35,7 @@ def simulate_noise(
|
|
|
35
35
|
"""
|
|
36
36
|
Simulates noise propagation from a set of source points considering obstacles, trees, and environmental factors.
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
Args:
|
|
39
39
|
source_points (gpd.GeoDataFrame):
|
|
40
40
|
A GeoDataFrame with one or more point geometries representing noise sources.
|
|
41
41
|
Optionally, it can include 'source_noise_db' and 'geometric_mean_freq_hz' columns for per-point simulation.
|
|
@@ -53,32 +53,33 @@ def simulate_noise(
|
|
|
53
53
|
frequencies. It's recommended to use values between 63 Hz and 8000 Hz; values outside this range will be
|
|
54
54
|
clamped to the nearest boundary for the sound absorption coefficient calculation.
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
Keyword Args:
|
|
57
|
+
absorb_ratio_column (str, optional): The name of the column in the `obstacles` GeoDataFrame that contains the
|
|
58
58
|
sound absorption coefficients for each obstacle. Default is None. If not specified, all obstacles will have
|
|
59
59
|
the `standart_absorb_ratio`.
|
|
60
|
-
|
|
60
|
+
standart_absorb_ratio (float, optional): The default sound absorption coefficient to use for obstacles without
|
|
61
61
|
specified values in the `absorb_ratio_column`. Default is 0.05, which is a typical value for concrete walls.
|
|
62
|
-
|
|
62
|
+
trees (gpd.GeoDataFrame, optional): A GeoDataFrame containing trees or dense vegetation along the sound wave's
|
|
63
63
|
path. Trees will scatter and absorb sound waves.
|
|
64
|
-
|
|
64
|
+
tree_resolution (int, optional): A resolution parameter for simulating tree interactions with sound waves.
|
|
65
65
|
Recommended values are between 2 and 16, with higher values providing more accurate simulation results.
|
|
66
|
-
|
|
66
|
+
air_temperature (float, optional): The air temperature in degrees Celsius. The recommended range is from 0 to
|
|
67
67
|
30 degrees Celsius, as temperatures outside this range will be clipped. Temperature affects the sound
|
|
68
68
|
propagation in the air.
|
|
69
|
-
|
|
69
|
+
target_noise_db (float, optional): The target noise level (in dB) for the simulation. Default is 40 dB.
|
|
70
70
|
Lower values may not be relevant for further analysis, as they are near the threshold of human hearing.
|
|
71
|
-
|
|
71
|
+
db_sim_step (float, optional): The step size in decibels for the noise simulation. Default is 1. For more
|
|
72
72
|
precise analysis, this can be adjusted. If the difference between `source_noise_db` and `target_noise_db`
|
|
73
73
|
is not divisible by the step size, the function will raise an error.
|
|
74
|
-
|
|
74
|
+
reflection_n (int, optional): The maximum number of reflections (bounces) to simulate for each sound wave.
|
|
75
75
|
Recommended values are between 1 and 3. Larger values will result in longer simulation times.
|
|
76
|
-
|
|
76
|
+
dead_area_r (float, optional): A debugging parameter that defines the radius of the "dead zone" for reflections.
|
|
77
77
|
Points within this area will not generate reflections. This is useful to prevent the algorithm from getting
|
|
78
78
|
stuck in corners or along building walls.
|
|
79
|
-
|
|
79
|
+
use_parallel (bool, optional): Whether to use ProcessPool for task distribution or not. Default is True.
|
|
80
|
+
|
|
80
81
|
Returns:
|
|
81
|
-
|
|
82
|
+
gpd.GeoDataFrame: A GeoDataFrame containing the noise simulation results, including noise levels and geometries
|
|
82
83
|
of the affected areas. Each point's simulation results will be merged into a single GeoDataFrame.
|
|
83
84
|
"""
|
|
84
85
|
# Obstacles args
|
|
@@ -31,9 +31,10 @@ def calculate_simplified_noise_frame(
|
|
|
31
31
|
Args:
|
|
32
32
|
noise_sources (gpd.GeoDataFrame): A GeoDataFrame containing geometries of noise sources (Point, LineString,
|
|
33
33
|
or Polygon). Each feature must have the following two columns:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
|
|
35
|
+
- 'source_noise_db': Initial sound level at the source, in decibels (dB).
|
|
36
|
+
- 'geometric_mean_freq_hz': Characteristic sound frequency (Hz) used to model distance-based attenuation.
|
|
37
|
+
|
|
37
38
|
Values in 'source_noise_db' must not exceed the physical maximum of 194 dB. Missing or NaN values in
|
|
38
39
|
required fields will raise an error.
|
|
39
40
|
|
|
@@ -45,21 +46,21 @@ def calculate_simplified_noise_frame(
|
|
|
45
46
|
attenuation model of sound in the atmosphere. Temperatures significantly outside the typical 0–30°C
|
|
46
47
|
range may lead to inaccurate results.
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
Keyword Args:
|
|
50
|
+
target_noise_db (float, optional): The minimum sound level threshold (in dB) to be modeled. Any value below
|
|
50
51
|
this threshold is considered insignificant and will be excluded from the resulting noise frame.
|
|
51
52
|
Default is 40 dB.
|
|
52
|
-
|
|
53
|
+
db_sim_step (float, optional): The simulation step size (in dB) used to discretize sound levels into
|
|
53
54
|
spatial layers. Default is 5. Smaller values produce more detailed output but increase computation time.
|
|
54
|
-
|
|
55
|
+
linestring_point_radius (float, optional): The spacing radius (in meters) used when converting LineString
|
|
55
56
|
geometries into distributed point sources for simulation. Default is 30. Reducing this value improves
|
|
56
57
|
detail along long lines.
|
|
57
|
-
|
|
58
|
+
polygon_point_radius (float, optional): The point spacing (in meters) for distributing sources within
|
|
58
59
|
Polygon geometries. Default is 15. Points are sampled across the polygon’s surface and perimeter to
|
|
59
60
|
represent the full sound-emitting area.
|
|
60
61
|
|
|
61
62
|
Returns:
|
|
62
|
-
|
|
63
|
+
gpd.GeoDataFrame: A GeoDataFrame representing simplified noise distribution areas. The output geometries
|
|
63
64
|
are polygons where each polygon is associated with the maximum sound level (in dB) present in that area,
|
|
64
65
|
as derived from overlapping source zones. The resulting data is dissolved by noise level and returned in
|
|
65
66
|
the original coordinate reference system (CRS) of the input sources.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
from .cluster_points_in_polygons import get_clusters_polygon
|
|
1
|
+
from .cluster_points_in_polygons import get_clusters_polygon
|
|
@@ -39,7 +39,7 @@ def get_clusters_polygon(
|
|
|
39
39
|
Generate cluster polygons for given points based on a specified minimum distance and minimum points per cluster.
|
|
40
40
|
Optionally, calculate the relative ratio between types of points within the clusters.
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
Args:
|
|
43
43
|
points (gpd.GeoDataFrame):
|
|
44
44
|
GeoDataFrame containing the points to be clustered.
|
|
45
45
|
Must include a 'service_code' column for service ratio calculations.
|
|
@@ -47,13 +47,13 @@ def get_clusters_polygon(
|
|
|
47
47
|
Minimum distance between points to be considered part of the same cluster. Defaults to 100.
|
|
48
48
|
min_point (int, optional):
|
|
49
49
|
Minimum number of points required to form a cluster. Defaults to 5.
|
|
50
|
-
method
|
|
50
|
+
method:
|
|
51
51
|
The clustering method to use. Must be either "DBSCAN" or "HDBSCAN". Defaults to "HDBSCAN".
|
|
52
52
|
service_code_column (str, optional):
|
|
53
53
|
Column, containing service type for relative ratio in clasterized polygons. Defaults to "service_code".
|
|
54
54
|
|
|
55
55
|
Returns:
|
|
56
|
-
|
|
56
|
+
tuple[gpd.GeoDataFrame, gpd.GeoDataFrame]:
|
|
57
57
|
A tuple containing the clustered polygons GeoDataFrame and the original points GeoDataFrame with cluster labels.
|
|
58
58
|
"""
|
|
59
59
|
if method not in ["DBSCAN", "HDBSCAN"]:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
from .provision import clip_provision, get_service_provision, recalculate_links
|
|
1
|
+
from .provision import clip_provision, get_service_provision, recalculate_links
|