A Sleep Sensor Made with Electret Condenser Microphones
Abstract
1. Introduction
2. Results
3. Discussion
4. Materials and Methods
4.1. Sensor and Circuit Overview
4.2. Wireless Data Transmission Module
4.3. Consideration of the Sensor Amplifier Circuit
4.4. Possibility of Reducing Crosstalk Using Regulators
4.5. Biasing an ECM with a Constant Current
4.6. Consideration of Circuit Constants and Components
4.6.1. Power Supply Voltage
4.6.2. I/V Resistance
4.6.3. Low-Pass Filter (LPF) and High-Pass Filter (HPF)
4.6.4. Reference Voltage
4.6.5. XBee ADC Midpoint Voltage
4.6.6. Resistor to Measure Remaining Battery Capacity
4.6.7. Op-amps
Requirements for Op-amps to Amplify the ECM
Op-amp Current
Op-amp Noise
Level Shifting of the Op-amp
4.7. Pressure Calibration Using a Micro-Pressure Sensor
5. Conclusions
6. Patents
Author Contributions
Funding
Institutional Review Board Statement
Informed Consent Statement
Data Availability Statement
Acknowledgments
Conflicts of Interest
Appendix A
Appendix B
- import java.io.*;
- import processing.serial.*;
- import com.rapplogic.xbee.*;
- import com.rapplogic.xbee.api.*;
- import com.rapplogic.xbee.api.wpan.*;
- import com.rapplogic.xbee.api.ZigBee.*;
- import com.rapplogic.xbee.examples.*;
- import com.rapplogic.xbee.examples.wpan.*;
- import com.rapplogic.xbee.examples.ZigBee.*;
- import com.rapplogic.xbee.socket.*;
- import com.rapplogic.xbee.test.*;
- import com.rapplogic.xbee.util.*;
- import controlP5.*;
- ControlP5 cp5;
- Chart adcChart;
- XBee xbee;
- XBeeAddress16 sensor_address16 = new XBeeAddress16(0, 0);
- public void nodeDiscovery(int theValue) {
- if(xbee.isConnected() == false) { return; }
- println("nodeDiscovery");
- try{
- xbee.sendAsynchronous(new AtCommand("ND"));
- }
- catch(XBeeException xe){ ; }
- cp5.get(ScrollableList.class, "sensors").clear();
- }
- public void setADC(int theValue) {
- if(sensor_address16.get16BitValue() == 0) { return; }
- println("setADC");
- XBeeAddress16 remoteAddress = sensor_address16;
- RemoteAtRequest request0 = new RemoteAtRequest(remoteAddress, "D0", 2);
- RemoteAtRequest request1 = new RemoteAtRequest(remoteAddress, "D1", 2);
- RemoteAtRequest request2 = new RemoteAtRequest(remoteAddress, "D2", 2);
- RemoteAtRequest request3 = new RemoteAtRequest(remoteAddress, "D3", 2);
- //int[] val = {0x13,0x88};
- int[] val = {0xff,0xfe};
- RemoteAtRequest request4 = new RemoteAtRequest(remoteAddress, "ST", val);
- try{
- xbee.sendAsynchronous(request0);
- xbee.sendAsynchronous(request1);
- //xbee.sendAsynchronous(request2);
- //xbee.sendAsynchronous(request3);
- xbee.sendAsynchronous(request4);
- }
- catch(XBeeException xe){ ; }
- }
- public void startSampling(int theValue) {
- if(sensor_address16.get16BitValue() == 0) { return; }
- println("startSampling");
- XBeeAddress16 remoteAddress = sensor_address16;
- //int[] val = {0,0x64}; // = 100 ms, 10 Hz
- //int[] val = {0,0x50}; // = 80 ms, 12.5 Hz
- //int[] val = {0,0x4b}; // = 75 ms, 13.33 Hz
- int[] val = {0,0x32}; // = 50 ms, 20 Hz ~ actual 12.5 Hz
- RemoteAtRequest request0 = new RemoteAtRequest(remoteAddress, “IR”, val);
- try{
- xbee.sendAsynchronous(request0);
- }
- catch(XBeeException xe){ ; }
- }
- public void stopSampling(int theValue) {
- if(sensor_address16.get16BitValue() == 0) { return; }
- println("stopSampling");
- XBeeAddress16 remoteAddress = sensor_address16;
- int[] val = {0,0};
- RemoteAtRequest request0 = new RemoteAtRequest(remoteAddress, "IR", val);
- try{
- xbee.sendAsynchronous(request0);
- }
- catch(XBeeException xe){ ; }
- }
- void setup(){
- size(1024, 768);
- cp5 = new ControlP5(this);
- adcChart = cp5.addChart("ADC View")
- .setPosition(10, 10)
- .setSize(800, 400)
- .setRange(0, 1.2)
- .setView(Chart.LINE) // use Chart.LINE, Chart.PIE, Chart.AREA, Chart.BAR_CENTERED
- .setStrokeWeight(1.5)
- .setColorCaptionLabel(color(40));
- adcChart.addDataSet("adc0");
- adcChart.setColors("adc0", color(200,50,0));
- adcChart.setData("adc0", new float[200]);
- adcChart.addDataSet("adc1");
- adcChart.setColors("adc1", color(0,200,100));
- adcChart.setData("adc1", new float[200]);
- cp5.addButton("nodeDiscovery")
- .setValue(0) .setPosition(220,440) .setSize(200,20);
- cp5.addButton("setADC")
- .setValue(0) .setPosition(220,470) .setSize(200,20);
- cp5.addButton("startSampling")
- .setValue(0) .setPosition(220,500) .setSize(200,20);
- cp5.addButton("stopSampling")
- .setValue(0) .setPosition(220,530) .setSize(200,20);
- cp5.addScrollableList("serialPort")
- .setPosition(10, 440) .setSize(200,100)
- .setBarHeight(20) .setItemHeight(20)
- .addItems(Serial.list())
- .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
- ;
- cp5.addScrollableList("sensors")
- .setPosition(430, 440) .setSize(200,100)
- .setBarHeight(20) .setItemHeight(20)
- .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
- ;
- cp5.addTextfield("outputfile")
- .setPosition(640, 440)
- .setSize(200,40)
- .setColor(color(255,0,0))
- ;
- cp5.get(Textfield.class,"outputfile").setText("output.csv");
- xbee = new XBee();
- }
- void serialPort(int n) {
- String port = (String)cp5.get(ScrollableList.class, "serialPort").getItem(n).get("text");
- print(port);
- if(xbee.isConnected() == true) {
- xbee.close();
- }
- try{
- xbee.open(port , 9600);
- System.out.print(" " + port + ">succeeded");
- }
- catch(XBeeException xe){
- System.out.print(" " + port + ">failed");
- }
- if(xbee.isConnected() == true) {
- xbee.addPacketListener(new XBeeListener());
- }
- }
- public void controlEvent(ControlEvent theEvent) {
- println("controlEvent:" + theEvent.getController().getName());
- }
- public static final int BUFSIZE = 200;
- float[] adcbuf0 = new float[BUFSIZE];
- float[] adcbuf1 = new float[BUFSIZE];
- int ptbuf0 = 0;
- int ptcount = 0;
- void draw() {
- background(140);
- if(ptcount != ptbuf0) {
- int diff = Math.abs(ptbuf0 - ptcount);
- try{
- Writer writer = new FileWriter(cp5.get(Textfield.class,"outputfile").getText(),true);
- if(diff < BUFSIZE/2) { // without loop back
- for(int i = ptcount;i < ptbuf0;i ++) {
- print("("+i+")");
- adcChart.push("adc0", adcbuf0[i]);
- adcChart.push("adc1", adcbuf1[i]);
- writer.write(nf(year(),4)+","+nf(month(),2)+","+nf(day(),2)+","+nf(hour(),2) + "," + nf(minute(),2) + "," + nf(second(),2) + ",");
- writer.write(String.format("%.3f",adcbuf0[i]) + "," + String.format("%.3f",adcbuf1[i])+"\r\n");
- }
- } else { // with loop end back
- for(int i = ptcount;i < BUFSIZE;i ++) {
- print("("+i+")");
- adcChart.push("adc0", adcbuf0[i]);
- adcChart.push("adc1", adcbuf1[i]);
- writer.write(nf(year(),4)+","+nf(month(),2)+","+nf(day(),2)+","+nf(hour(),2) + "," + nf(minute(),2) + "," + nf(second(),2) + ",");
- writer.write(String.format("%.3f",adcbuf0[i]) + "," + String.format("%.3f",adcbuf1[i])+"\r\n");
- }
- for(int i = 0;i < ptbuf0;i ++) {
- print("("+i+")");
- adcChart.push("adc0", adcbuf0[i]);
- adcChart.push("adc1", adcbuf1[i]);
- writer.write(nf(year(),4)+","+nf(month(),2)+","+nf(day(),2)+","+nf(hour(),2) + "," + nf(minute(),2) + "," + nf(second(),2) + ",");
- writer.write(String.format("%.3f",adcbuf0[i]) + "," + String.format("%.3f",adcbuf1[i])+"\r\n");
- }
- }
- writer.close();
- } catch(IOException ex) {
- ex.printStackTrace();
- }
- ptcount = ptbuf0;
- }
- }
- class XBeeListener implements PacketListener{
- public void processResponse(XBeeResponse response){
- ApiId id = response.getApiId();
- print(""+id.toString());
- switch(id){
- case ZNET_IO_SAMPLE_RESPONSE:
- ZNetRxIoSampleResponse ioSample = (ZNetRxIoSampleResponse)response;
- print(" AD0=" + String.format("%.3f", (float)ioSample.getAnalog0()*1.2/1024));
- print(" AD1=" + String.format("%.3f", (float)ioSample.getAnalog1()*1.2/1024));
- //print(" AD2=" + String.format("%.3f", (float)ioSample.getAnalog2()*1.2/1024));
- //print(" AD3=" + String.format("%.3f", (float)ioSample.getAnalog3()*1.2/1024));
- if(ptbuf0 >= BUFSIZE) { ptbuf0 = 0; }
- adcbuf0[ptbuf0] = (float)ioSample.getAnalog0()*1.2/1024.0;
- adcbuf1[ptbuf0] = (float)ioSample.getAnalog1()*1.2/1024.0;
- ptbuf0 ++;
- break;
- case ZNET_RX_RESPONSE:
- ZNetRxResponse rx = (ZNetRxResponse) response;
- println(ByteUtils.toBase16(rx.getRemoteAddress64().getAddress()));
- println(ByteUtils.toString(rx.getData()));
- break;
- case AT_RESPONSE:
- AtCommandResponse atResponse = (AtCommandResponse) response;
- if (atResponse.isOk()) {
- println("At Command successful: " + ByteUtils.toBase16(atResponse.getValue()));
- ZBNodeDiscover node = ZBNodeDiscover.parse(atResponse);
- println("NodeAddress16: " + ByteUtils.toBase16(node.getNodeAddress16().getAddress()));
- println("NodeAddress64: " + ByteUtils.toBase16(node.getNodeAddress64().getAddress()));
- cp5.get(ScrollableList.class, "sensors").addItem((String)ByteUtils.toBase16(node.getNodeAddress16().getAddress()),0);
- if(!sensor_address16.equals(node.getNodeAddress16()) && node.getNodeAddress16().get16BitValue() != 0) {
- sensor_address16 = node.getNodeAddress16();
- println("Sensor was registered.");
- }
- } else {
- println("At Command failed: " + ByteUtils.toBase16(atResponse.getValue()));
- }
- break;
- case REMOTE_AT_RESPONSE:
- RemoteAtResponse remoteAtResponse = (RemoteAtResponse) response;
- if (remoteAtResponse.isOk()) {
- println("RemoteAt Ok.");
- } else {
- println("RemoteAt Failed.");
- }
- break;
- default:
- print("?");
- break;
- }
- println(".");
- }
- }
Appendix C
Appendix D
Appendix E
Appendix F
References
- Snoeks, S.; Velasco, E.; Talavera, K.; Hellings, P.W. Nasal Obstruction: Overview of Pathophysiology and Presentation of a Clinically Relevant Preoperative Plan for Rhino(Septo)plasty. Facial Plast. Surg. 2024, 40, 275–286. [Google Scholar] [CrossRef] [PubMed]
- Trang, H.; Leske, V.; Gaultier, C. Use of nasal cannula for detecting sleep apneas and hypopneas in infants and children. Am. J. Respir. Crit. Care Med. 2002, 166, 464–468. [Google Scholar] [CrossRef] [PubMed]
- Choudhury, N.; Deshmukh, P. Obstructive Sleep Apnea in Adults and Ear, Nose, and Throat (ENT) Health: A Narrative Review. Cureus 2023. [Google Scholar] [CrossRef] [PubMed]
- Yeghiazarians, Y.; Jneid, H.; Tietjens, J.R.; Redline, S.; Brown, D.L.; El-Sherif, N.; Mehra, R.; Bozkurt, B.; Ndumele, C.E.; Somers, V.K. Obstructive Sleep Apnea and Cardiovascular Disease: A Scientific Statement from the American Heart Association. Circulation 2021, 144, E56–E67. [Google Scholar] [CrossRef]
- Kurnool, S.; McCowen, K.C.; Bernstein, N.A.; Malhotra, A. Sleep Apnea, Obesity, and Diabetes—An Intertwined Trio. Curr. Diab. Rep. 2023, 23, 165–171. [Google Scholar] [CrossRef]
- Gills, J.L.; Bubu, O.M. Obstructive Sleep Apnea and Alzheimer’s Disease Pathology: Is Sleep Architecture the Missing Key? J. Alzheimer’s Dis. 2024, 98, 69–73. [Google Scholar] [CrossRef]
- Jeng, Y.N.; Yang, T.M.; Lee, S.Y. Response identification in the extremely low frequency region of an electret condenser microphone. Sensors 2011, 11, 623–637. [Google Scholar] [CrossRef]
- Kinnerup, R.T.; Knott, A.; Thomsen, O.C.; Marbjerg, K.; Rasmussen, P. Preamplifier with ultra low frequency cutoff for infrasonic condenser microphone. In Proceedings of the American Society of Mechanical Engineers, Noise Control and Acoustics Division (Publication) NCAD, New York City, NY, USA,, 19–22 August 2012; pp. 605–616. [Google Scholar]
- Stoksted, P. Rhinometric measurements for determination of the nasal cycle. Acta Otolaryngol. 1953, 43, 159–175. [Google Scholar] [CrossRef]
- Kahana-Zweig, R.; Geva-Sagiv, M.; Weissbrod, A.; Secundo, L.; Soroker, N.; Sobel, N. Measuring and characterizing the human nasal cycle. PLoS ONE 2016, 11, e0162918. [Google Scholar] [CrossRef]
- Shannahoff-Khalsa, D. Lateralized rhythms of the central and autonomic nervous systems. Int. J. Psychophysiol. 1991, 11, 225–251. [Google Scholar] [CrossRef]
- Ishii, J.; Ishii, T.; Ito, M. The nasal cycle in patients with autonomic nervous disturbance. Acta Otolaryngol. 1993, 113, 51–56. [Google Scholar] [CrossRef] [PubMed]
- Norman, R.G.; Ahmed, M.M.; Walsleben, J.A.; Rapoport, D.M. Detection of respiratory events during NPSG: Nasal cannula/pressure sensor versus thermistor. Sleep 1997, 20, 1175–1184. [Google Scholar] [CrossRef] [PubMed]
- Roopa Manjunatha, G.; Roy Mahapatra, D.; Prakash, S.; Rajanna, K. Validation of polyvinylidene fluoride nasal sensor to assess nasal obstruction in comparison with subjective technique. Am. J. Otolaryngol.—Head Neck Med. Surg. 2015, 36, 122–129. [Google Scholar] [CrossRef] [PubMed]
- Hakimi, A.A.; Sharma, G.K.; Ngo, T.; Heidari, A.E.; Badger, C.D.; Tripathi, P.B.; Hong, E.M.; Chen, Z.; Wong, B.J.F. Coupling Pressure Sensing with Optical Coherence Tomography to Evaluate the Internal Nasal Valve. Ann. Otol. Rhinol. Laryngol. 2021, 130, 167–172. [Google Scholar] [CrossRef]
- Silvestri, S.; Schena, E. Micromachined flow sensors in biomedical applications. Micromachines 2012, 3, 225–243. [Google Scholar] [CrossRef]
- Kottapalli, A.G.P.; Tan, C.W.; Olfatnia, M.; Miao, J.M.; Barbastathis, G.; Triantafyllou, M. A liquid crystal polymer membrane MEMS sensor for flow rate and flow direction sensing applications. J. Micromech. Microeng. 2011, 21, 085006. [Google Scholar] [CrossRef]
- Dong, W.; Sheng, K.; Huang, B.; Xiong, K.; Liu, K.; Cheng, X. Stretchable self-powered TENG sensor array for human robot interaction based on conductive ionic gels and LSTM neural network. IEEE Sens. J. 2024, 24, 37962–37969. [Google Scholar] [CrossRef]
- Jiang, P.; Zhao, S.; Zhu, R. Smart sensing strip using monolithically integrated flexible flow sensor for noninvasively monitoring respiratory flow. Sensors (Switzerland) 2015, 15, 31738–31750. [Google Scholar] [CrossRef]
- Sabil, A.; Glos, M.; GüNther, A.; Schöbel, C.; Veauthier, C.; Fietze, I.; Penzel, T. Comparison of apnea detection using oronasal thermal air?ow sensor, nasal pressure transducer, respiratory inductance plethysmography and tracheal sound sensor. J. Clin. Sleep Med. 2019, 15, 285–292. [Google Scholar] [CrossRef]
- Teichtahl, H.; Cunnington, D.; Cherry, G.; Wang, D. Scoring polysomnography respiratory events: The utility of nasal pressure and oro-nasal thermal sensor recordings. Sleep Med. 2003, 4, 419–425. [Google Scholar] [CrossRef]
- Berry, R.B.; Koch, G.L.; Trautz, S.; Wagner, M.H. Comparison of respiratory event detection by a polyvinylidene fluoride film airflow sensor and a pneumotachograph in sleep apnea patients. Chest 2005, 128, 1331–1338. [Google Scholar] [CrossRef] [PubMed]
- Arnin, J.; Anopas, D.; Horapong, M.; Triponyuwasi, P.; Yamsa-Ard, T.; Iampetch, S.; Wongsawat, Y. Wireless-based portable EEG-EOG monitoring for real time drowsiness detection. In Proceedings of the Annual International Conference of the IEEE Engineering in Medicine and Biology Society, EMBS, Osaka, Japan, 3–7 July 2013; pp. 4977–4980. [Google Scholar]
- Fraile, L.P.; Tsampas, S.; Mylonas, G.; Amaxilatis, D. A Comparative Study of LoRa and IEEE 802.15.4-Based IoT Deployments Inside School Buildings. IEEE Access 2020, 8, 160957–160981. [Google Scholar] [CrossRef]
- Haque, K.F.; Abdelgawad, A.; Yelamarthi, K. Comprehensive Performance Analysis of Zigbee Communication: An Experimental Approach with XBee S2C Module. Sensors 2022, 22, 3245. [Google Scholar] [CrossRef] [PubMed]
- Shikida, M.; Naito, J.; Yokota, T.; Kawabe, T.; Hayashi, Y.; Sato, K. A catheter-type flow sensor for measurement of aspirated- and inspired-air characteristics in the bronchial region. J. Micromech. Microeng. 2009, 19, 105027. [Google Scholar] [CrossRef]
- Xu, S.; Liu, Y.; Lee, H.; Li, W. Neural interfaces: Bridging the brain to the world beyond healthcare. Exploration 2024, 4. [Google Scholar] [CrossRef]
Power supply | Four AA batteries (1.5 V) |
Uptime | About 2 days (50 h) |
Sensing pressure | ±50 Pa |
Sensor response frequency | Around 3 Hz |
Sampling Rate | 20 Hz |
Data output | Wireless/Real-time |
Module | Standard | Current Consumption | Remarks |
---|---|---|---|
XBee S2 | ZigBee | Transmit: 33 mA Receive: 28 mA | Java SDK is available. |
TWE-Lite (TWE-001L) | IEEE802.15.4 | Transmit: 17 mA Receive: 15 mA | Java SDK is not available. |
XBee S6 (Wi-Fi) | Wi-Fi | Transmit: 309 mA Receive: 100 mA | |
ESP8266 (ESP-WROOM-02) | Wi-Fi | Average 80 mA | |
ESP32 (ESP-WROOM-32) | Wi-Fi + Bluetooth LE | Wi-Fi transmission 160–260 mA | |
nRF51822 | Bluetooth LE | Transmit: 16 mA | Requires Windows 8.1 or greater |
RN4020 | Bluetooth LE | Transmit: 16 mA | Requires Windows 8.1 or greater |
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content. |
© 2025 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (https://creativecommons.org/licenses/by/4.0/).
Share and Cite
Kamogashira, T.; Yamasoba, T.; Kikuta, S.; Kondo, K. A Sleep Sensor Made with Electret Condenser Microphones. Clocks & Sleep 2025, 7, 28. https://doi.org/10.3390/clockssleep7020028
Kamogashira T, Yamasoba T, Kikuta S, Kondo K. A Sleep Sensor Made with Electret Condenser Microphones. Clocks & Sleep. 2025; 7(2):28. https://doi.org/10.3390/clockssleep7020028
Chicago/Turabian StyleKamogashira, Teru, Tatsuya Yamasoba, Shu Kikuta, and Kenji Kondo. 2025. "A Sleep Sensor Made with Electret Condenser Microphones" Clocks & Sleep 7, no. 2: 28. https://doi.org/10.3390/clockssleep7020028
APA StyleKamogashira, T., Yamasoba, T., Kikuta, S., & Kondo, K. (2025). A Sleep Sensor Made with Electret Condenser Microphones. Clocks & Sleep, 7(2), 28. https://doi.org/10.3390/clockssleep7020028