Input: Difference between revisions

From Control Systems Technology Group
Jump to navigation Jump to search
No edit summary
No edit summary
Line 99: Line 99:
Gathering Real-Time data is rather easy using the Arduino. When connected with a computer through USB, an Arduino can print values directly to a Serial Monitor. This Serial Monitor contains the information you want, and this information can be copied into a .txt-file. There is also an external tool for Microsoft Excel, to automatically gather data from the Serial Monitor. This tool is called PLX-DAQ, and prints the Serial data directly into an Excel sheet.
Gathering Real-Time data is rather easy using the Arduino. When connected with a computer through USB, an Arduino can print values directly to a Serial Monitor. This Serial Monitor contains the information you want, and this information can be copied into a .txt-file. There is also an external tool for Microsoft Excel, to automatically gather data from the Serial Monitor. This tool is called PLX-DAQ, and prints the Serial data directly into an Excel sheet.


The Arduino needs some code to measure the input of the sound sensor, and print the values to the Serial Monitor. A preview of this code can be seen below. This code also includes peak detection.
The Arduino needs some code to measure the input of the sound sensor, and print the values to the Serial Monitor. A preview of this code can be seen below. This code also includes peak detection. When a peak is detected, it can be printed to the Serial Monitor, but it will also turn on a light if the peak is within the given wake up time. Also, if the time exceeds the maximum of the alarm, the light will always turn on at the end. The light represents the output of this code.


<pre>
<pre>
/*---------- Pin initialization ----------*/
  const int inputPin = A0;                                // Input from the sensor
  const int inputPin = A0;                                // Input from the sensor
   
  const int outputPin = 13;                               // Pin for the output light
int timer = 0;
 
int oldValueTimer;                                     // Integer to remember old value for printing, if that turns out to be a peak
  /*---------- Editable values ----------*/  
const int maxArraySize = 100;                          // Max array size i.e. how many peaks are stored. This reduces memory needed
int peakValues[maxArraySize];                          // Array to store the peak values
int timeArray[maxArraySize];                            // Array to store the time the peak value is reached
  int arrayCounter = 0;                                  // Place in array to not store values that are exceeded in the next iteration
int measurement;                                        // Sensor value
  int counter = 5;                                        // Number of averages taken. Average is taken to filter out small noise  
  int counter = 5;                                        // Number of averages taken. Average is taken to filter out small noise  
  int currentValue = 0;                                   // Current value
  int maxWakeUpTime = 60;                                 // Alarm will wake you up no later than maxWakeUpTime
  int oldValue = 0;                                       // Previous value
  int wakeUpRange = 15;                                   // Time allowed before maxWakeUpTime
  bool printPeaks = false;                                // Testing feature; if true, it will print the peak values, otherwise, it will just print the measured values
  bool printPeaks = false;                                // Testing feature; if true, it will print the peak values, otherwise, it will just print the measured values
/*---------- Variables used by the program ----------*/
int timer = 0;                                          // Clock
int oldValueTimer;                                      // Integer to remember old value for printing, if that turns out to be a peak
float measurement;                                      // Sensor value
float currentValue = 0;                                // Current value
float oldValue;                                        // Previous value
  bool oldPlus = false;                                  // Boolean to save if graph is increasing or decreasing  
  bool oldPlus = false;                                  // Boolean to save if graph is increasing or decreasing  
                                                         //                            true          false
                                                         //                            true          false
void setup() {
void setup() {
  Serial.begin(9600);                                    // Set up output window
  Serial.begin(9600);                                    // Set up output window
  Serial.println("CLEARDATA");                            // Initialization of the Excel Table
  Serial.println("CLEARDATA");                            // Initialization of the Excel Table, needed for the PLX-DAQ
  Serial.println("LABEL,Time,Peak Value");                // Names of the rows, LABEL is for the PLX-DAQ
  Serial.println("LABEL,Time,Peak Value");                // Names of the rows, LABEL is for the PLX-DAQ
   
   
  pinMode(A0, INPUT);                                     // Sensor input pin
  pinMode(inputPin, INPUT);                               // Sensor input pin
pinMode(outputPin, OUTPUT);                            // Light output pin
digitalWrite(outputPin, LOW);                          // Light starts off being out
}
}


