/**
*
* 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
sim_time_t start;
sim_time_t end;
double power;
+ double reversePower;
+ int8_t strength;
bool lost;
bool ack;
message_t* msg;
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;
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;
}
return (signalStr - noise);
}
+ double arr_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));
+ 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;
+ else if (prr_hat < 0)
+ prr_hat = 0;
+
+ 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;
}
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 X = fabs(SNR_lin-beta2);
double PSE = 0.5*erfc(beta1*sqrt(X/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;
else if (prr_hat < 0)
}
+ /* 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;
else {
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("CpmModelC", "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("CpmModelC", " -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("CpmModelC", " acknowledgment requested, ");
// 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", " -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
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 {
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("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) {
gain_entry_t* neighborEntry = sim_gain_first(sim_node());
requestAck = ack;
outgoing = msg;
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 && (other == dest), power + sim_gain_value(sim_node(), other), reversePower + sim_gain_value(other, sim_node()));
neighborEntry = sim_gain_next(neighborEntry);
}
}
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);
+ }
}