Hollerer
Posts: 2
Joined: Sat Sep 29, 2018 3:02 am

Sound Sensor - Counting Trains

Wed Oct 17, 2018 11:06 pm

I’m trying to use a sound sensor to do two things: (1) determine if a train is passing by my house and (2) determine approximately how many seconds the train is present for. I’m hoping someone on here can help me with #2.

#1) To determine if a train is present, I’ve cobbled together some code that samples the value of the GPIO pin about ~2,000 times over ten seconds. If the sensor reads high for more than 10% of the sampled 10 seconds, a train is considered to be present.

#2) I’m currently planning to embed a series of additional if statements that each sample a new 10 second window if a train was present in the previous if statement. However, it seems really inefficient to have 36 sequential if statements to find out if a train was passing by my house for 5 minutes. Is there a better approach??

Quick disclaimer: This is my first raspberry pi / coding project—I’m open to any suggestions to improve the program.

Code: Select all

#!/usr/bin/python
import sys
import urllib2
import RPi.GPIO as GPIO
import time

myAPI = 'YW9KT0LI9W72Z7JY'
baseURL = 'https://api.thingspeak.com/update?api_key=%s' % myAPI

#GPIO SETUP
channel = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(channel, GPIO.IN)

def callback(channel):
        startTime = time.time()
        endTime = startTime + 10 # creates sample window
        soundPresentCount = 0.0 # number of instances in sample window where GPIO is HIGH
        soundAbsentCount = 0.0 # number of instances in sample window where GPIO is LOW
        while time.time() <= endTime:
			if GPIO.input(channel):
				soundPresentCount = soundPresentCount + 1.0
				time.sleep(0.005)
			else:
				soundAbsentCount = soundAbsentCount + 1.0
				time.sleep(0.005)
	print ("Counted Presents:"), soundPresentCount
	print ("Counted Absents:"), soundAbsentCount
	totalCount = soundPresentCount + soundAbsentCount
	print ("Total Count:"), totalCount
	presentPercent=(soundPresentCount/totalCount)*100.0
	print (presentPercent)
	if presentPercent>=10.0:
		trainCount = 1
		trainDuration = trainDuration + 10.0
		print ("Train Detected")
		conn = urllib2.urlopen(baseURL + '&field1=%s&field2=%s' % (trainCount, trainDuration))
		print conn.read()
		conn.close()
		soundAbsentCount = 0.0
		soundPresentCount = 0.0
	else:
		print ("No Train Detected")
		soundAbsentCount = 0.0
		soundPresentCount = 0.0
			
GPIO.add_event_detect(channel, GPIO.BOTH, bouncetime=50)  # let me know when the pin goes HIGH or LOW
GPIO.add_event_callback(channel, callback)  # assign function to GPIO PIN, Run function on change
 
# infinite loop
while True:
        time.sleep(0.5)

User avatar
Joel_Mckay
Posts: 150
Joined: Mon Nov 12, 2012 10:22 pm
Contact: Website

Re: Sound Sensor - Counting Trains

Thu Oct 18, 2018 4:23 am

Probably a usb sound-card/microphone or accelerometer would be more reliable.

I'd look for loud low-frequency rumbling peaks with a simple DFT in:
https://github.com/mborgerding/kissfft

Or a python wrapper for the awesome GSL library which does just about everything ( like finding treasure ;-) )
https://sourceforge.net/projects/pygsl/
https://www.gnu.org/software/gsl/doc/html/fft.html

Assuming fixed train velocity, measuring the Doppler frequency-shift should be able to identify the proximity minimum-distance location (shift ramp-up becomes ramp-down). You may even be able to approximate its traveling speed by measuring the selected Hz peak at time t before the shift-trend change event, assuming the train velocity remains constant, and measuring the Hz peak at time t after the shift-trend change event.
https://www.omnicalculator.com/physics/doppler-effect
;-)

Best of luck,
~J~

klricks
Posts: 5899
Joined: Sat Jan 12, 2013 3:01 am
Location: Grants Pass, OR, USA
Contact: Website

Re: Sound Sensor - Counting Trains

Thu Oct 18, 2018 4:46 am

Hollerer wrote:
Wed Oct 17, 2018 11:06 pm
........
#2) I’m currently planning to embed a series of additional if statements that each sample a new 10 second window if a train was present in the previous if statement. However, it seems really inefficient to have 36 sequential if statements to find out if a train was passing by my house for 5 minutes. Is there a better approach??
...
Not sure why you think you need 36 statements?
I would save a date/time stamp of when the train (noise) was detected then start an if loop waiting for noise to stop and then date/timestamp that.
Do maths on the timestamps to figure duration.....
How does the sensor distinguish other noise such as radio/TV........ Aircraft overhead etc?
Unless specified otherwise my response is based on the latest and fully updated Raspbian Stretch w/ Desktop OS.

Return to “Automation, sensing and robotics”