Jump to content

Measuring how hard you (and your partner) snore at night..


Recommended Posts

Required:

* two Sound Intensity bricklets, dangling some 50cm above where your heads are normally positioned in bed.

* [optional] Wifi module to pipe the collected data to your PC in another room

* some trivial software (below) continuously sampling the stereo bricklets, and dumping the measured values to files.

 

I chose to dump the samples as 32-bit floats so that I can import the "nightly dumps" into Audacity using its "File > Import > Raw Data" feature.

 

My setup produces 2 raw files, one for the "left" and "right" bed positions. Audacity quickly proves that my girlfriend was right in claiming I snore quite loudly.  :-[

 

package com.softwarepearls.apps.hardware.tinkerforge.health.snoring;

import static com.softwarepearls.lego.time.TimeAndDateKit.*;

import com.softwarepearls.lego.audio.enums.StereoPosition;
import com.softwarepearls.lego.filesystem.files.FileKit;
import com.softwarepearls.lego.hardware.tinkerforge.enums.BrickletType;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.input.SoundIntensity;
import com.softwarepearls.lego.hardware.tinkerforge.stack.BrickletDescriptor;
import com.softwarepearls.lego.hardware.tinkerforge.stack.TinkerForgeStack;
import com.softwarepearls.lego.java.system.SystemProperties;
import com.softwarepearls.lego.time.Frequency;
import com.softwarepearls.lego.time.TimeAndDateKit;
import com.tinkerforge.TinkerforgeException;

import java.io.*;
import java.util.Arrays;
import java.util.List;

/**
* Bare-bones two-person "sleep noise" recorder (meant to record snoring). For
* every night, produces two mono sound files holding the noise volume (not true
* sound!) recorded between 20:00 and 09:00.
* <P>
* Find out who snores the loudest, and when (apnea diagnoser?).
*/
public final class SleepRecorder implements Runnable {

private static final int RECORD_START_HOUR = 20;
private static final int RECORD_STOP_HOUR = 9;

private final static Frequency SAMPLING_FREQUENCY = Frequency.EVERY_10_MS;

// the following constants are specific to my personal setup. Modify to suit
// yours.
private final static String STACK_IP_ADDRESS = "192.168.0.114";
private final static String DUMP_FOLDER = "Documents/Audacity/SleepRecordings";

private final static String RIGHT_SENSOR_UID = "mkt";
private final static String LEFT_SENSOR_UID = "mmV";

private static final List<BrickletDescriptor> EXPECTED_BRICKLETS = Arrays.asList(

//
		new BrickletDescriptor(BrickletType.BRICKLET_SOUND_INTENSITY, "mkt"),//
		new BrickletDescriptor(BrickletType.BRICKLET_SOUND_INTENSITY, "mmV")//
		);

private DataOutputStream rightOut;
private DataOutputStream leftOut;

private void go() throws TinkerforgeException, IOException {

	Runtime.getRuntime().addShutdownHook(new Thread(this));

	final TinkerForgeStack tinkerForgeStack = TinkerForgeStack.initializeTinkerForgeStack(EXPECTED_BRICKLETS, STACK_IP_ADDRESS);
	final SoundIntensity rightSoundIntensity = (SoundIntensity) tinkerForgeStack.getBricklet(RIGHT_SENSOR_UID);
	final SoundIntensity leftSoundIntensity = (SoundIntensity) tinkerForgeStack.getBricklet(LEFT_SENSOR_UID);

	boolean recording = false;
	while (true) {
		if (recording) {
			recordSounds(rightSoundIntensity, leftSoundIntensity);

			recording = !waitForEnd();

			if (!recording) {
				closeFiles();
			}
			SAMPLING_FREQUENCY.delay();

		} else {

			recording = waitForStart();
			if (recording) {
				initFiles();
				continue;
			}
			Frequency.EVERY_10_SECOND.delay();
		}
	}
}

private void recordSounds(final SoundIntensity rightSoundIntensity, final SoundIntensity leftSoundIntensity) throws TinkerforgeException, IOException {

	final int rightIntensity = rightSoundIntensity.getIntensity();
	final int leftIntensity = leftSoundIntensity.getIntensity();
	writeToAudioFile(rightIntensity, StereoPosition.RIGHT);
	writeToAudioFile(leftIntensity, StereoPosition.LEFT);
}

private void initFiles() throws IOException {

	System.out.println("Initializing recordings for today " + currentDayOfMonth() + " " + currentMonth());

	rightOut = initRecordingFile(StereoPosition.RIGHT);
	leftOut = initRecordingFile(StereoPosition.LEFT);
}

private void closeFiles() throws IOException {

	System.out.println("Closing recordings.");

	rightOut.close();
	leftOut.close();
	rightOut = leftOut = null;
}

private DataOutputStream initRecordingFile(final StereoPosition stereoPosition) throws IOException {

	final File userHome = new File(SystemProperties.getUserHome());
	final File dumpRootDirectory = new File(userHome, DUMP_FOLDER);
	final File yearDirectory = new File(dumpRootDirectory, "" + currentYear());
	final String monthDirName = String.format("%02d_%s", currentMonthNumber() + 1, currentMonth());
	final File monthDirectory = new File(yearDirectory, monthDirName);
	FileKit.ensurePathExists(monthDirectory.getAbsolutePath());

	final String filename = String.format("%02d_%s_%s.raw", currentDayOfMonth(), currentDayName().substring(0, 3), stereoPosition);
	final File noiseFile = new File(monthDirectory, filename);
	System.out.println("Opened OK: " + noiseFile);
	final FileOutputStream fos = new FileOutputStream(noiseFile);
	final BufferedOutputStream bos = new BufferedOutputStream(fos);
	final DataOutputStream dos = new DataOutputStream(bos);

	return dos;
}

private void writeToAudioFile(final int intensity, final StereoPosition position) throws IOException {

	DataOutputStream out = rightOut;
	if (position == StereoPosition.LEFT) {
		out = leftOut;
	}
	final float floatIntensity = ((float) intensity) / 4096;
	out.writeFloat(floatIntensity);
}

private boolean waitForStart() {

	// return true;
	return TimeAndDateKit.currentHour() == RECORD_START_HOUR;
}

private boolean waitForEnd() {

	return TimeAndDateKit.currentHour() == RECORD_STOP_HOUR;
}

public static void main(final String[] args) throws TinkerforgeException, IOException {

	new SleepRecorder().go();
}

@Override
public void run() {

	try {
		closeFiles();
	}
	catch (final IOException e) {
		e.printStackTrace();
	}
}
}

Link zu diesem Kommentar
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

×
×
  • Neu erstellen...