diff --git a/controls/DataAnalysisTool/Tool/simplePlots.m b/controls/DataAnalysisTool/Tool/simplePlots.m
new file mode 100644
index 0000000000000000000000000000000000000000..edd91bf4aa05002531109897c7c0f6ca162ed387
--- /dev/null
+++ b/controls/DataAnalysisTool/Tool/simplePlots.m
@@ -0,0 +1,70 @@
+%% 
+plot(Time, Cam_Meas_Roll*(180/pi)); hold on;
+plot(Time, Quad_Meas_Roll*(180/pi));
+
+%%
+plot(Time, pitch_velocity*(180/pi)); hold on;
+plot(Time, roll_velocity*(180/pi));
+plot(Time, yaw_velocity*(180/pi));
+
+%% 
+figure;
+plot(time, VRPNPitchConstant*(180/pi)); hold on;
+plot(time, PitchConstant*(180/pi));
+legend('Camera Pitch', 'Quad Pitch');
+xlabel('seconds'); ylabel('degrees');
+
+%% 
+figure;
+plot(time, (VRPNRollConstant + pi)*(180/pi)); hold on;
+plot(time, RollConstant*(180/pi));
+legend('Camera Roll', 'Quad Roll');
+xlabel('seconds'); ylabel('degrees');
+
+%% 
+%plot(Time, X_setpoint); hold on;
+markerSize = 3;
+ax1 = subplot(2,1,1);
+plot(time, (XSetpointConstant - VRPNXConstant), '-o', 'MarkerSize', markerSize); hold on;
+plot(time, -XposPIDCorrection * (180/pi), '-o', 'MarkerSize', markerSize); hold off;
+legend('X Error', 'X PID output');
+
+
+ax2 = subplot(2,1,2);
+plot(time, (180/pi)*PitchConstant, '-o', 'MarkerSize', markerSize); hold on;
+plot(time, (180/pi)*PitchPIDCorrection, '-o', 'MarkerSize', markerSize);
+legend('Pitch Error', 'Pitch PID output');
+
+linkaxes([ax1, ax2], 'x');
+%%
+ax2 = subplot(2,2,1);
+plot(time, XSetpointConstant - VRPNXConstant);
+title('X error');
+
+ax1 = subplot(2,2,2);
+plot(time, XposPIDCorrection);
+title('x output');
+
+ax3 = subplot(2,2,3);
+plot(time, PitchPIDCorrection); hold on;
+plot(time, VRPNPitchConstant .* 10);
+title('pitch output');
+legend('output', 'Pitch');
+
+ax4 = subplot(2,2,4);
+plot(time, PitchRatePIDCorrection); hold on;
+plot(time, gyro_y .* 1044.26);
+legend('output', 'Pitch rate');
+title('pitch rate output');
+
+linkaxes([ax1, ax2, ax3, ax4], 'x');
+%%
+plot(time, 1044.26 .* (PitchPIDCorrection - gyro_y));hold on;
+%plot(time, PitchRatePIDCorrection);
+%%
+ax2 = subplot(2, 1, 1);
+plot(time, YawConstant);
+ax1 = subplot(2, 1, 2);
+plot(time, gyro_z); hold on;
+plot(time, YawRatePIDCorrection);
+linkaxes([ax1, ax2], 'x');
\ No newline at end of file
diff --git a/controls/model/c_controller.c b/controls/model/c_controller.c
new file mode 100644
index 0000000000000000000000000000000000000000..6bcee0997d9c72199d6983b738bac881478fdbe6
--- /dev/null
+++ b/controls/model/c_controller.c
@@ -0,0 +1,72 @@
+#include "c_controller.h"
+#include "quad_files/control_algorithm.c"
+#include "quad_files/computation_graph.c"
+double c_controller(int vrpn_id, double vrpn_ts, double set_x, double set_y, double set_z, double set_yaw,
+        double cur_x, double cur_y, double cur_z,
+        double cur_phi, double cur_theta, double cur_psi,
+        double cur_phi_d, double cur_theta_d, double cur_psi_d,
+        double *z_out, double *y_out, double *x_out, double *yaw_out,
+        double* pid_y_out, double* pid_roll_out) {
+    
+    static log_t log_struct;
+    static user_input_t user_input_struct;
+    static sensor_t sensor_struct;
+    static setpoint_t setpoint_struct;
+    static parameter_t ps;
+    static user_defined_t user_defined_struct;
+    static actuator_command_t actuator_struct;
+    static modular_structs_t structs;
+    
+    static int last_vrpn_id = -1;
+    static int initialized = 0;
+    if (!initialized) {
+        control_algorithm_init(&ps);
+        sensor_struct.currentQuadPosition.packetId = vrpn_id;
+        initialized = 1;
+    }
+    
+    // Check VRPN update
+    if (vrpn_id != last_vrpn_id) {
+        user_input_struct.locationFresh = 1;
+        int vrpn_ts_packets = (vrpn_ts / 0.01) + 0.5; // + 0.5 to round
+        sensor_struct.currentQuadPosition.packetId += vrpn_ts_packets;
+        // VRPN values
+        sensor_struct.currentQuadPosition.x_pos = cur_x;
+        sensor_struct.currentQuadPosition.y_pos = cur_y;
+        sensor_struct.currentQuadPosition.alt_pos = cur_z;
+        sensor_struct.currentQuadPosition.pitch = cur_theta;
+        sensor_struct.currentQuadPosition.roll = cur_phi;
+        sensor_struct.currentQuadPosition.yaw = cur_psi;
+        last_vrpn_id = vrpn_id;
+    }
+    
+    // Setpoints
+    /*
+    setpoint_struct.desiredQuadPosition.x_pos = set_x;
+    setpoint_struct.desiredQuadPosition.y_pos = set_y;
+    setpoint_struct.desiredQuadPosition.alt_pos = set_z;
+    setpoint_struct.desiredQuadPosition.yaw = set_yaw;
+    */
+    int i;
+    
+    // Sensors
+    sensor_struct.pitch_angle_filtered = cur_theta;
+    sensor_struct.roll_angle_filtered = cur_phi;
+    sensor_struct.theta_dot = cur_theta_d;
+    sensor_struct.phi_dot = cur_phi_d;
+    sensor_struct.psi_dot = cur_psi_d;
+    
+    control_algorithm(&log_struct, &user_input_struct, &sensor_struct, &setpoint_struct, &ps, &user_defined_struct, &actuator_struct, NULL);
+    
+    *z_out = graph_get_output(ps.graph, ps.alt_pid, PID_CORRECTION);
+    *y_out = graph_get_output(ps.graph, ps.roll_r_pid, PID_CORRECTION);
+    *x_out = graph_get_output(ps.graph, ps.pitch_r_pid, PID_CORRECTION);
+    *yaw_out = graph_get_output(ps.graph, ps.yaw_r_pid, PID_CORRECTION);
+    
+    *pid_y_out = graph_get_output(ps.graph, ps.y_pos_pid, PID_CORRECTION);
+    *pid_roll_out = graph_get_output(ps.graph, ps.roll_pid, PID_CORRECTION);
+    return 0;
+}
+
+int read_flap(int flap) { return AUTO_FLIGHT_MODE; }
+float get_last_loop_time() { return 0.005; }
diff --git a/controls/model/c_controller.h b/controls/model/c_controller.h
new file mode 100644
index 0000000000000000000000000000000000000000..e53b1a508409d70211a99fe6ba6de76e092ae7a5
--- /dev/null
+++ b/controls/model/c_controller.h
@@ -0,0 +1,18 @@
+#ifndef C_CONTROLLER_H
+#define C_CONTROLLER_H
+#include "quad_files/computation_graph.h"
+#include "quad_files/graph_blocks/node_pid.h"
+#include "quad_files/graph_blocks/node_bounds.h"
+#include "quad_files/graph_blocks/node_constant.h"
+#include "quad_files/graph_blocks/node_mixer.h"
+#include "quad_files/PID.h"
+#include "quad_files/control_algorithm.h"
+
+double c_controller(int vrpn_id, double vrpn_ts, double set_x, double set_y, double set_z, double set_yaw,
+        double cur_x, double cur_y, double cur_z,
+        double cur_phi, double cur_theta, double cur_psi,
+        double cur_phi_d, double cur_theta_d, double cur_psi_d,
+        double *z_out, double *y_out, double *x_out, double *yaw_out,
+        double* pid_y_out, double* pid_roll_out);
+
+#endif // C_CONTROLLER_H
\ No newline at end of file
diff --git a/controls/model/modelParameters.m b/controls/model/modelParameters.m
index e457e0332bd2705446dba5aa74145ebb9f26aeb0..f01946f1f512a9e114c26b68b801b0581d243f04 100644
--- a/controls/model/modelParameters.m
+++ b/controls/model/modelParameters.m
@@ -20,7 +20,8 @@
     If = 0.511;                     % Motor internal friction current
     Pmin = 1e5;                     % Minimum zybo output duty cycle command
     Pmax = 2e5;                     % Maximum zybo output duty cycle command
