]> 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 e6f097c4cc0b44691be46257b27bb253c183acb5..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;
@@ -120,7 +129,7 @@ implementation {
     else {
       noise_val = (double)sim_noise_generate(node_id, quotient);
     }
-    dbg("CpmModelC", "OUT: noise_hash_generation()\n");
+    dbg("CpmModelC,Tal", "%s: OUT: noise_hash_generation(): %lf\n", sim_time_string(), noise_val);
 
     return noise_val;
   }
@@ -131,10 +140,51 @@ 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;
@@ -151,33 +201,38 @@ implementation {
   }
   
   command bool Model.clearChannel() {
-    dbg("CpmModelC", "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 is %lf, PRR is %lf\n", SNR, prr_hat);
+    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
@@ -227,6 +282,9 @@ 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;
@@ -250,10 +308,16 @@ implementation {
     }
     dbg("CpmModelC,SNRLoss", "Packet from %i to %i\n", (int)mine->source, (int)sim_node());
     if (!checkReceive(mine)) {
-      dbg("CpmModelC,SNRLoss", " - lost packet from 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) {
+      // 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) {
@@ -265,21 +329,36 @@ implementation {
       // If we scheduled an ack, receiving = 0 when it completes
       if (mine->ack && signal Model.shouldAck(mine->msg)) {
         dbg_clear("CpmModelC", " scheduling ack.\n");
-       sim_gain_schedule_ack(mine->source, sim_time() + 1); 
+       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("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();
@@ -288,10 +367,15 @@ implementation {
     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
@@ -309,6 +393,10 @@ implementation {
       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;
     }
@@ -329,29 +417,42 @@ implementation {
 
   }
   
-  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("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) {
+  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;
+    transmissionEndTime = endTime;
     dbg("CpmModelC", "Node %i transmitting to %i, finishes at %llu.\n", sim_node(), dest, endTime);
 
     while (neighborEntry != NULL) {
       int other = neighborEntry->mote;
-      sim_gain_put(other, msg, endTime, ack && (other == dest), power + sim_gain_value(sim_node(), other));
+      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) {}
 
@@ -370,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);
+ }
 }