SpringCleanAndAnalyze.exe
· 47 MiB · Binary
Raw
This file can't be rendered. View the full file.
SpringCleanAndAnalyze.py
· 7.2 KiB · Python
Raw
import pandas as pd
import glob
import os
# ---------------------------------------------------------
# STEP 1 - Ask user which spring to process
# ---------------------------------------------------------
spring_name = input("Enter spring number (example: 1040_01): ").strip()
threshold = float(
input(
"Enter peak detection threshold (mm): "
)
)
# ---------------------------------------------------------
# STEP 2 - Find all matching test files
# ---------------------------------------------------------
file_pattern = f"Spring_{spring_name}_Test_*.csv"
file_list = glob.glob(file_pattern)
# Make sure files are processed in order
file_list.sort()
if len(file_list) == 0:
print(f"No files found matching: {file_pattern}")
exit()
# ---------------------------------------------------------
# STEP 3 - Variables used while combining files
# ---------------------------------------------------------
combined_data = []
time_offset = 0
# ---------------------------------------------------------
# STEP 4 - Process each test file
# ---------------------------------------------------------
for test_number, file in enumerate(file_list, start=1):
print(f"Processing: {file}")
# Read CSV
df = pd.read_csv(file)
# Remove rows containing empty data
df = df.dropna()
# Time column name
time_column = "Time (s)"
# Create Test column
df["Test"] = test_number
# Create continuous time column
df["Continuous Time (s)"] = df[time_column] + time_offset
# Determine ending time for next test
last_time = df[time_column].iloc[-1]
time_offset += last_time
# Store cleaned data
combined_data.append(df)
# ---------------------------------------------------------
# STEP 5 - Combine all tests into one dataframe
# ---------------------------------------------------------
final_df = pd.concat(combined_data, ignore_index=True)
# ---------------------------------------------------------
# STEP 6 - Create output filename
# ---------------------------------------------------------
output_file = f"Spring_{spring_name}_Cleaned.csv"
# ---------------------------------------------------------
# STEP 7 - Save cleaned data
# ---------------------------------------------------------
final_df.to_csv(output_file, index=False)
print()
print(f"Finished Cleaning!")
print(f"Output saved as: {output_file}")
# ---------------------------------------------------------------------
# ANALYZING SECTION
# ---------------------------------------------------------------------
# ---------------------------------------------------------
# STEP 2 - Open cleaned file
# ---------------------------------------------------------
input_file = f"Spring_{spring_name}_Cleaned.csv"
print(f"\nLoading {input_file}...")
df = pd.read_csv(input_file)
# ---------------------------------------------------------
# STEP 3 - Define important column names
# ---------------------------------------------------------
extension_column = "Extension (mm)"
# ---------------------------------------------------------
# STEP 4 - Create Above Threshold flag
#
# 1 = Extension is above threshold
# 0 = Extension is below threshold
# ---------------------------------------------------------
print("Creating Above Threshold...")
df["Above Threshold"] = (
df[extension_column] >= threshold
).astype(int)
# ---------------------------------------------------------
# STEP 5 - Create Previous Above Threshold column
#
# Shift the Above Threshold column down by one row
# ---------------------------------------------------------
print("Creating Previous Above Threshold...")
df["Previous Above Threshold"] = (
df["Above Threshold"]
.shift(1)
.fillna(0)
.astype(int)
)
# ---------------------------------------------------------
# STEP 6 - Create Rising Edge column
#
# Rising Edge occurs when:
#
# Previous = 0
# Current = 1
# ---------------------------------------------------------
print("Creating Rising Edge...")
df["Rising Edge"] = (
(df["Above Threshold"] == 1)
&
(df["Previous Above Threshold"] == 0)
).astype(int)
# ---------------------------------------------------------
# STEP 7 - Create Falling Edge column
#
# Falling Edge occurs when:
#
# Previous = 1
# Current = 0
# ---------------------------------------------------------
print("Creating Falling Edge...")
df["Falling Edge"] = (
(df["Above Threshold"] == 0)
&
(df["Previous Above Threshold"] == 1)
).astype(int)
# ---------------------------------------------------------
# STEP 8 - Create Cycle Number
#
# Every Rising Edge starts a new cycle.
#
# Example:
#
# Rising Edge:
# 0 0 1 0 0 1 0
#
# Cycle Number:
# 0 0 1 1 1 2 2
# ---------------------------------------------------------
print("Creating Cycle Number...")
df["Cycle Number"] = (
df["Rising Edge"]
.cumsum()
)
# ---------------------------------------------------------
# STEP 9 - Save analyzed file
# ---------------------------------------------------------
print("Saving Analyzed File...")
output_file = f"Spring_{spring_name}_Analyzed.csv"
df.to_csv(output_file, index=False)
# ---------------------------------------------------------
# STEP 11 - Create Peak Summary
# ---------------------------------------------------------
peak_summary = []
print("Creating Cycle Numbers...")
# Get all valid cycle numbers
cycle_numbers = sorted(
df[df["Cycle Number"] > 0]["Cycle Number"].unique()
)
for cycle in cycle_numbers:
# Get only rows for this cycle that are above threshold
cycle_data = df[
(df["Cycle Number"] == cycle)
&
(df["Above Threshold"] == 1)
]
# Skip empty cycles just in case
if len(cycle_data) == 0:
continue
# Find row with maximum load
peak_index = cycle_data["Load (N)"].idxmax()
peak_row = df.loc[peak_index]
peak_summary.append({
"Cycle Number": cycle,
"Test": peak_row["Test"],
"Peak Load (N)": peak_row["Load (N)"],
"Peak Extension (mm)": peak_row[extension_column],
"Peak Time (s)": peak_row["Continuous Time (s)"],
"Peak Row": peak_index
})
# ---------------------------------------------------------
# STEP 12 - Create dataframe
# ---------------------------------------------------------
peak_df = pd.DataFrame(peak_summary)
# ---------------------------------------------------------
# STEP 13 - Save peak summary
# ---------------------------------------------------------
print("Saving peak summary...")
peak_output_file = (
f"Spring_{spring_name}_Peaks.csv"
)
peak_df.to_csv(
peak_output_file,
index=False
)
# Cycles per test count
cycles_per_test = (
peak_df.groupby("Test").size()
)
print("Cycles Per Test:")
for test, count in cycles_per_test.items():
print(f"Test {int(test)}: {count}")
# ---------------------------------------------------------
# STEP 14 - Report results
# ---------------------------------------------------------
total_cycles = int(
df["Cycle Number"].max()
)
print("\nAnalysis Complete")
print(
f"Total Cycles Found: "
f"{total_cycles}"
)
print(
f"Total Peaks Found: "
f"{len(peak_summary)}"
)
print(
f"Analyzed File: "
f"{output_file}"
)
print(
f"Peak Summary File: "
f"{peak_output_file}"
)
input("\nPress Enter to exit")
| 1 | import pandas as pd |
| 2 | import glob |
| 3 | import os |
| 4 | |
| 5 | |
| 6 | # --------------------------------------------------------- |
| 7 | # STEP 1 - Ask user which spring to process |
| 8 | # --------------------------------------------------------- |
| 9 | spring_name = input("Enter spring number (example: 1040_01): ").strip() |
| 10 | |
| 11 | threshold = float( |
| 12 | input( |
| 13 | "Enter peak detection threshold (mm): " |
| 14 | ) |
| 15 | ) |
| 16 | |
| 17 | |
| 18 | # --------------------------------------------------------- |
| 19 | # STEP 2 - Find all matching test files |
| 20 | # --------------------------------------------------------- |
| 21 | file_pattern = f"Spring_{spring_name}_Test_*.csv" |
| 22 | |
| 23 | file_list = glob.glob(file_pattern) |
| 24 | |
| 25 | # Make sure files are processed in order |
| 26 | file_list.sort() |
| 27 | |
| 28 | if len(file_list) == 0: |
| 29 | print(f"No files found matching: {file_pattern}") |
| 30 | exit() |
| 31 | |
| 32 | |
| 33 | # --------------------------------------------------------- |
| 34 | # STEP 3 - Variables used while combining files |
| 35 | # --------------------------------------------------------- |
| 36 | combined_data = [] |
| 37 | |
| 38 | time_offset = 0 |
| 39 | |
| 40 | |
| 41 | # --------------------------------------------------------- |
| 42 | # STEP 4 - Process each test file |
| 43 | # --------------------------------------------------------- |
| 44 | for test_number, file in enumerate(file_list, start=1): |
| 45 | |
| 46 | print(f"Processing: {file}") |
| 47 | |
| 48 | # Read CSV |
| 49 | df = pd.read_csv(file) |
| 50 | |
| 51 | # Remove rows containing empty data |
| 52 | df = df.dropna() |
| 53 | |
| 54 | # Time column name |
| 55 | time_column = "Time (s)" |
| 56 | |
| 57 | # Create Test column |
| 58 | df["Test"] = test_number |
| 59 | |
| 60 | # Create continuous time column |
| 61 | df["Continuous Time (s)"] = df[time_column] + time_offset |
| 62 | |
| 63 | # Determine ending time for next test |
| 64 | last_time = df[time_column].iloc[-1] |
| 65 | |
| 66 | time_offset += last_time |
| 67 | |
| 68 | # Store cleaned data |
| 69 | combined_data.append(df) |
| 70 | |
| 71 | |
| 72 | # --------------------------------------------------------- |
| 73 | # STEP 5 - Combine all tests into one dataframe |
| 74 | # --------------------------------------------------------- |
| 75 | final_df = pd.concat(combined_data, ignore_index=True) |
| 76 | |
| 77 | |
| 78 | # --------------------------------------------------------- |
| 79 | # STEP 6 - Create output filename |
| 80 | # --------------------------------------------------------- |
| 81 | output_file = f"Spring_{spring_name}_Cleaned.csv" |
| 82 | |
| 83 | |
| 84 | # --------------------------------------------------------- |
| 85 | # STEP 7 - Save cleaned data |
| 86 | # --------------------------------------------------------- |
| 87 | final_df.to_csv(output_file, index=False) |
| 88 | |
| 89 | print() |
| 90 | print(f"Finished Cleaning!") |
| 91 | print(f"Output saved as: {output_file}") |
| 92 | |
| 93 | |
| 94 | # --------------------------------------------------------------------- |
| 95 | # ANALYZING SECTION |
| 96 | # --------------------------------------------------------------------- |
| 97 | |
| 98 | |
| 99 | # --------------------------------------------------------- |
| 100 | # STEP 2 - Open cleaned file |
| 101 | # --------------------------------------------------------- |
| 102 | |
| 103 | input_file = f"Spring_{spring_name}_Cleaned.csv" |
| 104 | |
| 105 | print(f"\nLoading {input_file}...") |
| 106 | |
| 107 | df = pd.read_csv(input_file) |
| 108 | |
| 109 | |
| 110 | # --------------------------------------------------------- |
| 111 | # STEP 3 - Define important column names |
| 112 | # --------------------------------------------------------- |
| 113 | |
| 114 | extension_column = "Extension (mm)" |
| 115 | |
| 116 | |
| 117 | # --------------------------------------------------------- |
| 118 | # STEP 4 - Create Above Threshold flag |
| 119 | # |
| 120 | # 1 = Extension is above threshold |
| 121 | # 0 = Extension is below threshold |
| 122 | # --------------------------------------------------------- |
| 123 | print("Creating Above Threshold...") |
| 124 | df["Above Threshold"] = ( |
| 125 | df[extension_column] >= threshold |
| 126 | ).astype(int) |
| 127 | |
| 128 | |
| 129 | # --------------------------------------------------------- |
| 130 | # STEP 5 - Create Previous Above Threshold column |
| 131 | # |
| 132 | # Shift the Above Threshold column down by one row |
| 133 | # --------------------------------------------------------- |
| 134 | print("Creating Previous Above Threshold...") |
| 135 | df["Previous Above Threshold"] = ( |
| 136 | df["Above Threshold"] |
| 137 | .shift(1) |
| 138 | .fillna(0) |
| 139 | .astype(int) |
| 140 | ) |
| 141 | |
| 142 | |
| 143 | # --------------------------------------------------------- |
| 144 | # STEP 6 - Create Rising Edge column |
| 145 | # |
| 146 | # Rising Edge occurs when: |
| 147 | # |
| 148 | # Previous = 0 |
| 149 | # Current = 1 |
| 150 | # --------------------------------------------------------- |
| 151 | print("Creating Rising Edge...") |
| 152 | df["Rising Edge"] = ( |
| 153 | (df["Above Threshold"] == 1) |
| 154 | & |
| 155 | (df["Previous Above Threshold"] == 0) |
| 156 | ).astype(int) |
| 157 | |
| 158 | |
| 159 | # --------------------------------------------------------- |
| 160 | # STEP 7 - Create Falling Edge column |
| 161 | # |
| 162 | # Falling Edge occurs when: |
| 163 | # |
| 164 | # Previous = 1 |
| 165 | # Current = 0 |
| 166 | # --------------------------------------------------------- |
| 167 | print("Creating Falling Edge...") |
| 168 | df["Falling Edge"] = ( |
| 169 | (df["Above Threshold"] == 0) |
| 170 | & |
| 171 | (df["Previous Above Threshold"] == 1) |
| 172 | ).astype(int) |
| 173 | |
| 174 | |
| 175 | # --------------------------------------------------------- |
| 176 | # STEP 8 - Create Cycle Number |
| 177 | # |
| 178 | # Every Rising Edge starts a new cycle. |
| 179 | # |
| 180 | # Example: |
| 181 | # |
| 182 | # Rising Edge: |
| 183 | # 0 0 1 0 0 1 0 |
| 184 | # |
| 185 | # Cycle Number: |
| 186 | # 0 0 1 1 1 2 2 |
| 187 | # --------------------------------------------------------- |
| 188 | print("Creating Cycle Number...") |
| 189 | df["Cycle Number"] = ( |
| 190 | df["Rising Edge"] |
| 191 | .cumsum() |
| 192 | ) |
| 193 | |
| 194 | |
| 195 | # --------------------------------------------------------- |
| 196 | # STEP 9 - Save analyzed file |
| 197 | # --------------------------------------------------------- |
| 198 | print("Saving Analyzed File...") |
| 199 | output_file = f"Spring_{spring_name}_Analyzed.csv" |
| 200 | |
| 201 | df.to_csv(output_file, index=False) |
| 202 | |
| 203 | |
| 204 | # --------------------------------------------------------- |
| 205 | # STEP 11 - Create Peak Summary |
| 206 | # --------------------------------------------------------- |
| 207 | |
| 208 | peak_summary = [] |
| 209 | |
| 210 | print("Creating Cycle Numbers...") |
| 211 | # Get all valid cycle numbers |
| 212 | cycle_numbers = sorted( |
| 213 | df[df["Cycle Number"] > 0]["Cycle Number"].unique() |
| 214 | ) |
| 215 | |
| 216 | for cycle in cycle_numbers: |
| 217 | |
| 218 | # Get only rows for this cycle that are above threshold |
| 219 | cycle_data = df[ |
| 220 | (df["Cycle Number"] == cycle) |
| 221 | & |
| 222 | (df["Above Threshold"] == 1) |
| 223 | ] |
| 224 | |
| 225 | # Skip empty cycles just in case |
| 226 | if len(cycle_data) == 0: |
| 227 | continue |
| 228 | |
| 229 | # Find row with maximum load |
| 230 | peak_index = cycle_data["Load (N)"].idxmax() |
| 231 | |
| 232 | peak_row = df.loc[peak_index] |
| 233 | |
| 234 | peak_summary.append({ |
| 235 | "Cycle Number": cycle, |
| 236 | "Test": peak_row["Test"], |
| 237 | "Peak Load (N)": peak_row["Load (N)"], |
| 238 | "Peak Extension (mm)": peak_row[extension_column], |
| 239 | "Peak Time (s)": peak_row["Continuous Time (s)"], |
| 240 | "Peak Row": peak_index |
| 241 | }) |
| 242 | |
| 243 | # --------------------------------------------------------- |
| 244 | # STEP 12 - Create dataframe |
| 245 | # --------------------------------------------------------- |
| 246 | |
| 247 | peak_df = pd.DataFrame(peak_summary) |
| 248 | |
| 249 | # --------------------------------------------------------- |
| 250 | # STEP 13 - Save peak summary |
| 251 | # --------------------------------------------------------- |
| 252 | print("Saving peak summary...") |
| 253 | peak_output_file = ( |
| 254 | f"Spring_{spring_name}_Peaks.csv" |
| 255 | ) |
| 256 | |
| 257 | peak_df.to_csv( |
| 258 | peak_output_file, |
| 259 | index=False |
| 260 | ) |
| 261 | |
| 262 | # Cycles per test count |
| 263 | cycles_per_test = ( |
| 264 | peak_df.groupby("Test").size() |
| 265 | ) |
| 266 | |
| 267 | print("Cycles Per Test:") |
| 268 | |
| 269 | for test, count in cycles_per_test.items(): |
| 270 | print(f"Test {int(test)}: {count}") |
| 271 | |
| 272 | # --------------------------------------------------------- |
| 273 | # STEP 14 - Report results |
| 274 | # --------------------------------------------------------- |
| 275 | |
| 276 | total_cycles = int( |
| 277 | df["Cycle Number"].max() |
| 278 | ) |
| 279 | |
| 280 | print("\nAnalysis Complete") |
| 281 | print( |
| 282 | f"Total Cycles Found: " |
| 283 | f"{total_cycles}" |
| 284 | ) |
| 285 | |
| 286 | print( |
| 287 | f"Total Peaks Found: " |
| 288 | f"{len(peak_summary)}" |
| 289 | ) |
| 290 | |
| 291 | print( |
| 292 | f"Analyzed File: " |
| 293 | f"{output_file}" |
| 294 | ) |
| 295 | |
| 296 | print( |
| 297 | f"Peak Summary File: " |
| 298 | f"{peak_output_file}" |
| 299 | ) |
| 300 | |
| 301 | input("\nPress Enter to exit") |
SpringCleanAndAnalzye2.py
· 11 KiB · Python
Raw
import pandas as pd
import glob
import os
# ---------------------------------------------------------
# STEP 1 - Ask user for settings that apply to all springs
# ---------------------------------------------------------
threshold = float(
input(
"Enter peak detection threshold (mm): "
)
)
# This controls whether the larger intermediate files are saved.
# The cleaned and analyzed DataFrames are still created in memory either way
# because they are needed to calculate the peak summary.
generate_cleaned_analyzed = input(
"Generate cleaned and analyzed files? (y/n): "
).strip().lower()
save_intermediate_files = generate_cleaned_analyzed == "y"
# ---------------------------------------------------------
# STEP 2 - Create list of springs to process
#
# The program will process springs in this order:
#
# 1040_00, 1040_01, ..., 1040_99
# 1090_00, 1090_01, ..., 1090_99
# ---------------------------------------------------------
spring_list = []
for spring_prefix in ["1040", "1090"]:
for spring_number in range(100):
spring_name = f"{spring_prefix}_{spring_number:02d}"
spring_list.append(spring_name)
# ---------------------------------------------------------
# STEP 3 - Function to process one spring
#
# This function does everything your original program did,
# but for one automatically-selected spring instead of one
# manually-entered spring.
# ---------------------------------------------------------
def process_spring(spring_name, threshold, save_intermediate_files):
print()
print("---------------------------------------------------------")
print(f"Checking spring: {spring_name}")
print("---------------------------------------------------------")
# ---------------------------------------------------------
# Find all matching test files for this spring
# ---------------------------------------------------------
file_pattern = f"Spring_{spring_name}_Test_*.csv"
file_list = glob.glob(file_pattern)
# Make sure files are processed in order.
# This is important because Test 1 should come before Test 2, etc.
file_list.sort()
# If this spring has no matching files, skip it.
if len(file_list) == 0:
print(f"No files found matching: {file_pattern}")
return
print(f"Found {len(file_list)} file(s).")
# ---------------------------------------------------------
# Variables used while combining files
# ---------------------------------------------------------
combined_data = []
time_offset = 0
# ---------------------------------------------------------
# Process each test file for this spring
# ---------------------------------------------------------
for test_number, file in enumerate(file_list, start=1):
print(f"Processing: {file}")
# Read CSV
df = pd.read_csv(file)
# Remove rows containing empty data
df = df.dropna()
# Time column name
time_column = "Time (s)"
# Create Test column.
# This assigns Test 1, Test 2, Test 3, etc. based on file order.
df["Test"] = test_number
# Create continuous time column.
# This makes the time from multiple files act like one continuous test.
df["Continuous Time (s)"] = df[time_column] + time_offset
# Determine ending time for next test.
# The next file's time starts where this one ended.
last_time = df[time_column].iloc[-1]
time_offset += last_time
# Store cleaned data in memory.
combined_data.append(df)
# ---------------------------------------------------------
# Combine all tests into one DataFrame
# ---------------------------------------------------------
final_df = pd.concat(combined_data, ignore_index=True)
# ---------------------------------------------------------
# Save cleaned data only if user selected yes
# ---------------------------------------------------------
cleaned_output_file = f"Spring_{spring_name}_Cleaned.csv"
if save_intermediate_files:
final_df.to_csv(cleaned_output_file, index=False)
print()
print("Finished Cleaning!")
print(f"Cleaned output saved as: {cleaned_output_file}")
else:
print()
print("Finished Cleaning in memory.")
print("Cleaned file was not saved because user selected no.")
# ---------------------------------------------------------------------
# ANALYZING SECTION
# ---------------------------------------------------------------------
# Instead of opening the cleaned file from disk, use final_df directly.
# This allows the analysis to work even when the user chooses not to save
# the cleaned CSV file.
df = final_df.copy()
# ---------------------------------------------------------
# Define important column names
# ---------------------------------------------------------
extension_column = "Extension (mm)"
# ---------------------------------------------------------
# Create Above Threshold flag
#
# 1 = Extension is above threshold
# 0 = Extension is below threshold
# ---------------------------------------------------------
print("Creating Above Threshold...")
df["Above Threshold"] = (
df[extension_column] >= threshold
).astype(int)
# ---------------------------------------------------------
# Create Previous Above Threshold column
#
# Shift the Above Threshold column down by one row.
# This lets each row compare itself to the row before it.
# ---------------------------------------------------------
print("Creating Previous Above Threshold...")
df["Previous Above Threshold"] = (
df["Above Threshold"]
.shift(1)
.fillna(0)
.astype(int)
)
# ---------------------------------------------------------
# Create Rising Edge column
#
# Rising Edge occurs when:
#
# Previous = 0
# Current = 1
#
# This marks the start of a compression cycle.
# ---------------------------------------------------------
print("Creating Rising Edge...")
df["Rising Edge"] = (
(df["Above Threshold"] == 1)
&
(df["Previous Above Threshold"] == 0)
).astype(int)
# ---------------------------------------------------------
# Create Falling Edge column
#
# Falling Edge occurs when:
#
# Previous = 1
# Current = 0
#
# This marks where the signal drops back below the threshold.
# ---------------------------------------------------------
print("Creating Falling Edge...")
df["Falling Edge"] = (
(df["Above Threshold"] == 0)
&
(df["Previous Above Threshold"] == 1)
).astype(int)
# ---------------------------------------------------------
# Create Cycle Number
#
# Every Rising Edge starts a new cycle.
#
# Example:
#
# Rising Edge:
# 0 0 1 0 0 1 0
#
# Cycle Number:
# 0 0 1 1 1 2 2
#
# The cumulative sum increases by 1 every time a rising edge occurs.
# ---------------------------------------------------------
print("Creating Cycle Number...")
df["Cycle Number"] = (
df["Rising Edge"]
.cumsum()
)
# ---------------------------------------------------------
# Save analyzed file only if user selected yes
# ---------------------------------------------------------
analyzed_output_file = f"Spring_{spring_name}_Analyzed.csv"
if save_intermediate_files:
print("Saving Analyzed File...")
df.to_csv(analyzed_output_file, index=False)
print(f"Analyzed output saved as: {analyzed_output_file}")
else:
print("Analyzed file was not saved because user selected no.")
# ---------------------------------------------------------
# Create Peak Summary
# ---------------------------------------------------------
peak_summary = []
print("Creating peak summary...")
# Get all valid cycle numbers.
# Cycle 0 is ignored because it is before the first rising edge.
cycle_numbers = sorted(
df[df["Cycle Number"] > 0]["Cycle Number"].unique()
)
for cycle in cycle_numbers:
# Get only rows for this cycle that are above threshold.
# This searches the active compression portion of the cycle.
cycle_data = df[
(df["Cycle Number"] == cycle)
&
(df["Above Threshold"] == 1)
]
# Skip empty cycles just in case.
if len(cycle_data) == 0:
continue
# Find row with maximum load inside this cycle's above-threshold area.
peak_index = cycle_data["Load (N)"].idxmax()
peak_row = df.loc[peak_index]
peak_summary.append({
"Cycle Number": cycle,
"Test": peak_row["Test"],
"Peak Load (N)": peak_row["Load (N)"],
"Peak Extension (mm)": peak_row[extension_column],
"Peak Time (s)": peak_row["Continuous Time (s)"],
"Peak Row": peak_index
})
# ---------------------------------------------------------
# Create peak summary DataFrame
# ---------------------------------------------------------
peak_df = pd.DataFrame(peak_summary)
# ---------------------------------------------------------
# Save peak summary
#
# This file is always saved because it is the main output.
# ---------------------------------------------------------
print("Saving peak summary...")
peak_output_file = f"Spring_{spring_name}_Peaks.csv"
peak_df.to_csv(
peak_output_file,
index=False
)
# ---------------------------------------------------------
# Report cycles per test
# ---------------------------------------------------------
if len(peak_df) > 0:
cycles_per_test = (
peak_df.groupby("Test").size()
)
print("Cycles Per Test:")
for test, count in cycles_per_test.items():
print(f"Test {int(test)}: {count}")
else:
print("No peaks found for this spring.")
# ---------------------------------------------------------
# Report results
# ---------------------------------------------------------
total_cycles = int(
df["Cycle Number"].max()
)
print()
print("Analysis Complete")
print(f"Spring: {spring_name}")
print(f"Total Cycles Found: {total_cycles}")
print(f"Total Peaks Found: {len(peak_summary)}")
if save_intermediate_files:
print(f"Cleaned File: {cleaned_output_file}")
print(f"Analyzed File: {analyzed_output_file}")
print(f"Peak Summary File: {peak_output_file}")
# ---------------------------------------------------------
# STEP 4 - Run the process for every spring in the list
# ---------------------------------------------------------
for spring_name in spring_list:
process_spring(
spring_name,
threshold,
save_intermediate_files
)
# ---------------------------------------------------------
# STEP 5 - Keep command window open
# ---------------------------------------------------------
print()
print("Finished processing all springs.")
input("\nPress Enter to exit")
| 1 | import pandas as pd |
| 2 | import glob |
| 3 | import os |
| 4 | |
| 5 | |
| 6 | # --------------------------------------------------------- |
| 7 | # STEP 1 - Ask user for settings that apply to all springs |
| 8 | # --------------------------------------------------------- |
| 9 | |
| 10 | threshold = float( |
| 11 | input( |
| 12 | "Enter peak detection threshold (mm): " |
| 13 | ) |
| 14 | ) |
| 15 | |
| 16 | # This controls whether the larger intermediate files are saved. |
| 17 | # The cleaned and analyzed DataFrames are still created in memory either way |
| 18 | # because they are needed to calculate the peak summary. |
| 19 | generate_cleaned_analyzed = input( |
| 20 | "Generate cleaned and analyzed files? (y/n): " |
| 21 | ).strip().lower() |
| 22 | |
| 23 | save_intermediate_files = generate_cleaned_analyzed == "y" |
| 24 | |
| 25 | |
| 26 | # --------------------------------------------------------- |
| 27 | # STEP 2 - Create list of springs to process |
| 28 | # |
| 29 | # The program will process springs in this order: |
| 30 | # |
| 31 | # 1040_00, 1040_01, ..., 1040_99 |
| 32 | # 1090_00, 1090_01, ..., 1090_99 |
| 33 | # --------------------------------------------------------- |
| 34 | |
| 35 | spring_list = [] |
| 36 | |
| 37 | for spring_prefix in ["1040", "1090"]: |
| 38 | for spring_number in range(100): |
| 39 | spring_name = f"{spring_prefix}_{spring_number:02d}" |
| 40 | spring_list.append(spring_name) |
| 41 | |
| 42 | |
| 43 | # --------------------------------------------------------- |
| 44 | # STEP 3 - Function to process one spring |
| 45 | # |
| 46 | # This function does everything your original program did, |
| 47 | # but for one automatically-selected spring instead of one |
| 48 | # manually-entered spring. |
| 49 | # --------------------------------------------------------- |
| 50 | |
| 51 | def process_spring(spring_name, threshold, save_intermediate_files): |
| 52 | |
| 53 | print() |
| 54 | print("---------------------------------------------------------") |
| 55 | print(f"Checking spring: {spring_name}") |
| 56 | print("---------------------------------------------------------") |
| 57 | |
| 58 | # --------------------------------------------------------- |
| 59 | # Find all matching test files for this spring |
| 60 | # --------------------------------------------------------- |
| 61 | |
| 62 | file_pattern = f"Spring_{spring_name}_Test_*.csv" |
| 63 | |
| 64 | file_list = glob.glob(file_pattern) |
| 65 | |
| 66 | # Make sure files are processed in order. |
| 67 | # This is important because Test 1 should come before Test 2, etc. |
| 68 | file_list.sort() |
| 69 | |
| 70 | # If this spring has no matching files, skip it. |
| 71 | if len(file_list) == 0: |
| 72 | print(f"No files found matching: {file_pattern}") |
| 73 | return |
| 74 | |
| 75 | print(f"Found {len(file_list)} file(s).") |
| 76 | |
| 77 | # --------------------------------------------------------- |
| 78 | # Variables used while combining files |
| 79 | # --------------------------------------------------------- |
| 80 | |
| 81 | combined_data = [] |
| 82 | |
| 83 | time_offset = 0 |
| 84 | |
| 85 | # --------------------------------------------------------- |
| 86 | # Process each test file for this spring |
| 87 | # --------------------------------------------------------- |
| 88 | |
| 89 | for test_number, file in enumerate(file_list, start=1): |
| 90 | |
| 91 | print(f"Processing: {file}") |
| 92 | |
| 93 | # Read CSV |
| 94 | df = pd.read_csv(file) |
| 95 | |
| 96 | # Remove rows containing empty data |
| 97 | df = df.dropna() |
| 98 | |
| 99 | # Time column name |
| 100 | time_column = "Time (s)" |
| 101 | |
| 102 | # Create Test column. |
| 103 | # This assigns Test 1, Test 2, Test 3, etc. based on file order. |
| 104 | df["Test"] = test_number |
| 105 | |
| 106 | # Create continuous time column. |
| 107 | # This makes the time from multiple files act like one continuous test. |
| 108 | df["Continuous Time (s)"] = df[time_column] + time_offset |
| 109 | |
| 110 | # Determine ending time for next test. |
| 111 | # The next file's time starts where this one ended. |
| 112 | last_time = df[time_column].iloc[-1] |
| 113 | |
| 114 | time_offset += last_time |
| 115 | |
| 116 | # Store cleaned data in memory. |
| 117 | combined_data.append(df) |
| 118 | |
| 119 | # --------------------------------------------------------- |
| 120 | # Combine all tests into one DataFrame |
| 121 | # --------------------------------------------------------- |
| 122 | |
| 123 | final_df = pd.concat(combined_data, ignore_index=True) |
| 124 | |
| 125 | # --------------------------------------------------------- |
| 126 | # Save cleaned data only if user selected yes |
| 127 | # --------------------------------------------------------- |
| 128 | |
| 129 | cleaned_output_file = f"Spring_{spring_name}_Cleaned.csv" |
| 130 | |
| 131 | if save_intermediate_files: |
| 132 | final_df.to_csv(cleaned_output_file, index=False) |
| 133 | |
| 134 | print() |
| 135 | print("Finished Cleaning!") |
| 136 | print(f"Cleaned output saved as: {cleaned_output_file}") |
| 137 | else: |
| 138 | print() |
| 139 | print("Finished Cleaning in memory.") |
| 140 | print("Cleaned file was not saved because user selected no.") |
| 141 | |
| 142 | # --------------------------------------------------------------------- |
| 143 | # ANALYZING SECTION |
| 144 | # --------------------------------------------------------------------- |
| 145 | |
| 146 | # Instead of opening the cleaned file from disk, use final_df directly. |
| 147 | # This allows the analysis to work even when the user chooses not to save |
| 148 | # the cleaned CSV file. |
| 149 | df = final_df.copy() |
| 150 | |
| 151 | # --------------------------------------------------------- |
| 152 | # Define important column names |
| 153 | # --------------------------------------------------------- |
| 154 | |
| 155 | extension_column = "Extension (mm)" |
| 156 | |
| 157 | # --------------------------------------------------------- |
| 158 | # Create Above Threshold flag |
| 159 | # |
| 160 | # 1 = Extension is above threshold |
| 161 | # 0 = Extension is below threshold |
| 162 | # --------------------------------------------------------- |
| 163 | |
| 164 | print("Creating Above Threshold...") |
| 165 | |
| 166 | df["Above Threshold"] = ( |
| 167 | df[extension_column] >= threshold |
| 168 | ).astype(int) |
| 169 | |
| 170 | # --------------------------------------------------------- |
| 171 | # Create Previous Above Threshold column |
| 172 | # |
| 173 | # Shift the Above Threshold column down by one row. |
| 174 | # This lets each row compare itself to the row before it. |
| 175 | # --------------------------------------------------------- |
| 176 | |
| 177 | print("Creating Previous Above Threshold...") |
| 178 | |
| 179 | df["Previous Above Threshold"] = ( |
| 180 | df["Above Threshold"] |
| 181 | .shift(1) |
| 182 | .fillna(0) |
| 183 | .astype(int) |
| 184 | ) |
| 185 | |
| 186 | # --------------------------------------------------------- |
| 187 | # Create Rising Edge column |
| 188 | # |
| 189 | # Rising Edge occurs when: |
| 190 | # |
| 191 | # Previous = 0 |
| 192 | # Current = 1 |
| 193 | # |
| 194 | # This marks the start of a compression cycle. |
| 195 | # --------------------------------------------------------- |
| 196 | |
| 197 | print("Creating Rising Edge...") |
| 198 | |
| 199 | df["Rising Edge"] = ( |
| 200 | (df["Above Threshold"] == 1) |
| 201 | & |
| 202 | (df["Previous Above Threshold"] == 0) |
| 203 | ).astype(int) |
| 204 | |
| 205 | # --------------------------------------------------------- |
| 206 | # Create Falling Edge column |
| 207 | # |
| 208 | # Falling Edge occurs when: |
| 209 | # |
| 210 | # Previous = 1 |
| 211 | # Current = 0 |
| 212 | # |
| 213 | # This marks where the signal drops back below the threshold. |
| 214 | # --------------------------------------------------------- |
| 215 | |
| 216 | print("Creating Falling Edge...") |
| 217 | |
| 218 | df["Falling Edge"] = ( |
| 219 | (df["Above Threshold"] == 0) |
| 220 | & |
| 221 | (df["Previous Above Threshold"] == 1) |
| 222 | ).astype(int) |
| 223 | |
| 224 | # --------------------------------------------------------- |
| 225 | # Create Cycle Number |
| 226 | # |
| 227 | # Every Rising Edge starts a new cycle. |
| 228 | # |
| 229 | # Example: |
| 230 | # |
| 231 | # Rising Edge: |
| 232 | # 0 0 1 0 0 1 0 |
| 233 | # |
| 234 | # Cycle Number: |
| 235 | # 0 0 1 1 1 2 2 |
| 236 | # |
| 237 | # The cumulative sum increases by 1 every time a rising edge occurs. |
| 238 | # --------------------------------------------------------- |
| 239 | |
| 240 | print("Creating Cycle Number...") |
| 241 | |
| 242 | df["Cycle Number"] = ( |
| 243 | df["Rising Edge"] |
| 244 | .cumsum() |
| 245 | ) |
| 246 | |
| 247 | # --------------------------------------------------------- |
| 248 | # Save analyzed file only if user selected yes |
| 249 | # --------------------------------------------------------- |
| 250 | |
| 251 | analyzed_output_file = f"Spring_{spring_name}_Analyzed.csv" |
| 252 | |
| 253 | if save_intermediate_files: |
| 254 | print("Saving Analyzed File...") |
| 255 | |
| 256 | df.to_csv(analyzed_output_file, index=False) |
| 257 | |
| 258 | print(f"Analyzed output saved as: {analyzed_output_file}") |
| 259 | else: |
| 260 | print("Analyzed file was not saved because user selected no.") |
| 261 | |
| 262 | # --------------------------------------------------------- |
| 263 | # Create Peak Summary |
| 264 | # --------------------------------------------------------- |
| 265 | |
| 266 | peak_summary = [] |
| 267 | |
| 268 | print("Creating peak summary...") |
| 269 | |
| 270 | # Get all valid cycle numbers. |
| 271 | # Cycle 0 is ignored because it is before the first rising edge. |
| 272 | cycle_numbers = sorted( |
| 273 | df[df["Cycle Number"] > 0]["Cycle Number"].unique() |
| 274 | ) |
| 275 | |
| 276 | for cycle in cycle_numbers: |
| 277 | |
| 278 | # Get only rows for this cycle that are above threshold. |
| 279 | # This searches the active compression portion of the cycle. |
| 280 | cycle_data = df[ |
| 281 | (df["Cycle Number"] == cycle) |
| 282 | & |
| 283 | (df["Above Threshold"] == 1) |
| 284 | ] |
| 285 | |
| 286 | # Skip empty cycles just in case. |
| 287 | if len(cycle_data) == 0: |
| 288 | continue |
| 289 | |
| 290 | # Find row with maximum load inside this cycle's above-threshold area. |
| 291 | peak_index = cycle_data["Load (N)"].idxmax() |
| 292 | |
| 293 | peak_row = df.loc[peak_index] |
| 294 | |
| 295 | peak_summary.append({ |
| 296 | "Cycle Number": cycle, |
| 297 | "Test": peak_row["Test"], |
| 298 | "Peak Load (N)": peak_row["Load (N)"], |
| 299 | "Peak Extension (mm)": peak_row[extension_column], |
| 300 | "Peak Time (s)": peak_row["Continuous Time (s)"], |
| 301 | "Peak Row": peak_index |
| 302 | }) |
| 303 | |
| 304 | # --------------------------------------------------------- |
| 305 | # Create peak summary DataFrame |
| 306 | # --------------------------------------------------------- |
| 307 | |
| 308 | peak_df = pd.DataFrame(peak_summary) |
| 309 | |
| 310 | # --------------------------------------------------------- |
| 311 | # Save peak summary |
| 312 | # |
| 313 | # This file is always saved because it is the main output. |
| 314 | # --------------------------------------------------------- |
| 315 | |
| 316 | print("Saving peak summary...") |
| 317 | |
| 318 | peak_output_file = f"Spring_{spring_name}_Peaks.csv" |
| 319 | |
| 320 | peak_df.to_csv( |
| 321 | peak_output_file, |
| 322 | index=False |
| 323 | ) |
| 324 | |
| 325 | # --------------------------------------------------------- |
| 326 | # Report cycles per test |
| 327 | # --------------------------------------------------------- |
| 328 | |
| 329 | if len(peak_df) > 0: |
| 330 | |
| 331 | cycles_per_test = ( |
| 332 | peak_df.groupby("Test").size() |
| 333 | ) |
| 334 | |
| 335 | print("Cycles Per Test:") |
| 336 | |
| 337 | for test, count in cycles_per_test.items(): |
| 338 | print(f"Test {int(test)}: {count}") |
| 339 | |
| 340 | else: |
| 341 | print("No peaks found for this spring.") |
| 342 | |
| 343 | # --------------------------------------------------------- |
| 344 | # Report results |
| 345 | # --------------------------------------------------------- |
| 346 | |
| 347 | total_cycles = int( |
| 348 | df["Cycle Number"].max() |
| 349 | ) |
| 350 | |
| 351 | print() |
| 352 | print("Analysis Complete") |
| 353 | print(f"Spring: {spring_name}") |
| 354 | print(f"Total Cycles Found: {total_cycles}") |
| 355 | print(f"Total Peaks Found: {len(peak_summary)}") |
| 356 | |
| 357 | if save_intermediate_files: |
| 358 | print(f"Cleaned File: {cleaned_output_file}") |
| 359 | print(f"Analyzed File: {analyzed_output_file}") |
| 360 | |
| 361 | print(f"Peak Summary File: {peak_output_file}") |
| 362 | |
| 363 | |
| 364 | # --------------------------------------------------------- |
| 365 | # STEP 4 - Run the process for every spring in the list |
| 366 | # --------------------------------------------------------- |
| 367 | |
| 368 | for spring_name in spring_list: |
| 369 | process_spring( |
| 370 | spring_name, |
| 371 | threshold, |
| 372 | save_intermediate_files |
| 373 | ) |
| 374 | |
| 375 | |
| 376 | # --------------------------------------------------------- |
| 377 | # STEP 5 - Keep command window open |
| 378 | # --------------------------------------------------------- |
| 379 | |
| 380 | print() |
| 381 | print("Finished processing all springs.") |
| 382 | |
| 383 | input("\nPress Enter to exit") |
errors.txt
· 1.9 KiB · Text
Raw
---------------------------------------------------------
Checking spring: 1090_02
---------------------------------------------------------
Found 3 file(s).
Processing: Spring_1090_02_Test_01.csv
Processing: Spring_1090_02_Test_02.csv
Processing: Spring_1090_02_Test_03.csv
Finished Cleaning in memory.
Cleaned file was not saved because user selected no.
Creating Above Threshold...
Traceback (most recent call last):
File "C:\Users\wdsch\AppData\Roaming\Python\Python314\site-packages\pandas\core\indexes\base.py", line 3641, in get_loc
return self._engine.get_loc(casted_key)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
File "pandas/_libs/index.pyx", line 168, in pandas._libs.index.IndexEngine.get_loc
File "pandas/_libs/index.pyx", line 197, in pandas._libs.index.IndexEngine.get_loc
File "pandas/_libs/hashtable_class_helper.pxi", line 7668, in pandas._libs.hashtable.PyObjectHashTable.get_item
File "pandas/_libs/hashtable_class_helper.pxi", line 7676, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 'Extension (mm)'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "c:\Users\wdsch\OneDrive\Documents\Halozyme\Spring Python\SpringCleanAndAnalyze.py", line 369, in <module>
process_spring(
~~~~~~~~~~~~~~^
spring_name,
^^^^^^^^^^^^
threshold,
^^^^^^^^^^
save_intermediate_files
^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "c:\Users\wdsch\OneDrive\Documents\Halozyme\Spring Python\SpringCleanAndAnalyze.py", line 167, in process_spring
df[extension_column] >= threshold
~~^^^^^^^^^^^^^^^^^^
File "C:\Users\wdsch\AppData\Roaming\Python\Python314\site-packages\pandas\core\frame.py", line 4378, in __getitem__
indexer = self.columns.get_loc(key)
File "C:\Users\wdsch\AppData\Roaming\Python\Python314\site-packages\pandas\core\indexes\base.py", line 3648, in get_loc
raise KeyError(key) from err
KeyError: 'Extension (mm)'
| 1 | --------------------------------------------------------- |
| 2 | Checking spring: 1090_02 |
| 3 | --------------------------------------------------------- |
| 4 | Found 3 file(s). |
| 5 | Processing: Spring_1090_02_Test_01.csv |
| 6 | Processing: Spring_1090_02_Test_02.csv |
| 7 | Processing: Spring_1090_02_Test_03.csv |
| 8 | |
| 9 | Finished Cleaning in memory. |
| 10 | Cleaned file was not saved because user selected no. |
| 11 | Creating Above Threshold... |
| 12 | Traceback (most recent call last): |
| 13 | File "C:\Users\wdsch\AppData\Roaming\Python\Python314\site-packages\pandas\core\indexes\base.py", line 3641, in get_loc |
| 14 | return self._engine.get_loc(casted_key) |
| 15 | ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^ |
| 16 | File "pandas/_libs/index.pyx", line 168, in pandas._libs.index.IndexEngine.get_loc |
| 17 | File "pandas/_libs/index.pyx", line 197, in pandas._libs.index.IndexEngine.get_loc |
| 18 | File "pandas/_libs/hashtable_class_helper.pxi", line 7668, in pandas._libs.hashtable.PyObjectHashTable.get_item |
| 19 | File "pandas/_libs/hashtable_class_helper.pxi", line 7676, in pandas._libs.hashtable.PyObjectHashTable.get_item |
| 20 | KeyError: 'Extension (mm)' |
| 21 | |
| 22 | The above exception was the direct cause of the following exception: |
| 23 | |
| 24 | Traceback (most recent call last): |
| 25 | File "c:\Users\wdsch\OneDrive\Documents\Halozyme\Spring Python\SpringCleanAndAnalyze.py", line 369, in <module> |
| 26 | process_spring( |
| 27 | ~~~~~~~~~~~~~~^ |
| 28 | spring_name, |
| 29 | ^^^^^^^^^^^^ |
| 30 | threshold, |
| 31 | ^^^^^^^^^^ |
| 32 | save_intermediate_files |
| 33 | ^^^^^^^^^^^^^^^^^^^^^^^ |
| 34 | ) |
| 35 | ^ |
| 36 | File "c:\Users\wdsch\OneDrive\Documents\Halozyme\Spring Python\SpringCleanAndAnalyze.py", line 167, in process_spring |
| 37 | df[extension_column] >= threshold |
| 38 | ~~^^^^^^^^^^^^^^^^^^ |
| 39 | File "C:\Users\wdsch\AppData\Roaming\Python\Python314\site-packages\pandas\core\frame.py", line 4378, in __getitem__ |
| 40 | indexer = self.columns.get_loc(key) |
| 41 | File "C:\Users\wdsch\AppData\Roaming\Python\Python314\site-packages\pandas\core\indexes\base.py", line 3648, in get_loc |
| 42 | raise KeyError(key) from err |
| 43 | KeyError: 'Extension (mm)' |