In this section, we introduce the key parameters and the format of the input data required for the task.
-
num_sensor: This parameter specifies the number of sensors to be created. Sensors will be assigned IDs ranging from 1 to num_sensorth.
-
sampling: This parameter defines the interval, measured in seconds, between each data collection from the sensors.
-
interval: This parameter sets the total duration of the experiment, measured in hours.
Each line of the input data should be added by the following format:
id,timestamp,value
Where:
-
id: Represents the unique identifier of the sensor as defined by the
num_sensor
parameter. -
timestamp: The timestamp is calculated based on the current system time. Initially, the timestamp starts at the current time minus the total experiment duration (
interval
). For subsequent data points, the timestamp is incremented by the value ofsampling
seconds.
time_t current_time = time(nullptr);
time_t start_time = current_time - measurement_duration * 3600;
time_t timestamp = start_time;
// Generate data for each timestamp
while (timestamp <= current_time) {
// Get local time information
struct tm* tm_info = localtime(×tamp);
// Format timestamp using stringstream
stringstream timestamp_ss;
timestamp_ss << put_time(tm_info, "%Y:%m:%d %H:%M:%S");
string timestamp_str = timestamp_ss.str();
for (int i = 1; i <= num_sensors; i++)
{
//do something here
}
// Move to the next timestamp
timestamp += sampling_time;
}
- value: The value is generated randomly within a given range using the following C++ function:
double generateRandomValue(double min, double max) {
//rand() function to get a value in range min, max
double random = static_cast<double>(rand()) / RAND_MAX; //casting it to double and dividing it
//by RAND_MAX, you convert the integer
//random value to a floating-point value between 0 and 1.
return min + random * (max - min);
}
// Initialize random seed
srand(static_cast<unsigned int>(time(nullptr)));
// Generate simulated measurement value
double measurement = generateRandomValue(0.1, 40000.0); //Range specified in the problem header
That is a simple explanation of all the requirements for Task 1. Now, let's delve into how to read input from the command line. To execute the simulation with specific parameters, type the following command in the terminal:
./lux_sim -n 3 -st 60 -si 10
Read how to pass parameters into Cpp program in this link: https://stackoverflow.com/questions/50021775/command-line-arguments-to-execute-a-c-program
int main(int argc, char* argv[]) {
// Default values for command-line arguments
int num_sensors = 1;
int sampling_time = 60; //unit in seconds
int measurement_duration = 24; //unit in hours
// Parse command-line arguments
for (int i = 1; i < argc; i++) {
string arg = argv[i];
// Parse the value of each command-line argument
if (arg == "-n" && i + 1 < argc) {
num_sensors = stoi(argv[i + 1]);
}
else if (arg == "-st" && i + 1 < argc) {
sampling_time = stoi(argv[i + 1]);
}
else if (arg == "-si" && i + 1 < argc) {
measurement_duration = stoi(argv[i + 1]);
}
}
//Use for debugging
// cout << "Number of sensors: " << num_sensors << endl;
// cout << "Sampling time: " << sampling_time << " seconds" << endl;
// cout << "Measurement duration: " << measurement_duration << " hours" << endl;
}
To write the simulation data to a CSV file, I use the following C++ code snippet:
ofstream datafile("lux_sensor.csv");
datafile << "id,time,value\n";// Write header to the output file
datafile << "Content to the file" << endln;
// Close the output file
datafile.close();
cout << "Data generated and stored successfully!" << endl;
Each line in the output file should be written in this fomat:
datafile << i << "," << timestamp_str << "," << fixed << setprecision(2) << measurement << "\n";
Here, we only print the value round up to 2 digits after decimal point, so I use fixed << setprecision(2)
in iomanip
library
Now, run the command from the Linux terminal to compile the program:
g++ lux_sim.cpp -o lux_sim
Then run it:
./lux_sim -n 3 -st 60 -si 10
A message will show up to confirm we have successfully written data to the csv file
Data generated and store successfully!
Checking the lux_sensor.csv
file, it will appear in the same directory as our code and may look something like this:
id,time,value
1,2023:12:31 05:23:59,895.65
2,2023:12:31 05:23:59,11573.57
3,2023:12:31 05:23:59,35734.77
1,2023:12:31 05:26:59,34121.59
2,2023:12:31 05:26:59,1339.59
3,2023:12:31 05:26:59,32881.15
............
As mentioned in the requirements, the following errors may occur during the execution of Task 1:
- Wrong command-line statement, e.g.: lack of the 1 or a few required command-line
argument. The error message can be “Error 01: invalid command”.
// Check if the correct number of command-line arguments is provided if (argc != 7) { writelog("Error 01: Invalid command"); return 1; }
- Invalid value of the command-line argument, e.g. negative number of sensors. The error
message can be “Error 02: invalid argument”.
// Check for invalid argument values if (num_sensors < 1 || sampling_time < 1 || measurement_duration < 1) { writelog("Error 02: Invalid argument"); return 1; }
- “lux_sensor.csv” file is existing and is a read-only file. The error message can be “Error 03:
file access denied”
if (!datafile.is_open()) { writelog("Error 03: File access denied"); return 1; }
with the writelog
function as follow:
void writelog(const string& message) {
ofstream logfile("task1.log", ios::app);
if (logfile.is_open()) {
logfile << message << endl;
} else {
cerr << "Error: Unable to open log file 'task1.log'" << endl;
}
logfile.close();
}