-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimulation.py
More file actions
279 lines (219 loc) · 9.46 KB
/
Copy pathsimulation.py
File metadata and controls
279 lines (219 loc) · 9.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
"""
Position simulation module for NavIC + LoRa monitoring system
Generates realistic positioning data when hardware is unavailable
"""
import random
import time
import math
from datetime import datetime
import config
from distance import calculate_position_from_rssi
class PositionSimulator:
"""Handles simulation of NavIC and LoRa positioning data"""
def __init__(self):
self.base_lat, self.base_lon = config.BASE_COORDS
self.human_pos = (self.base_lat, self.base_lon)
self.cow_positions = [
(self.base_lat + 0.001, self.base_lon + 0.001), # Cow 1
(self.base_lat - 0.001, self.base_lon + 0.002) # Cow 2
]
self.simulation_start_time = time.time()
def simulate_navic_position(self, base_lat=None, base_lon=None):
"""
Simulate realistic human movement using NavIC positioning
Args:
base_lat: Base latitude (optional, uses config default)
base_lon: Base longitude (optional, uses config default)
Returns:
Tuple of (latitude, longitude) for current human position
"""
# Check if fixed position mode is enabled
if config.FIXED_POSITION_MODE:
self.human_pos = config.FIXED_HUMAN_COORDS
return self.human_pos
if base_lat is None:
base_lat = self.base_lat
if base_lon is None:
base_lon = self.base_lon
# Create realistic movement pattern
elapsed_time = time.time() - self.simulation_start_time
# Slow walking pattern with some randomness
movement_scale = config.HUMAN_MOVEMENT_RANGE
# Use sine wave for smooth movement with random component
lat_variation = movement_scale * (
0.5 * math.sin(elapsed_time / 60) + # 1-minute cycle
0.3 * random.uniform(-1, 1) # Random component
)
lon_variation = movement_scale * (
0.5 * math.cos(elapsed_time / 80) + # Slightly different cycle
0.3 * random.uniform(-1, 1) # Random component
)
new_lat = base_lat + lat_variation
new_lon = base_lon + lon_variation
# Update internal position
self.human_pos = (new_lat, new_lon)
return self.human_pos
def simulate_lora_signals(self, human_pos, num_cows=2):
"""
Generate RSSI values and estimate cow positions based on signal strength
Args:
human_pos: Tuple of (latitude, longitude) for human position
num_cows: Number of cows to simulate (default: 2)
Returns:
List of dictionaries containing cow data with positions and RSSI
"""
cow_data = []
for i in range(num_cows):
# Simulate RSSI with realistic values
# Closer cows have stronger signals (less negative RSSI)
base_rssi = random.uniform(config.RSSI_MIN, config.RSSI_MAX)
# Add some time-based variation to simulate movement
elapsed_time = time.time() - self.simulation_start_time
rssi_variation = 5 * math.sin(elapsed_time / (30 + i * 10)) # Different periods for each cow
current_rssi = base_rssi + rssi_variation
# Ensure RSSI stays within realistic bounds
current_rssi = max(config.RSSI_MIN, min(config.RSSI_MAX, current_rssi))
# Calculate estimated position based on RSSI
# Use different angle offsets for each cow
angle_offset = i * 120 + (elapsed_time / 10) % 360 # Rotating positions
estimated_pos = calculate_position_from_rssi(human_pos, current_rssi, angle_offset)
# Add some random movement to cow positions
movement_scale = config.COW_MOVEMENT_RANGE
lat_noise = movement_scale * random.uniform(-0.5, 0.5)
lon_noise = movement_scale * random.uniform(-0.5, 0.5)
final_lat = estimated_pos[0] + lat_noise
final_lon = estimated_pos[1] + lon_noise
cow_info = {
'id': i + 1,
'lat': final_lat,
'lon': final_lon,
'rssi': round(current_rssi, 1),
'timestamp': datetime.now().isoformat(),
'signal_quality': self._assess_signal_quality(current_rssi)
}
cow_data.append(cow_info)
# Update internal cow positions
if i < len(self.cow_positions):
self.cow_positions[i] = (final_lat, final_lon)
return cow_data
def _assess_signal_quality(self, rssi):
"""
Assess LoRa signal quality based on RSSI value
Args:
rssi: RSSI value in dBm
Returns:
String describing signal quality
"""
if rssi > -70:
return 'Excellent'
elif rssi > -85:
return 'Good'
elif rssi > -100:
return 'Fair'
else:
return 'Poor'
def get_current_positions(self):
"""
Get current positions for human and all cows
Returns:
Dictionary with human coordinates and cow data
"""
# Update human position with NavIC simulation
human_coords = self.simulate_navic_position()
# Generate cow positions with LoRa simulation
cow_data = self.simulate_lora_signals(human_coords)
return {
'human': {
'lat': human_coords[0],
'lon': human_coords[1],
'timestamp': datetime.now().isoformat(),
'positioning_system': 'NavIC'
},
'cows': cow_data,
'system_time': datetime.now().isoformat(),
'update_interval': config.UPDATE_INTERVAL
}
def generate_test_scenario(self, scenario_type='normal'):
"""
Generate specific test scenarios for system validation
Args:
scenario_type: Type of scenario ('normal', 'alert', 'mixed')
Returns:
Position data for the specified scenario
"""
human_pos = self.simulate_navic_position()
if scenario_type == 'alert':
# Force cows to be beyond alert threshold
cow_data = []
for i in range(2):
# Place cows at distances > 100m
distance = random.uniform(120, 200)
angle = random.uniform(0, 360)
lat_offset = (distance * math.cos(math.radians(angle))) / 111000
lon_offset = (distance * math.sin(math.radians(angle))) / (111000 * math.cos(math.radians(human_pos[0])))
cow_lat = human_pos[0] + lat_offset
cow_lon = human_pos[1] + lon_offset
# Generate corresponding RSSI for this distance
rssi = config.RSSI_REFERENCE - 10 * config.PATH_LOSS_EXPONENT * math.log10(distance)
rssi = max(config.RSSI_MIN, min(config.RSSI_MAX, rssi))
cow_data.append({
'id': i + 1,
'lat': cow_lat,
'lon': cow_lon,
'rssi': round(rssi, 1),
'timestamp': datetime.now().isoformat(),
'signal_quality': self._assess_signal_quality(rssi)
})
elif scenario_type == 'normal':
# Keep cows within safe distance
cow_data = self.simulate_lora_signals(human_pos)
else: # mixed scenario
cow_data = self.simulate_lora_signals(human_pos)
return {
'human': {
'lat': human_pos[0],
'lon': human_pos[1],
'timestamp': datetime.now().isoformat(),
'positioning_system': 'NavIC'
},
'cows': cow_data,
'system_time': datetime.now().isoformat(),
'scenario_type': scenario_type
}
def reset_simulation(self):
"""Reset simulation to initial state"""
self.human_pos = (self.base_lat, self.base_lon)
self.cow_positions = [
(self.base_lat + 0.001, self.base_lon + 0.001),
(self.base_lat - 0.001, self.base_lon + 0.002)
]
self.simulation_start_time = time.time()
# Global simulator instance
simulator = PositionSimulator()
def get_current_positions():
"""
Convenience function to get current positions
Returns:
Current position data for human and cows
"""
return simulator.get_current_positions()
def simulate_navic_position(base_lat=None, base_lon=None):
"""
Convenience function for NavIC position simulation
Args:
base_lat: Base latitude
base_lon: Base longitude
Returns:
Tuple of (latitude, longitude) for human position
"""
return simulator.simulate_navic_position(base_lat, base_lon)
def simulate_lora_signals(human_pos, num_cows=2):
"""
Convenience function for LoRa signal simulation
Args:
human_pos: Human position tuple
num_cows: Number of cows to simulate
Returns:
List of cow data with RSSI and positions
"""
return simulator.simulate_lora_signals(human_pos, num_cows)