function save_simulated_servo_data(data, fs) { var flight_time = []; var servo_angle = []; var servo_speed = []; for (let i = 1; i < data.length; i++) { flight_time.push(Math.round(data[i].flight_time*100)/100); servo_angle.push(data[i].servo_angle); servo_speed.push(data[i].parachute_retraction_speed); } fs.writeFile('servo_data.json', flight_time + '\n' + servo_angle + '\n' + servo_speed, err => { if (err) { console.error(err) return } //file written successfully }) } function send_data(data, ALTIMETER_ERROR, ACCELEROMETER_ERROR, port) { var msg = data.flight_time + "T "; msg += data.altitude*get_random_percent(ALTIMETER_ERROR) + "A "; msg += data.accel.x*get_random_percent(ACCELEROMETER_ERROR) + "X "; msg += data.accel.y*get_random_percent(ACCELEROMETER_ERROR) + "Y "; msg += data.accel.z*get_random_percent(ACCELEROMETER_ERROR) + "Z"; msg += "!"; port.write(msg); console.log(); console.log("Sent: " + msg); } function plot_data(data, fc_data, plotly, open, fs) { var flight_time_values = []; // Graph 1 data var altitude_values = []; var accel_x_values = []; var accel_y_values = []; var accel_z_values = []; for (let i = 1; i < fc_data.length; i++) { flight_time_values.push(fc_data[i].flight_time); altitude_values.push(fc_data[i]["altitude"]); accel_x_values.push(fc_data[i]["accel"].x); accel_y_values.push(fc_data[i]["accel"].y); accel_z_values.push(fc_data[i]["accel"].z); } var altitude_trace = { x: flight_time_values, y: altitude_values, name: "Actual Altitude (m)", type: "scatter", }; var accel_x_trace = { x: flight_time_values, y: accel_x_values, name: "Sensor Accel X (m/s/s)", type: "scatter", }; var accel_y_trace = { x: flight_time_values, y: accel_y_values, name: "Sensor Accel Y (m/s/s)", type: "scatter", }; var accel_z_trace = { x: flight_time_values, y: accel_z_values, name: "Sensor Accel Z (m/s/s)", type: "scatter", }; var graph1_data = { data: [altitude_trace, accel_x_trace, accel_y_trace, accel_z_trace], }; // Graph 2 data var predicted_apogee_values = []; var servo_angle_values = []; var drag_force_values = []; var vel_x_values = []; var vel_y_values = []; var vel_z_values = []; var pos_x_values = []; var pos_y_values = []; var pos_z_values = []; for (let i = 1; i < fc_data.length; i++) { predicted_apogee_values.push(fc_data[i]["predicted_apogee"]); servo_angle_values.push(fc_data[i]["servo_angle"]); drag_force_values.push(fc_data[i]["total_drag"]); vel_x_values.push(fc_data[i]["integration_velocity"].x); vel_y_values.push(fc_data[i]["integration_velocity"].y); vel_z_values.push(fc_data[i]["integration_velocity"].z); pos_x_values.push(fc_data[i]["integration_position"].x); pos_y_values.push(fc_data[i]["integration_position"].y); pos_z_values.push(fc_data[i]["integration_position"].z); } var predicted_apogee_trace = { x: flight_time_values, y: predicted_apogee_values, name: "Predicted Apogee (m)", type: "scatter", }; var servo_angle_trace = { x: flight_time_values, y: servo_angle_values, name: "Servo Angle", type: "scatter", }; var drag_force_trace = { x: flight_time_values, y: drag_force_values, name: "Drag Force (N)", type: "scatter", }; var vel_x_trace = { x: flight_time_values, y: vel_x_values, name: "Integrated Velocity X (m/s)", type: "scatter", }; var vel_y_trace = { x: flight_time_values, y: vel_y_values, name: "Integrated Velocity Y (m/s)", type: "scatter", }; var vel_z_trace = { x: flight_time_values, y: vel_z_values, name: "Integrated Velocity Z (m/s)", type: "scatter", }; var pos_x_trace = { x: flight_time_values, y: pos_x_values, name: "Integrated Position X (m)", type: "scatter", }; var pos_y_trace = { x: flight_time_values, y: pos_y_values, name: "Integrated Position Y (m)", type: "scatter", }; var pos_z_trace = { x: flight_time_values, y: pos_z_values, name: "Integrated Position Z (m)", type: "scatter", }; var graph2_data = { data: [predicted_apogee_trace, altitude_trace, servo_angle_trace, drag_force_trace, vel_x_trace, vel_y_trace, vel_z_trace, pos_x_trace, pos_y_trace, pos_z_trace], }; // Graph 3 data var predicted_time_of_flight_values = []; var main_parachute_retract_speed_values = []; var main_parachute_retract_distance_values = []; for (let i = 1; i < fc_data.length; i++) { predicted_time_of_flight_values.push(fc_data[i]["predicted_time_of_flight"]); main_parachute_retract_speed_values.push(fc_data[i]["main_parachute_retract_speed"]); main_parachute_retract_distance_values.push(fc_data[i]["main_parachute_retract_distance"]); } var predicted_time_of_flight_trace = { x: flight_time_values, y: predicted_time_of_flight_values, name: "Predicted Time of Flight (s)", type: "scatter", }; var main_parachute_retract_speed_trace = { x: flight_time_values, y: main_parachute_retract_speed_values, name: "Main Parachute Retract Speed (cm/s)", type: "scatter", }; var main_parachute_retract_distance_trace = { x: flight_time_values, y: main_parachute_retract_distance_values, name: "Main Parachute Retract Distance (cm)", type: "scatter", }; var graph3_data = { //data: [predicted_time_of_flight_trace, altitude_trace, accel_x_trace, accel_y_trace, accel_z_trace, drag_force_trace, vel_x_trace, vel_y_trace, vel_z_trace, main_parachute_retract_speed_trace], data: [predicted_time_of_flight_trace, altitude_trace, accel_x_trace, accel_y_trace, accel_z_trace, drag_force_trace, vel_x_trace, vel_y_trace, vel_z_trace, main_parachute_retract_speed_trace, main_parachute_retract_distance_trace], }; var imgOptions = { format: 'pdf', width: 1000, height: 500, }; // Exporting pdfs plotly.getImage(graph1_data, imgOptions, function (err, imgStream) { if (err) return console.log (err); var fileStream = fs.createWriteStream('Graph 1.pdf'); imgStream.pipe(fileStream); }); plotly.getImage(graph2_data, imgOptions, function (err, imgStream) { if (err) return console.log (err); var fileStream = fs.createWriteStream('Graph 2.pdf'); imgStream.pipe(fileStream); }); plotly.getImage(graph3_data, imgOptions, function (err, imgStream) { if (err) return console.log (err); var fileStream = fs.createWriteStream('Graph 3.pdf'); imgStream.pipe(fileStream); }); /* // More featured plot accessed through plotly's website var layout = { title: "Simulator Altitude", xaxis: { title: "Seconds (s)", }, yaxis: {title: "Altitude (m)"}, yaxis2: { title: "Predicted Altitude (m)", titlefont: {color: "rgb(148, 103, 189)"}, tickfont: {color: "rgb(148, 103, 189)"}, overlaying: "y", side: "right" }, }; var graphOptions = { layout: layout, filename: "Altitude Plot", fileopt: "overwrite" }; plotly.plot(data.data, graphOptions, function (err, msg) { open(msg.url); }); */ } function calculate_drag(cd, area, velocity, air_density) { return 0.5 * air_density * velocity * velocity * cd * area; } function interpolate_data(x_data, y_data, num_x_vals, actual_x_val) { if (actual_x_val > x_data[num_x_vals-1]) { return 0; } var lower_bound_index; for (let i = 0; i < num_x_vals; i++) { if (actual_x_val == x_data[i]) { // If the x value we're looking at lands exactly at a data point, just use it return y_data[i]; // Return the y value associated with the x value we are looking at } else if (actual_x_val > x_data[i]) { // The x value we're looking for is greater than the value we're comparing it to, then we just passed the suitable range lower_bound_index = i; // Save the index of the last x value where we are greater than } else { // If the x value we're looking for is less than the value we're comparing it to, stop break; } } // Now that we have the lower bound index, we know which two x values the data point will fall between, // so we create a secant line between the two bounds and then grab the estimated y value // y = mx + b -> y = (y2-y1)/(x2-x1)*(x-x1) + y1 // where (x1,y1) is the lower bound data point and (x2,y2) is the upper bound data point return ((y_data[lower_bound_index+1] - y_data[lower_bound_index])/(x_data[lower_bound_index+1] - x_data[lower_bound_index]))*(actual_x_val - x_data[lower_bound_index]) + y_data[lower_bound_index]; } function sign(x) { if (x == 0) { return 0; } else if (x < 0) { return -1; } else { return 1; } } function get_random_percent(max) { var rand1 = Math.random(); if (rand1 < 0.5) { rand1 = -1; } else { rand1 = 1; } return 1+(Math.floor(Math.random()*max*100) * rand1)*0.0001; } module.exports = {save_simulated_servo_data, send_data, plot_data, calculate_drag, interpolate_data, sign, get_random_percent};