void loop() {
void loop() {
   for (int i = 0; i <= counter; i++){                   // Loop to take average value
   for (int i = 0; i < counter; i++){                     // Loop to take average value
     delay(1000);                                        // Progress a second
     delay(1000);                                        // Progress a second
     timer++;
     timer++;
     measurement = analogRead(inputPin);
     measurement = analogRead(inputPin);
    currentValue = currentValue + measurement;
      
      
     if (printPeaks == false){                            // Prints out the measurements to the Serial monitor
     if (printPeaks == false){                            // Prints out the measurements to the Serial monitor
Line 136: Line 142:
       Serial.print(",");
       Serial.print(",");
       Serial.println(measurement);
       Serial.println(measurement);
     }
     }    
                       
    currentValue = currentValue + measurement;         
   }
   }
     currentValue = currentValue / counter;              // currentValue is now the average
     currentValue = currentValue / counter;              // currentValue is now the average


     if (currentValue < oldValue && oldPlus == true){    // If the graph is just behind the peak (function is decreasing, but the last measurement was increasing)
     if (currentValue < oldValue && oldPlus == true){    // If the graph is just behind the peak (function is decreasing, but the last measurement was increasing) --> peak is found
       oldPlus = false;
       oldPlus = false;
      if (oldValueTimer >= maxWakeUpTime - wakeUpRange){ // If the peak is within waking up range
          digitalWrite(outputPin, HIGH);
      }
      
      
       if (printPeaks == true){                          // Print out found peaks to the Serial monitor
       if (printPeaks == true){                          // Print out found peaks to the Serial monitor
Line 150: Line 158:
         Serial.println(oldValue);
         Serial.println(oldValue);
       }
       }
      arrayCounter++;
     }
     }
     if (currentValue > oldValue){                        // If the value is higher than last time, store it in the array. Overwrites the last value if function is still increasing
   
     if (currentValue > oldValue){                        // Change oldPlus to true, indicating the function is increasing
       oldPlus = true;
       oldPlus = true;
      peakValues[arrayCounter] = currentValue;
      timeArray[arrayCounter] = timer;
     }
     }
    if (timer >= maxWakeUpTime){
      digitalWrite(outputPin, HIGH);                    // Turn on the light hard coded if time is at the end of your alarm
    }
   
     oldValue = currentValue;                            // Update old value and reset the current value for the next loop
     oldValue = currentValue;                            // Update old value and reset the current value for the next loop
     oldValueTimer = timer;                                   
     oldValueTimer = timer;                                   

Revision as of 15:12, 10 March 2016

Back to main page: PRE2015_3_Groep4

To the code: Code

To the output: Output

Brightness

The brightness is measured by a sensor inside the bedroom. In the simulation this will be represented by an integer light strength. The value is determined by superposing the sunlight that falls through the blinds and the light generated by our wake-up light. It is assumed there are no other light sources in the bedroom. It is also assumed that the window is always vertical and perpendicular to the suns rays.

The intensity of the sunlight is calculated based on the date and time. It is assumed the sky is clear, and there are no obstacles above the horizon.

The light coming from the wake-up light is regulated by the controller, giving an output strength, as a fraction of the full output strength( 250 lx [1]). These two values are then added to give the input brightness.

Temperature

The room is to be modeled as a 3x4x2.5m box filled with air, surrounded by outside air on one side and the house all other sides. This proved to be more difficult than thought, therefor we will start with a simpler, linear model for temperature change:

[math]\displaystyle{ dT = k*(T - T_\infty) }[/math]

With k a heat transition constant (estimated at k = -0.03), T the room temperature and T the temperature the room assumes when not regulated, 12°C. When the heating is on an additional term is introduced:

[math]\displaystyle{ dT_{heating} = h*(T_r - T) }[/math]

With h a convection constant (estimated at h = 0.02) and Tr the radiator temperature at 50°C

Sleep model

The Sleep Cycle App provides graphs to the user that show his measured sleep behavior during that night. Here's an example:

Sleepcycle irregular sleep.png

To model this pattern, we assumed that if the graph is split up in pieces with the peaks and valleys as cutting points, each piece will be sinusoidal with a random period and amplitude. Furthermore, we made the assumption that the period is normally distributed with mean 90 minutes or 5400 seconds (mean duration of one sleep cycle) and standard deviation 30 minutes or 1800 seconds. At first, we assumed that the amplitude is uniformly distributed, but people sleep deeper just after going to sleep and lighter just before waking up, so we had to come up with our own probability distribution. We decided to use the following probability density function:

[math]\displaystyle{ f(x) = rc \left( x - \frac{1}{2} \right) + 1 \qquad 0 \le x \le 1 \quad \and \quad -2 \le rc \le 2 }[/math]

[math]\displaystyle{ P(0 \le X \le x) = \int\limits_{0}^{x} f(x)dx = \frac{1}{2} rc \left( x^2 + \left( \frac{2}{rc} - 1 \right) x \right) }[/math]

So X is a fraction and the probability of X = x depends on the coefficient rc. How closer rc is to 2, how closer E[X] is to 1 and how closer rc is to -2, how closer E[X] is to 0. To get a random value for x, the second function needs to be rewritten, which gives:

[math]\displaystyle{ x = \frac{1}{2} - \frac{1}{rc} \pm \sqrt{ \frac{2}{rc} P(0 \le X \le x) + \frac{1}{rc^2} - \frac{1}{rc} + \frac{1}{4} } }[/math]

0 ≤ x ≤ 1, so for positive rc the ± becomes a + and for negative rc a -. If rc = 0, then this is a uniform distribution. If a value for P(0 ≤ X ≤ x) is taken from a uniform distribution with range [0,1], then a random value for x can be calculated. To model de transition from generally deep sleep to light sleep, the value of rc must decrease from 2 to -2 over time. For this we used the following function:

[math]\displaystyle{ rc = \frac{4}{1 + e^{\frac{t - 2,5T_{gem}}{20000}}} - 2 }[/math]

t is the time elapsed since going to bed and is represented by the number of ticks and Tgem is the mean duration of one sleep cycle and is in this case 90 minutes. A person needs an average of five complete sleep cycles for a good night's rest, so the point of inflection is 2.5*Tgem.

Script

globals [y
         Tgem
         start
         T
         p
         rc
         x
         R
         time
         stage
         test]

to Setup
  clear-all
  set y 100
  set Tgem (90 * 60)
  reset-ticks
end

to Go
  foreach [1 2] [
    set start y
    set T -1
    while [T < 0] [set T (random-normal Tgem 1800)]
    set p (random-float 1.0)
    set rc (4 / (1 + exp((ticks - (2.5 * Tgem)) / 20000)) - 2)
    ifelse rc > 0
      [set x (0.5 - (1 / rc) + sqrt((2.0 / rc) * p + (rc ^ -2) - (rc ^ -1) + 0.25))]
      [set x (0.5 - (1 / rc) - sqrt((2.0 / rc) * p + (rc ^ -2) - (rc ^ -1) + 0.25))]
    ifelse ? = 1
      [set R (x * start / 2)]
      [set R ((x - 1) * (100 - start) / 2)]
    set time (n-values (T / 2) [?])
    foreach time [
      set y (R * (cos (360 * ? / T)) + start - R)
      set stage ((y - (y mod 25)) / 25 - 3)
      set test (1 / (1 + exp(ticks)))
      tick
    ]
  ]
end

Result

Running the script gives these two graphs:

SlaapGrafieken.png

The first graph shows how deep you sleep on a percentage scale and the second graph translates that to the sleep stage you're in. Stage 0 means being awake and corresponds with 100%-75% on the first graph. Afterwards come stages -1, -2 and -3 which correspond with 75%-50%, 50%-25% and 25%-0% respectively. They are actually stages 1, 2 and 3, the three stages of the sleep cycle. Stage 1 can also correspond with REM sleep, because they both behave the same based on the sound you make during those stages.

User Settings

Gathering Real-Time Data

Gathering Real-Time data is rather easy using the Arduino. When connected with a computer through USB, an Arduino can print values directly to a Serial Monitor. This Serial Monitor contains the information you want, and this information can be copied into a .txt-file. There is also an external tool for Microsoft Excel, to automatically gather data from the Serial Monitor. This tool is called PLX-DAQ, and prints the Serial data directly into an Excel sheet.

The Arduino needs some code to measure the input of the sound sensor, and print the values to the Serial Monitor. A preview of this code can be seen below. This code also includes peak detection. When a peak is detected, it can be printed to the Serial Monitor, but it will also turn on a light if the peak is within the given wake up time. Also, if the time exceeds the maximum of the alarm, the light will always turn on at the end. The light represents the output of this code.

 /*---------- Pin initialization ----------*/ 
 const int inputPin = A0;                                // Input from the sensor
 const int outputPin = 13;                               // Pin for the output light

 /*---------- Editable values ----------*/ 
 int counter = 5;                                        // Number of averages taken. Average is taken to filter out small noise 
 int maxWakeUpTime = 60;                                 // Alarm will wake you up no later than maxWakeUpTime
 int wakeUpRange = 15;                                   // Time allowed before maxWakeUpTime
 bool printPeaks = false;                                // Testing feature; if true, it will print the peak values, otherwise, it will just print the measured values

 /*---------- Variables used by the program ----------*/ 
 int timer = 0;                                          // Clock 
 int oldValueTimer;                                      // Integer to remember old value for printing, if that turns out to be a peak
 float measurement;                                      // Sensor value
 float currentValue = 0;                                 // Current value
 float oldValue;                                         // Previous value
 bool oldPlus = false;                                   // Boolean to save if graph is increasing or decreasing 
                                                         //                             true          false
void setup() {
 Serial.begin(9600);                                     // Set up output window
 Serial.println("CLEARDATA");                            // Initialization of the Excel Table, needed for the PLX-DAQ
 Serial.println("LABEL,Time,Peak Value");                // Names of the rows, LABEL is for the PLX-DAQ
 
 pinMode(inputPin, INPUT);                               // Sensor input pin
 pinMode(outputPin, OUTPUT);                             // Light output pin
 
 digitalWrite(outputPin, LOW);                           // Light starts off being out
}

void loop() {
  for (int i = 0; i < counter; i++){                     // Loop to take average value
    delay(1000);                                         // Progress a second
    timer++;
    measurement = analogRead(inputPin);
    currentValue = currentValue + measurement; 
    
    if (printPeaks == false){                            // Prints out the measurements to the Serial monitor
      Serial.print(timer);
      Serial.print(",");
      Serial.println(measurement);
    }      
  }
    currentValue = currentValue / counter;               // currentValue is now the average

    if (currentValue < oldValue && oldPlus == true){     // If the graph is just behind the peak (function is decreasing, but the last measurement was increasing) --> peak is found
      oldPlus = false;

      if (oldValueTimer >= maxWakeUpTime - wakeUpRange){ // If the peak is within waking up range
          digitalWrite(outputPin, HIGH);
      }
     
      if (printPeaks == true){                           // Print out found peaks to the Serial monitor
        Serial.print(oldValueTimer);
        Serial.print(",");
        Serial.println(oldValue);
      }
    }
    
    if (currentValue > oldValue){                        // Change oldPlus to true, indicating the function is increasing
      oldPlus = true;
    }

    if (timer >= maxWakeUpTime){
      digitalWrite(outputPin, HIGH);                     // Turn on the light hard coded if time is at the end of your alarm
    }
    
    oldValue = currentValue;                             // Update old value and reset the current value for the next loop
    oldValueTimer = timer;                                   
    currentValue = 0;
}

References

  1. Philips.com, Wake-up Light HF3470/60 | Philips, consulted February 2016, http://www.usa.philips.com/c-p/HF3470_60/wake-up-light/