Skip to content

Commit aa747a4

Browse files
committed
Noise library and examples for basic FFT and frequency binning
1 parent bca0449 commit aa747a4

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed

examples/noise-amps-at-freqs.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import ST7735
2+
from PIL import Image, ImageDraw
3+
from enviroplus.noise import Noise
4+
5+
SAMPLERATE = 16000
6+
7+
FREQ_LOW = 100.0
8+
FREQ_HIGH = 2000.0
9+
WIDTH = 100
10+
11+
noise = Noise()
12+
13+
disp = ST7735.ST7735(
14+
port=0,
15+
cs=ST7735.BG_SPI_CS_FRONT,
16+
dc=9,
17+
backlight=12,
18+
rotation=90)
19+
20+
disp.begin()
21+
22+
img = Image.new('RGB', (disp.width, disp.height), color=(0, 0, 0))
23+
draw = ImageDraw.Draw(img)
24+
25+
26+
while True:
27+
amps = noise.get_amplitudes_at_frequency_ranges([
28+
(100,200),
29+
(500,600),
30+
(1000,1200)
31+
])
32+
amps = [n * 32 for n in amps]
33+
img2 = img.copy()
34+
draw.rectangle((0, 0, disp.width, disp.height), (0, 0, 0))
35+
img.paste(img2, (1, 0))
36+
draw.line((0, 0, 0, amps[0]), fill=(0, 0, 255))
37+
draw.line((0, 0, 0, amps[1]), fill=(0, 255, 0))
38+
draw.line((0, 0, 0, amps[2]), fill=(255, 0, 0))
39+
40+
disp.display(img)
41+

examples/noise-profile.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import ST7735
2+
from PIL import Image, ImageDraw
3+
from enviroplus.noise import Noise
4+
5+
SAMPLERATE = 16000
6+
7+
FREQ_LOW = 100.0
8+
FREQ_HIGH = 2000.0
9+
WIDTH = 100
10+
11+
noise = Noise()
12+
13+
disp = ST7735.ST7735(
14+
port=0,
15+
cs=ST7735.BG_SPI_CS_FRONT,
16+
dc=9,
17+
backlight=12,
18+
rotation=90)
19+
20+
disp.begin()
21+
22+
img = Image.new('RGB', (disp.width, disp.height), color=(0, 0, 0))
23+
draw = ImageDraw.Draw(img)
24+
25+
26+
while True:
27+
low, mid, high, amp = noise.measure()
28+
low *= 128
29+
mid *= 128
30+
high *= 128
31+
amp *= 64
32+
33+
img2 = img.copy()
34+
draw.rectangle((0, 0, disp.width, disp.height), (0, 0, 0))
35+
img.paste(img2, (1, 0))
36+
draw.line((0, 0, 0, amp), fill=(int(low), int(mid), int(high)))
37+
38+
disp.display(img)
39+

library/enviroplus/noise.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import sounddevice
2+
import numpy
3+
import math
4+
5+
class Noise():
6+
def __init__(
7+
self,
8+
sample_rate=16000,
9+
duration=0.5):
10+
11+
self.duration = duration
12+
self.sample_rate = sample_rate
13+
14+
def get_amplitudes_at_frequency_ranges(self, ranges):
15+
recording = self._record()
16+
magnitude = numpy.abs(numpy.fft.rfft(recording[:, 0], n=self.sample_rate))
17+
result = []
18+
for r in ranges:
19+
start, end = r
20+
result.append(numpy.mean(magnitude[start:end]))
21+
return result
22+
23+
def get_amplitude_at_frequency_range(self, start, end):
24+
n = self.sample_rate // 2
25+
if start > n or end > n:
26+
raise ValueError("Maxmimum frequency is {}".format(n))
27+
28+
recording = self._record()
29+
magnitude = numpy.abs(numpy.fft.rfft(recording[:, 0], n=self.sample_rate))
30+
return numpy.mean(magnitude[start:end])
31+
32+
def get_noise_profile(
33+
self,
34+
noise_floor=100,
35+
low=0.12,
36+
mid=0.36,
37+
high=None):
38+
39+
if high is None:
40+
high = 1.0 - low - mid
41+
42+
recording = self._record()
43+
magnitude = numpy.abs(numpy.fft.rfft(recording[:, 0], n=self.sample_rate))
44+
45+
sample_count = (self.sample_rate // 2) - noise_floor
46+
47+
mid_start = noise_floor + int(sample_count * low)
48+
high_start = mid_start + int(sample_count * mid)
49+
noise_ceiling = high_start + int(sample_count * high)
50+
51+
amp_low = numpy.mean(magnitude[self.noise_floor:mid_start])
52+
amp_mid = numpy.mean(magnitude[mid_start:high_start])
53+
amp_high = numpy.mean(magnitude[high_start:noise_ceiling])
54+
amp_total = (low + mid + high) / 3.0
55+
56+
return amp_low, amp_mid, amp_high, amp_total
57+
58+
def _record(self):
59+
return sounddevice.rec(
60+
int(self.duration * self.sample_rate),
61+
samplerate=self.sample_rate,
62+
blocking=True,
63+
channels=1,
64+
dtype='float64'
65+
)
66+

0 commit comments

Comments
 (0)