]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/lib/tossim/CpmModelC.nc
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / tos / lib / tossim / CpmModelC.nc
index c0a0db0596b66d209ad6a9a3523de788f88d708d..4a84a278eed37e3a33d0358c9fda62a3131777db 100644 (file)
 /**
  *
  * CPM (closest-pattern matching) is a wireless noise simulation model
- * based on statistical extraction from empirical noise data.
- * This model provides far more precise
- * software simulation environment by exploiting time-correlated noise
- * characteristic and shadowing effect as well as path-loss model. For
- * details, please refer to the paper
+ * based on statistical extraction from empirical noise data.  This
+ * model provides far more precise software simulation environment by
+ * exploiting time-correlated noise characteristics. For details,
+ * please refer to the paper
  *
  * "Improving Wireless Simulation through Noise Modeling." HyungJune
  * Lee and Philip Levis, IPSN 2007. You can find a copy at
@@ -51,6 +50,8 @@ implementation {
   message_t* outgoing; // If I'm sending, this is my outgoing packet
   bool requestAck;
   bool receiving = 0;  // Whether or not I think I'm receiving a packet
+  bool transmitting = 0; // Whether or not I think I'm tranmitting a packet
+  sim_time_t transmissionEndTime; // to check pending transmission
   struct receive_message;
   typedef struct receive_message receive_message_t;
 
@@ -59,6 +60,8 @@ implementation {
     sim_time_t start;
     sim_time_t end;
     double power;
+    double reversePower;
+    int8_t strength;
     bool lost;
     bool ack;
     message_t* msg;
@@ -68,8 +71,14 @@ implementation {
   receive_message_t* outstandingReceptionHead = NULL;
 
   receive_message_t* allocate_receive_message();
+  void free_receive_message(receive_message_t* msg);
   sim_event_t* allocate_receive_event(sim_time_t t, receive_message_t* m);
 
+  bool shouldReceive(double SNR);
+  bool checkReceive(receive_message_t* msg);
+  double packetNoise(receive_message_t* msg);
+  double checkPrr(receive_message_t* msg);
+  
   double timeInMs()   {
     sim_time_t ftime = sim_time();
     int hours, minutes, seconds;
@@ -113,14 +122,14 @@ implementation {
     double noise_val;
     uint16_t node_id = sim_node();
 
-    dbg("SNIST_1", "IN: noise_hash_generation()\n");
+    dbg("CpmModelC", "IN: noise_hash_generation()\n");
     if (5 <= remain && remain < 10) {
        noise_val = (double)sim_noise_generate(node_id, quotient+1);
       }
     else {
       noise_val = (double)sim_noise_generate(node_id, quotient);
     }
-    dbg("SNIST_1", "OUT: noise_hash_generation()\n");
+    dbg("CpmModelC,Tal", "%s: OUT: noise_hash_generation(): %lf\n", sim_time_string(), noise_val);
 
     return noise_val;
   }
@@ -131,53 +140,99 @@ implementation {
     return (signalStr - noise);
   }
   
+  double arr_estimate_from_snr(double SNR) {
+    double beta1 = 0.9794;
+    double beta2 = 2.3851;
+    double X = SNR-beta2;
+    double PSE = 0.5*erfc(beta1*X/sqrt(2));
+    double prr_hat = pow(1-PSE, 23*2);
+    dbg("CpmModelC,SNRLoss", "SNR is %lf, ARR is %lf\n", SNR, prr_hat);
+    if (prr_hat > 1)
+      prr_hat = 1.1;
+    else if (prr_hat < 0)
+      prr_hat = -0.1;
+       
+    return prr_hat;
+  }
+  
+  int shouldAckReceive(double snr) {
+    double prr = arr_estimate_from_snr(snr);
+    double coin = RandomUniform();
+    if ( (prr >= 0) && (prr <= 1) ) {
+      if (coin < prr)
+       prr = 1.0;
+      else
+       prr = 0.0;
+    }
+    return (int)prr;
+  }
+  
   void sim_gain_ack_handle(sim_event_t* evt)  {
-    if (outgoing != NULL && requestAck && sim_mote_is_on(sim_node())) {
-      signal Model.acked(outgoing);
+    // Four conditions must hold for an ack to be issued:
+    // 1) Transmitter is still sending a packet (i.e., not cancelled)
+    // 2) The packet requested an acknowledgment
+    // 3) The transmitter is on
+    // 4) The packet passes the SNR/ARR curve
+    if (requestAck && // This 
+       outgoing != NULL &&
+       sim_mote_is_on(sim_node())) {
+      receive_message_t* rcv = (receive_message_t*)evt->data;
+      double power = rcv->reversePower;
+      double noise = packetNoise(rcv);
+      double snr = power - noise;
+      if (shouldAckReceive(snr)) {
+       signal Model.acked(outgoing);
+      }
     }
+    free_receive_message((receive_message_t*)evt->data);
   }
 
   sim_event_t receiveEvent;
   // This clear threshold comes from the CC2420 data sheet
-  double clearThreshold = -95.0;
+  double clearThreshold = -72.0;
   bool collision = FALSE;
   message_t* incoming = NULL;
   int incomingSource;
 
   command void Model.setClearValue(double value) {
     clearThreshold = value;
-    dbg("SNIST_1", "Setting clear threshold to %f\n", clearThreshold);
+    dbg("CpmModelC", "Setting clear threshold to %f\n", clearThreshold);
        
   }
   
   command bool Model.clearChannel() {
-    dbg("SNIST_1", "Checking clear channel @ %s: %f <= %f \n", sim_time_string(), (double)noise_hash_generation(), clearThreshold);
-    return noise_hash_generation() < clearThreshold;
+    dbg("CpmModelC", "Checking clear channel @ %s: %f <= %f \n", sim_time_string(), (double)packetNoise(NULL), clearThreshold);
+    return packetNoise(NULL) < clearThreshold;
   }
 
-  void sim_gain_schedule_ack(int source, sim_time_t t) {
+  void sim_gain_schedule_ack(int source, sim_time_t t, receive_message_t* r) {
     sim_event_t* ackEvent = (sim_event_t*)malloc(sizeof(sim_event_t));
+    
     ackEvent->mote = source;
     ackEvent->force = 1;
     ackEvent->cancelled = 0;
     ackEvent->time = t;
     ackEvent->handle = sim_gain_ack_handle;
     ackEvent->cleanup = sim_queue_cleanup_event;
+    ackEvent->data = r;
+    
     sim_queue_insert(ackEvent);
   }
 
   double prr_estimate_from_snr(double SNR) {
-    double beta1 = 1.3687;
-    double beta2 = 0.9187;
-    double SNR_lin = pow(10.0, SNR/10.0);
-    double X = fabs(SNR_lin-beta2);
-    double PSE = 0.5*erfc(beta1*sqrt(X/2));
+    // Based on CC2420 measurement by Kannan.
+    // The updated function below fixes the problem of non-zero PRR
+    // at very low SNR. With this function PRR is 0 for SNR <= 3.
+    double beta1 = 0.9794;
+    double beta2 = 2.3851;
+    double X = SNR-beta2;
+    double PSE = 0.5*erfc(beta1*X/sqrt(2));
     double prr_hat = pow(1-PSE, 23*2);
-
+    dbg("CpmModelC,SNR", "SNR is %lf, PRR is %lf\n", SNR, prr_hat);
     if (prr_hat > 1)
-      prr_hat = 1;
+      prr_hat = 1.1;
     else if (prr_hat < 0)
-      prr_hat = 0;
+      prr_hat = -0.1;
        
     return prr_hat;
   }
@@ -185,7 +240,7 @@ implementation {
   bool shouldReceive(double SNR) {
     double prr = prr_estimate_from_snr(SNR);
     double coin = RandomUniform();
-    if ( (prr != 0) && (prr != 1) ) {
+    if ( (prr >= 0) && (prr <= 1) ) {
       if (coin < prr)
        prr = 1.0;
       else
@@ -202,9 +257,10 @@ implementation {
       if (list != msg) {
        noise += pow(10.0, list->power / 10.0);
       }
+      list = list->next;
     }
     noise = 10.0 * log(noise) / log(10.0);
-    return shouldReceive(msg->power / noise);
+    return shouldReceive(msg->power - noise);
   }
   
   double packetNoise(receive_message_t* msg) {
@@ -215,6 +271,7 @@ implementation {
       if (list != msg) {
        noise += pow(10.0, list->power / 10.0);
       }
+      list = list->next;
     }
     noise = 10.0 * log(noise) / log(10.0);
     return noise;
@@ -225,12 +282,15 @@ implementation {
   }
   
 
+  /* Handle a packet reception. If the packet is being acked,
+     pass the corresponding receive_message_t* to the ack handler,
+     otherwise free it. */
   void sim_gain_receive_handle(sim_event_t* evt) {
     receive_message_t* mine = (receive_message_t*)evt->data;
     receive_message_t* predecessor = NULL;
     receive_message_t* list = outstandingReceptionHead;
 
-    dbg("SNIST_1", "Handling reception event @ %s.\n", sim_time_string());
+    dbg("CpmModelC", "Handling reception event @ %s.\n", sim_time_string());
     while (list != NULL) {
       if (list->next == mine) {
        predecessor = list;
@@ -244,99 +304,155 @@ implementation {
       outstandingReceptionHead = mine->next;
     }
     else {
-      dbgerror("SNIST", "Incoming packet list structure is corrupted: entry is not the head and no entry points to it.\n");
+      dbgerror("CpmModelC", "Incoming packet list structure is corrupted: entry is not the head and no entry points to it.\n");
     }
-    
+    dbg("CpmModelC,SNRLoss", "Packet from %i to %i\n", (int)mine->source, (int)sim_node());
     if (!checkReceive(mine)) {
-      dbg("SNIST", "Lost packet as SNR was too low.\n");
+      dbg("CpmModelC,SNRLoss", " - lost packet from %i as SNR was too low.\n", (int)mine->source);
       mine->lost = 1;
     }
-    
     if (!mine->lost) {
-      dbg_clear("SNIST", "  -signaling reception, ");
+      // Copy this receiver's packet signal strength to the metadata region
+      // of the packet. Note that this packet is actually shared across all
+      // receivers: a higher layer performs the copy.
+      tossim_metadata_t* meta = (tossim_metadata_t*)(&mine->msg->metadata);
+      meta->strength = mine->strength;
+      
+      dbg_clear("CpmModelC,SNRLoss", "  -signaling reception\n");
       signal Model.receive(mine->msg);
       if (mine->ack) {
-        dbg_clear("SNIST", " acknowledgment requested, ");
+        dbg_clear("CpmModelC", " acknowledgment requested, ");
       }
       else {
-        dbg_clear("SNIST", " no acknowledgment requested.\n");
+        dbg_clear("CpmModelC", " no acknowledgment requested.\n");
       }
       // If we scheduled an ack, receiving = 0 when it completes
       if (mine->ack && signal Model.shouldAck(mine->msg)) {
-        dbg_clear("SNIST", " scheduling ack.\n");
-       sim_gain_schedule_ack(mine->source, sim_time() + 1); 
+        dbg_clear("CpmModelC", " scheduling ack.\n");
+       sim_gain_schedule_ack(mine->source, sim_time() + 1, mine);
+      }
+      else { // Otherwise free the receive_message_t*
+       free_receive_message(mine);
       }
       // We're searching for new packets again
       receiving = 0;
     } // If the packet was lost, then we're searching for new packets again
     else {
+      if (RandomUniform() < 0.001) {
+       dbg("CpmModelC,SNRLoss", "Packet was technically lost, but TOSSIM introduces an ack false positive rate.\n");
+       if (mine->ack && signal Model.shouldAck(mine->msg)) {
+         dbg_clear("CpmModelC", " scheduling ack.\n");
+         sim_gain_schedule_ack(mine->source, sim_time() + 1, mine);
+       }
+       else { // Otherwise free the receive_message_t*
+         free_receive_message(mine);
+       }
+      }
+      else {
+       free_receive_message(mine);
+      }
       receiving = 0;
-      dbg_clear("SNIST", "  -packet was lost.\n");
+      dbg_clear("CpmModelC,SNRLoss", "  -packet was lost.\n");
     }
-    free(mine);
   }
-  
+   
   // Create a record that a node is receiving a packet,
   // enqueue a receive event to figure out what happens.
-  void enqueue_receive_event(int source, sim_time_t endTime, message_t* msg, bool receive, double power) {
+  void enqueue_receive_event(int source, sim_time_t endTime, message_t* msg, bool receive, double power, double reversePower) {
     sim_event_t* evt;
+    receive_message_t* list;
     receive_message_t* rcv = allocate_receive_message();
     double noiseStr = packetNoise(rcv);
     rcv->source = source;
     rcv->start = sim_time();
     rcv->end = endTime;
     rcv->power = power;
+    rcv->reversePower = reversePower;
+    // The strength of a packet is the sum of the signal and noise. In most cases, this means
+    // the signal. By sampling this here, it assumes that the packet RSSI is sampled at
+    // the beginning of the packet. This is true for the CC2420, but is not true for all
+    // radios. But generalizing seems like complexity for minimal gain at this point.
+    rcv->strength = (int8_t)(floor(10.0 * log(pow(10.0, power/10.0) + pow(10.0, noiseStr/10.0)) / log(10.0)));
     rcv->msg = msg;
     rcv->lost = 0;
     rcv->ack = receive;
-    
     // If I'm off, I never receive the packet, but I need to keep track of
     // it in case I turn on and someone else starts sending me a weaker
     // packet. So I don't set receiving to 1, but I keep track of
     // the signal strength.
 
     if (!sim_mote_is_on(sim_node())) { 
-      dbg("SNIST", "Lost packet from %i due to %i being off\n", source, sim_node());
+      dbg("CpmModelC", "Lost packet from %i due to %i being off\n", source, sim_node());
       rcv->lost = 1;
     }
     else if (!shouldReceive(power - noiseStr)) {
+      dbg("CpmModelC,SNRLoss", "Lost packet from %i to %i due to SNR being too low (%i)\n", source, sim_node(), (int)(power - noiseStr));
       rcv->lost = 1;
     }
     else if (receiving) {
+      dbg("CpmModelC,SNRLoss", "Lost packet from %i due to %i being mid-reception\n", source, sim_node());
+      rcv->lost = 1;
+    }
+    else if (transmitting && (rcv->start < transmissionEndTime) && (transmissionEndTime <= rcv->end)) {
+      dbg("CpmModelC,SNRLoss", "Lost packet from %i due to %i being mid-transmission, transmissionEndTime %llu\n", source, sim_node(), transmissionEndTime);
       rcv->lost = 1;
     }
     else {
       receiving = 1;
-      rcv->next = outstandingReceptionHead;
-      outstandingReceptionHead = rcv;
-      evt = allocate_receive_event(endTime, rcv);
-      sim_queue_insert(evt);
     }
+
+    list = outstandingReceptionHead;
+    while (list != NULL) {
+      if (!shouldReceive(list->power - rcv->power)) {
+       dbg("Gain,SNRLoss", "Going to lose packet from %i with signal %lf as am receiving a packet from %i with signal %lf\n", list->source, list->power, source, rcv->power);
+       list->lost = 1;
+      }
+      list = list->next;
+    }
+    
+    rcv->next = outstandingReceptionHead;
+    outstandingReceptionHead = rcv;
+    evt = allocate_receive_event(endTime, rcv);
+    sim_queue_insert(evt);
+
   }
   
-  void sim_gain_put(int dest, message_t* msg, sim_time_t endTime, bool receive, double power) {
+  void sim_gain_put(int dest, message_t* msg, sim_time_t endTime, bool receive, double power, double reversePower) {
     int prevNode = sim_node();
-    dbg("SNIST_1", "Enqueing reception event for %i at %llu.\n", dest, endTime);
+    dbg("CpmModelC", "Enqueing reception event for %i at %llu with power %lf.\n", dest, endTime, power);
     sim_set_node(dest);
-    enqueue_receive_event(prevNode, endTime, msg, receive, power);
+    enqueue_receive_event(prevNode, endTime, msg, receive, power, reversePower);
     sim_set_node(prevNode);
   }
 
-  command void Model.putOnAirTo(int dest, message_t* msg, bool ack, sim_time_t endTime, double power) {
-    gain_entry_t* link = sim_gain_first(sim_node());
+  command void Model.putOnAirTo(int dest, message_t* msg, bool ack, sim_time_t endTime, double power, double reversePower) {
+    receive_message_t* list;
+    gain_entry_t* neighborEntry = sim_gain_first(sim_node());
     requestAck = ack;
     outgoing = msg;
-    dbg("SNIST", "Node %i transmitting to %i, finishes at %llu.\n", sim_node(), dest, endTime);
+    transmissionEndTime = endTime;
+    dbg("CpmModelC", "Node %i transmitting to %i, finishes at %llu.\n", sim_node(), dest, endTime);
 
-    while (link != NULL) {
-      int other = link->mote;
-      sim_gain_put(other, msg, endTime, ack && (other == dest), power);
-      link = sim_gain_next(link);
+    while (neighborEntry != NULL) {
+      int other = neighborEntry->mote;
+      sim_gain_put(other, msg, endTime, ack, power + sim_gain_value(sim_node(), other), reversePower + sim_gain_value(other, sim_node()));
+      neighborEntry = sim_gain_next(neighborEntry);
+    }
+
+    list = outstandingReceptionHead;
+    while (list != NULL) {    
+      list->lost = 1;
+      dbg("CpmModelC,SNRLoss", "Lost packet from %i because %i has outstanding reception, startTime %llu endTime %llu\n", list->source, sim_node(), list->start, list->end);
+      list = list->next;
     }
   }
     
 
-  
+  command void Model.setPendingTransmission() {
+    transmitting = TRUE;
+    dbg("CpmModelC", "setPendingTransmission: transmitting %i @ %s\n", transmitting, sim_time_string());
+  }
+
   
  default event void Model.receive(message_t* msg) {}
 
@@ -355,5 +471,8 @@ implementation {
  receive_message_t* allocate_receive_message() {
    return (receive_message_t*)malloc(sizeof(receive_message_t));
  }
+
+ void free_receive_message(receive_message_t* msg) {
+   free(msg);
+ }
 }