-    Tc = 0.01;                      % Camera system sampling period
+    Tc = 0.04;                      % Camera system sampling period
+    Tq = 0.005;                     % Quad sampling period
     tau_c = 0;                      % Camera system total latency
     Vb = 11.1;                      % Nominal battery voltage (V)
     x_controlled_o = 0;             % Equilibrium lateral controller output
diff --git a/controls/model/quad_files/.gitignore b/controls/model/quad_files/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1c4bc674e912af84e9c6bed639cd5780a68b7846
--- /dev/null
+++ b/controls/model/quad_files/.gitignore
@@ -0,0 +1,3 @@
+# Don't track the copied files here
+*.h
+*.c
\ No newline at end of file
diff --git a/controls/model/quad_files/copy_files.bat b/controls/model/quad_files/copy_files.bat
new file mode 100644
index 0000000000000000000000000000000000000000..bd5f65861b103ddaf3b761a47c9bc584bb35b50b
--- /dev/null
+++ b/controls/model/quad_files/copy_files.bat
@@ -0,0 +1,27 @@
+copy ..\..\..\quad\computation_graph\src\computation_graph.c computation_graph.c
+copy ..\..\..\quad\computation_graph\src\computation_graph.h computation_graph.h
+
+copy ..\..\..\quad\sw\modular_quad_pid\src\control_algorithm.h control_algorithm.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\control_algorithm.c control_algorithm.c
+
+copy ..\..\..\quad\sw\modular_quad_pid\src\PID.h PID.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\type_def.h type_def.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\sensor_processing.h sensor_processing.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\log_data.h log_data.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\quadposition.h quadposition.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\util.h util.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\timer.h timer.h
+copy ..\..\..\groundStation\src\backend\commands.h commands.h
+copy ..\..\..\groundStation\src\backend\callbacks.h callbacks.h
+
+mkdir graph_blocks
+copy ..\..\..\quad\computation_graph\src\graph_blocks\node_constant.h graph_blocks\node_constant.h
+copy ..\..\..\quad\computation_graph\src\graph_blocks\node_constant.c graph_blocks\node_constant.c
+copy ..\..\..\quad\computation_graph\src\graph_blocks\node_add.h graph_blocks\node_add.h
+copy ..\..\..\quad\computation_graph\src\graph_blocks\node_add.c graph_blocks\node_add.c
+copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_mixer.c graph_blocks\node_mixer.c
+copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_mixer.h graph_blocks\node_mixer.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_pid.c graph_blocks\node_pid.c
+copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_pid.h graph_blocks\node_pid.h
+copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_bounds.c graph_blocks\node_bounds.c
+copy ..\..\..\quad\sw\modular_quad_pid\src\graph_blocks\node_bounds.h graph_blocks\node_bounds.h
\ No newline at end of file
diff --git a/controls/model/test_model.slx b/controls/model/test_model.slx
index 805e43a9e1d83040c87b713476195126ca17d371..d95ac846d3726b2898b9a6499f563588a52764c8 100644
Binary files a/controls/model/test_model.slx and b/controls/model/test_model.slx differ
diff --git a/quad/computation_graph/src/computation_graph.c b/quad/computation_graph/src/computation_graph.c
index 5fcfd4c5c76ad7c221da927c410f45184c5c0578..7434e14a112117b8dbe22a3ecd300b04c6c90413 100644
--- a/quad/computation_graph/src/computation_graph.c
+++ b/quad/computation_graph/src/computation_graph.c
@@ -103,7 +103,7 @@ int graph_add_node(struct computation_graph *graph,
     new_node->n_children = 0;
     new_node->updated = 1;
     new_node->output_values = malloc(type->n_outputs * sizeof(double));
-    new_node->param_values = malloc(type->n_params * sizeof(double));
+    new_node->param_values = calloc(type->n_params, sizeof(double));
     new_node->input_srcs = malloc(type->n_inputs * sizeof(struct input_type));
     // Check that malloc succeeded in every case which memory was requested
     if ((type->n_outputs && !new_node->output_values) ||
diff --git a/quad/computation_graph/src/graph_blocks/node_add.c b/quad/computation_graph/src/graph_blocks/node_add.c
index eefb22fde9ae9a5cc72d2eb679905f2e70038ac9..048a49b3b6a9c054f74900e356e6377f17a6a4b7 100644
--- a/quad/computation_graph/src/graph_blocks/node_add.c
+++ b/quad/computation_graph/src/graph_blocks/node_add.c
@@ -8,7 +8,7 @@ static void reset(void *state) {}
 
 static const char* const in_names[2] = {"Summand 1", "Summand 2"};
 static const char* const out_names[1] = {"Sum"};
-static const char* const param_names[0] = {};
+static const char* const param_names[1] = {"Error if you see this"};
 const struct graph_node_type node_add_type = {
         .input_names = in_names,
         .output_names = out_names,
diff --git a/quad/computation_graph/src/graph_blocks/node_constant.c b/quad/computation_graph/src/graph_blocks/node_constant.c
index 8ad9f8c5afdb5dc8f4cfacac00f2725ad388a59a..b2a46e757eef397b4c9805d4b76a159fccc6c9a0 100644
--- a/quad/computation_graph/src/graph_blocks/node_constant.c
+++ b/quad/computation_graph/src/graph_blocks/node_constant.c
@@ -6,7 +6,7 @@ static void output_const(void *state, const double *params, const double *inputs
 }
 static void reset(void *state) {}
 
-static const char* const in_names[0] = {};
+static const char* const in_names[1] = {"You shouldn't see this"};
 static const char* const out_names[1] = {"Constant"};
 static const char* const param_names[1] = {"Constant"};
 const struct graph_node_type node_const_type = {
diff --git a/quad/sw/modular_quad_pid/src/PID.h b/quad/sw/modular_quad_pid/src/PID.h
index a7701ab2a8a8701343d4e65d5688759d70aba2b9..4c5e4b81f0273a9a62aa175b6c0f350914fb67a2 100644
--- a/quad/sw/modular_quad_pid/src/PID.h
+++ b/quad/sw/modular_quad_pid/src/PID.h
@@ -49,6 +49,7 @@
 #define YPOS_KP 0.015f
 #define YPOS_KI 0.005f
 #define YPOS_KD 0.03f
+#define YPOS_ALPHA 0
 
 
 //Pitch constants
@@ -74,6 +75,7 @@
 #define XPOS_KP -0.015f
 #define XPOS_KI -0.005f
 #define XPOS_KD -0.03f
+#define XPOS_ALPHA 0
 
 
 //Throttle constants
diff --git a/quad/sw/modular_quad_pid/src/control_algorithm.c b/quad/sw/modular_quad_pid/src/control_algorithm.c
index 7a92f9f6bf6b7883d37f12d4f9cbc0dc207041fc..428323fd44a78db6f0be841ea870d0dcdd8deff9 100644
--- a/quad/sw/modular_quad_pid/src/control_algorithm.c
+++ b/quad/sw/modular_quad_pid/src/control_algorithm.c
@@ -174,9 +174,11 @@ int control_algorithm_init(parameter_t * ps)
     graph_set_param_val(graph, ps->x_pos_pid, PID_KP, XPOS_KP);
     graph_set_param_val(graph, ps->x_pos_pid, PID_KI, XPOS_KI);
     graph_set_param_val(graph, ps->x_pos_pid, PID_KD, XPOS_KD);
+    graph_set_param_val(graph, ps->x_pos_pid, PID_ALPHA, XPOS_ALPHA);
     graph_set_param_val(graph, ps->y_pos_pid, PID_KP, YPOS_KP);
     graph_set_param_val(graph, ps->y_pos_pid, PID_KI, YPOS_KI);
     graph_set_param_val(graph, ps->y_pos_pid, PID_KD, YPOS_KD);
+    graph_set_param_val(graph, ps->y_pos_pid, PID_ALPHA, YPOS_ALPHA);
     graph_set_param_val(graph, ps->alt_pid, PID_KP, ALT_ZPOS_KP);
     graph_set_param_val(graph, ps->alt_pid, PID_KI, ALT_ZPOS_KI);
     graph_set_param_val(graph, ps->alt_pid, PID_KD, ALT_ZPOS_KD);
@@ -189,6 +191,10 @@ int control_algorithm_init(parameter_t * ps)
     graph_set_param_val(graph, ps->clamp_d_pwmY, BOUNDS_MIN, -PWM_DIFF_BOUNDS);
     graph_set_param_val(graph, ps->clamp_d_pwmY, BOUNDS_MAX, PWM_DIFF_BOUNDS);
 
+
+    // Initial value for sampling periods
+    graph_set_param_val(graph, ps->pos_time, CONST_SET, 0.04);
+    graph_set_param_val(graph, ps->angle_time, CONST_SET, 0.005);
     // Set initial mode
     connect_manual(ps);
 
@@ -243,7 +249,7 @@ int control_algorithm_init(parameter_t * ps)
 		user_defined_struct->flight_mode = AUTO_FLIGHT_MODE;
 		connect_autonomous(ps);
 		// Reset this when autonomous is engaged, so there is not a large difference at the start of autonomous
-		last_vrpn_id = sensor_struct->currentQuadPosition.packetId;
+		last_vrpn_id = sensor_struct->currentQuadPosition.packetId - 1;
 	}
 
 	//PIDS///////////////////////////////////////////////////////////////////////
diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c b/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c
index 8b702b360654b3e957d19743abc24b433f58f64d..316c1ce8218b835ee002c8c4352c97af111b318d 100644
--- a/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c
+++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_mixer.c
@@ -25,7 +25,7 @@ static void reset_mixer(void *state) {}
 
 static const char* const in_names[4] = {"Throttle", "Pitch", "Roll", "Yaw"};
 static const char* const out_names[4] = {"PWM 0", "PWM 1", "PWM 2", "PWM 3"};
-static const char* const param_names[0] = {};
+static const char* const param_names[1] = {"You shouldnt see this"};
 const struct graph_node_type node_mixer_type = {
         .input_names = in_names,
         .output_names = out_names,
diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c
index acf77b5b4051c446067dfaea395a05cf89d1f916..7222094577d6c4ba1f41c93f65e5bdbe00c4dc75 100644
--- a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c
+++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.c
@@ -8,6 +8,7 @@ static double FLT_EPSILON = 0.0001;
 struct pid_node_state {
     double prev_error; // Previous error
     double acc_error; // Accumulated error
+    double last_filtered; // Last output from the filtered derivative
 };
 
 // The generic PID diagram. This function takes in pid inputs (CUR_POINT and SETOINT) and calculates the output "pid_correction"
@@ -49,13 +50,20 @@ static void pid_computation(void *state, const double* params, const double *inp
       pid_state->acc_error += error;
     }
 
-    double change_in_error = error - pid_state->prev_error;
 
     // Compute each term's contribution
     P = params[PID_KP] * error;
     I = params[PID_KI] * pid_state->acc_error * inputs[PID_DT];
-    D = params[PID_KD] * (change_in_error / inputs[PID_DT]);
-
+    // Low-pass filter on derivative
+    double change_in_error = error - pid_state->prev_error;
+    double term1 = params[PID_ALPHA] * pid_state->last_filtered;
+    double derivative = change_in_error / inputs[PID_DT];
+    if (inputs[PID_DT] == 0) { // Divide by zero check
+        derivative = 0;
+    }
+    double term2 = params[PID_KD] * (1.0f - params[PID_ALPHA]) * derivative;
+    D = term1 + term2;
+    pid_state->last_filtered = D; // Store filtered value for next filter iteration
     pid_state->prev_error = error; // Store the current error into the state
 
     outputs[PID_CORRECTION] = P + I + D; // Store the computed correction
@@ -67,19 +75,20 @@ static void reset_pid(void *state) {
     struct pid_node_state* pid_state = (struct pid_node_state*)state;
     pid_state->acc_error = 0;
     pid_state->prev_error = 0;
+    pid_state->last_filtered = 0;
 }
 
 
 static const char* const in_names[3] = {"Cur point", "Setpoint", "dt"};
 static const char* const out_names[1] = {"Correction"};
-static const char* const param_names[3] = {"Kp", "Ki", "Kd"};
+static const char* const param_names[4] = {"Kp", "Ki", "Kd", "alpha"};
 const struct graph_node_type node_pid_type = {
         .input_names = in_names,
         .output_names = out_names,
         .param_names = param_names,
         .n_inputs = 3,
         .n_outputs = 1,
-        .n_params = 3,
+        .n_params = 4,
         .execute = pid_computation,
         .reset = reset_pid
 };
diff --git a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h
index 75ded4af02edbc2cacbc68035f5a0970d65e38dc..ee841adde3e19f7ef86930bdb94da4e8eee76488 100644
--- a/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h
+++ b/quad/sw/modular_quad_pid/src/graph_blocks/node_pid.h
@@ -19,7 +19,8 @@ enum graph_node_pid_outputs {
 enum graph_node_pid_params {
     PID_KP, // Proportional constant
     PID_KI, // Integral constant
-    PID_KD // Derivative constant
+    PID_KD, // Derivative constant
+    PID_ALPHA // alpha = (1 - N*T_s); High values mean more filtering
 };
 
 #endif // __NODE_PID_H__