diff --git a/SimulationGraph/main.py b/SimulationGraph/main.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b230e1293013a52411c9ea7c3dfb0ee18a6406ba 100644 --- a/SimulationGraph/main.py +++ b/SimulationGraph/main.py @@ -0,0 +1,70 @@ +import json +import matplotlib.pyplot as plt +import pandas as pd +import sys +import os + +def plot_simulation_analysis(file_path): + with open(file_path, "r") as f: + data = json.load(f) + + logs = data["logs"] + + df = pd.DataFrame(logs) + + fig, axs = plt.subplots(3, 2, figsize=(15, 12)) + fig.suptitle("Simulation Session Analysis", fontsize=16) + + axs[0, 0].plot(df["timestamp"], df["totalDistance"], label="Total Distance", color="blue") + axs[0, 0].set_title("Total Distance Travelled") + axs[0, 0].set_xlabel("Time (s)") + axs[0, 0].set_ylabel("Distance (units)") + axs[0, 0].legend() + + axs[0, 1].plot(df["timestamp"], df["currentScore"], label="Score", color="green") + axs[0, 1].set_title("Score Over Time") + axs[0, 1].set_xlabel("Time (s)") + axs[0, 1].set_ylabel("Score") + axs[0, 1].legend() + + df["speed"] = df["velocity"].apply(lambda v: (v['x']**2 + v['y']**2 + v['z']**2)**0.5) + axs[1, 0].plot(df["timestamp"], df["speed"], label="Speed", color="orange") + axs[1, 0].set_title("Instantaneous Speed") + axs[1, 0].set_xlabel("Time (s)") + axs[1, 0].set_ylabel("Speed (units/s)") + axs[1, 0].legend() + + axs[1, 1].plot(df["timestamp"], df["variationInDirection"], label="Direction Changes", color="purple") + axs[1, 1].set_title("Direction Variation (sliding window)") + axs[1, 1].set_xlabel("Time (s)") + axs[1, 1].set_ylabel("Changes") + axs[1, 1].legend() + + axs[2, 0].plot(df["timestamp"], df["explorationEfficiency"], label="Exploration Efficiency", color="red") + axs[2, 0].set_title("Exploration Efficiency") + axs[2, 0].set_xlabel("Time (s)") + axs[2, 0].set_ylabel("Ratio (%)") + axs[2, 0].legend() + + axs[2, 1].plot(df["timestamp"], df["obstaclesHitCount"], label="Obstacles Hit", color="brown") + axs[2, 1].set_title("Obstacles Hit Over Time") + axs[2, 1].set_xlabel("Time (s)") + axs[2, 1].set_ylabel("Count") + axs[2, 1].legend() + + plt.tight_layout(rect=[0, 0.03, 1, 0.95]) + output_path = "simulation_analysis.png" + plt.savefig(output_path) + print(f"Graph saved to {output_path}") + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python main.py <simulation_file.json>") + sys.exit(1) + + simulation_file = sys.argv[1] + if not os.path.exists(simulation_file): + print(f"File not found: {simulation_file}") + sys.exit(1) + + plot_simulation_analysis(simulation_file) diff --git a/SimulationGraph/readme.md b/SimulationGraph/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..aa35c9dcf3a2a451137fcae12298aab7e81a8980 --- /dev/null +++ b/SimulationGraph/readme.md @@ -0,0 +1,55 @@ +# Simulation analyzer + +This Python application visualizes data from simulation log files generated by a Unity project. It is intended for analyzing gameplay sessions, especially in the context of learning curves or rehabilitation exercises. + +## Simulation log files + +If simulation logs exist, they are stored in the following directory of the Unity project: + +``` +impulse/Assets/SimulationLogs/ +``` + +Each file is saved in JSON format and typically follows this naming pattern: + +``` +Simulation-DD-MM-YYYY-hh-mm-ss.json +``` + +## How to run the application + +1. Make sure you have Python installed. +2. Install the required dependencies: + +``` +pip install matplotlib pandas +``` + +3. Run the script by passing a path to the simulation file: + +``` +python main.py impulse/Assets/SimulationLogs/Simulation-25-03-2025-10-26-42.json +``` + +## What it does + +The application generates a set of visual graphs to help you analyze a simulation session. It includes: + +- Total distance travelled over time +- Score progression +- Instantaneous speed (based on velocity vector) +- Direction changes (as variation indicator) +- Exploration efficiency ratio (distance vs parcours length) +- Cumulative number of obstacles hit + +These metrics help evaluate a player's performance, progression, and behavior throughout the session. + +## Purpose + +This tool is designed to support research and evaluation in interactive environments, such as: + +- **Learning progression analysis** +- **Detection of behavioral plateaus** +- **Rehabilitation and physical therapy monitoring** + +It enables game designers, therapists, or researchers to better understand user performance and adjust scenarios accordingly. diff --git a/SimulationGraph/simulation_analysis.png b/SimulationGraph/simulation_analysis.png new file mode 100644 index 0000000000000000000000000000000000000000..e318b5e2f39c75173fa406a2a448cb3d1ae82914 Binary files /dev/null and b/SimulationGraph/simulation_analysis.png differ diff --git a/UDP_App/UDPsender.py b/UDP_App/UDPsender.py index c094205603c596dc91d09922afc10143cd1f9106..8a906fbb40610b78d9454ef162b63ac0a6a6cb04 100644 --- a/UDP_App/UDPsender.py +++ b/UDP_App/UDPsender.py @@ -117,13 +117,23 @@ def draw_center_and_arrows(canvas): ) -def add_scroll_info_label(parent): +def add_scroll_info_label(canvas): info_text = "Scroll ↑ : rotate right\nScroll ↓ : rotate left" label_info = tk.Label( - parent, text=info_text, bg="white", fg="black", justify="right" + canvas, text=info_text, bg="white", fg="black", justify="right" ) label_info.place(relx=1.0, x=-10, y=10, anchor="ne") + def redirect_scroll(event): + canvas.event_generate("<MouseWheel>", x=event.x, y=event.y, delta=event.delta) + + def redirect_motion(event): + canvas.event_generate("<Motion>", x=event.x, y=event.y) + + label_info.bind("<MouseWheel>", redirect_scroll) + label_info.bind("<Motion>", redirect_motion) + + def disable_tracking(event): global is_tracking @@ -146,12 +156,12 @@ def main(): canvas.pack() draw_center_and_arrows(canvas) - add_scroll_info_label(root) + add_scroll_info_label(canvas) - root.bind("<Motion>", track_mouse) - root.bind("<MouseWheel>", adjust_rotation) - root.bind("<Enter>", enable_tracking) - root.bind("<Leave>", disable_tracking) + canvas.bind("<Motion>", track_mouse) + canvas.bind("<MouseWheel>", adjust_rotation) + canvas.bind("<Enter>", enable_tracking) + canvas.bind("<Leave>", disable_tracking) update_position() diff --git a/UDP_App/readme.md b/UDP_App/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..b991cb651f14daadf58d072885894cef9fbdab01 --- /dev/null +++ b/UDP_App/readme.md @@ -0,0 +1,68 @@ +# UDP Mouse Position Sender + +This is a lightweight Python application that sends mouse position and rotation data via UDP, simulating input to a system such as a Unity-based application. + +## Purpose + +This tool is designed to **simulate a real physical device** that would normally provide position data. It is particularly useful for testing in development environments when the actual hardware is not available. + +The real device sends only `x` and `y` position values (no rotation), with a **maximum value of 65 units** in each axis. However, this simulator also includes rotation data (notably `y_theta`) for testing purposes, as it can be helpful during development. + +## Features + +- Sends data: `x, y, z, x_theta, y_theta, z_theta` +- Uses a 2D canvas to emulate movement +- Scroll to simulate rotation along Y-axis +- Mouse hover in/out to start/stop tracking + +## Setup + +### Requirements +You do not need external libraries beyond the standard library (`socket` and `tkinter`). + +``` +pip install socket tk +``` + +### Usage + +1. Run the script: + +``` +python main.py +``` + +2. A window opens: + - Move your mouse within the window to simulate `x` and `y` movement. + - Use scroll wheel to adjust `y_theta`. + - Data is sent to `127.0.0.1:5000` as UDP packets every 100ms. + +## Data Format + +The app sends a string of comma-separated values: + +``` +x,y,z,x_theta,y_theta,z_theta +``` + +- `x`, `y` are scaled from mouse position in the window (range: 15 → 65). +- `z` and other rotations are currently fixed at 0, except `y_theta`. + +### Example Packet Sent: +``` +42.5,51.3,0,0,15,0 +``` + +## Notes + +- Movement only sends data when the mouse is inside the window. +- Exiting the window pauses tracking. +- Output is printed in the console for visibility. + +## Use Case + +Emulating spatial inputs in development environments like: +- Unity +- Custom rehab software +- Remote control emulators +