-
Notifications
You must be signed in to change notification settings - Fork 69
/
wind_direction.py
executable file
·111 lines (88 loc) · 3.62 KB
/
wind_direction.py
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
#!/usr/bin/python3
import json
import time
import math
import MCP342X
import os
class wind_direction(object):
def __init__(self, adc_channel=0, config_file=None):
self.adc_channel = adc_channel
self.adc = MCP342X.MCP342X(address=0x69)
config_file_path = os.path.join(os.path.dirname(__file__), config_file)
with open(config_file_path, "r") as f:
self.config = json.load(f)
vin = self.config["vin"]
vdivider = self.config["vdivider"]
for dir in self.config["directions"]:
dir["vout"] = self.calculate_vout(vdivider, dir["ohms"], vin)
dir["adc"] = round(self.adc.max * (dir["vout"] / self.adc.vref))
sorted_by_adc = sorted(self.config["directions"], key=lambda x: x["adc"])
for index, dir in enumerate(sorted_by_adc):
if index > 0:
below = sorted_by_adc[index - 1]
delta = (dir["adc"] - below["adc"]) / 2.0
dir["adcmin"] = dir["adc"] - delta + 1
else:
dir["adcmin"] = 1
if index < (len(sorted_by_adc) - 1):
above = sorted_by_adc[index + 1]
delta = (above["adc"] - dir["adc"]) / 2.0
dir["adcmax"] = dir["adc"] + delta
else:
dir["adcmax"] = self.adc.max - 1
def calculate_vout(self, ra, rb, vin): # Ohm's law resistive divider calculation
return (float(rb) / float(ra + rb)) * float(vin)
def get_dir(self, adc_value):
angle = None
for dir in self.config["directions"]:
if (adc_value > 0 and
adc_value >= dir["adcmin"] and
adc_value <= dir["adcmax"] and
adc_value < self.adc.max):
angle = dir["angle"]
break
return angle
def get_average(self, angles):
"""
Consider the following three angles as an example: 10, 20, and 30
degrees. Intuitively, calculating the mean would involve adding these
three angles together and dividing by 3, in this case indeed resulting
in a correct mean angle of 20 degrees. By rotating this system
anticlockwise through 15 degrees the three angles become 355 degrees,
5 degrees and 15 degrees. The naive mean is now 125 degrees, which is
the wrong answer, as it should be 5 degrees.
"""
# http://en.wikipedia.org/wiki/Directional_statistics
sin_sum = 0.0
cos_sum = 0.0
for angle in angles:
r = math.radians(angle)
sin_sum += math.sin(r)
cos_sum += math.cos(r)
flen = float(len(angles))
s = sin_sum / flen
c = cos_sum / flen
arc = math.degrees(math.atan(s / c))
average = 0.0
if s > 0 and c > 0:
average = arc
elif c < 0:
average = arc + 180
elif s < 0 and c > 0:
average = arc + 360
return 0.0 if average == 360 else average
def get_value(self, length=5):
data = []
print("Measuring wind direction for %d seconds..." % length)
start_time = time.time()
while time.time() - start_time <= length:
adc_value = self.adc.read(self.adc_channel)
direction = self.get_dir(adc_value)
if direction is not None: # keep only good measurements
data.append(direction)
else:
print("Could not determine wind direction for ADC reading: %s" % adc_value)
return self.get_average(data)
if __name__ == "__main__":
obj = wind_direction(0, "wind_direction.json")
print(obj.get_value(10))