Last active 4 days ago

Revision 42b6ef8b2ece818efd39efb4671658b43b4851e0

This file can't be rendered. View the full file.
SpringCleanAndAnalyze.py Raw
1import pandas as pd
2import glob
3import os
4
5
6# ---------------------------------------------------------
7# STEP 1 - Ask user which spring to process
8# ---------------------------------------------------------
9spring_name = input("Enter spring number (example: 1040_01): ").strip()
10
11threshold = float(
12 input(
13 "Enter peak detection threshold (mm): "
14 )
15)
16
17
18# ---------------------------------------------------------
19# STEP 2 - Find all matching test files
20# ---------------------------------------------------------
21file_pattern = f"Spring_{spring_name}_Test_*.csv"
22
23file_list = glob.glob(file_pattern)
24
25# Make sure files are processed in order
26file_list.sort()
27
28if 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# ---------------------------------------------------------
36combined_data = []
37
38time_offset = 0
39
40
41# ---------------------------------------------------------
42# STEP 4 - Process each test file
43# ---------------------------------------------------------
44for 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# ---------------------------------------------------------
75final_df = pd.concat(combined_data, ignore_index=True)
76
77
78# ---------------------------------------------------------
79# STEP 6 - Create output filename
80# ---------------------------------------------------------
81output_file = f"Spring_{spring_name}_Cleaned.csv"
82
83
84# ---------------------------------------------------------
85# STEP 7 - Save cleaned data
86# ---------------------------------------------------------
87final_df.to_csv(output_file, index=False)
88
89print()
90print(f"Finished Cleaning!")
91print(f"Output saved as: {output_file}")
92
93
94# ---------------------------------------------------------------------
95# ANALYZING SECTION
96# ---------------------------------------------------------------------
97
98
99# ---------------------------------------------------------
100# STEP 2 - Open cleaned file
101# ---------------------------------------------------------
102
103input_file = f"Spring_{spring_name}_Cleaned.csv"
104
105print(f"\nLoading {input_file}...")
106
107df = pd.read_csv(input_file)
108
109
110# ---------------------------------------------------------
111# STEP 3 - Define important column names
112# ---------------------------------------------------------
113
114extension_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# ---------------------------------------------------------
123print("Creating Above Threshold...")
124df["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# ---------------------------------------------------------
134print("Creating Previous Above Threshold...")
135df["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# ---------------------------------------------------------
151print("Creating Rising Edge...")
152df["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# ---------------------------------------------------------
167print("Creating Falling Edge...")
168df["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# ---------------------------------------------------------
188print("Creating Cycle Number...")
189df["Cycle Number"] = (
190 df["Rising Edge"]
191 .cumsum()
192)
193
194
195# ---------------------------------------------------------
196# STEP 9 - Save analyzed file
197# ---------------------------------------------------------
198print("Saving Analyzed File...")
199output_file = f"Spring_{spring_name}_Analyzed.csv"
200
201df.to_csv(output_file, index=False)
202
203
204# ---------------------------------------------------------
205# STEP 11 - Create Peak Summary
206# ---------------------------------------------------------
207
208peak_summary = []
209
210print("Creating Cycle Numbers...")
211# Get all valid cycle numbers
212cycle_numbers = sorted(
213 df[df["Cycle Number"] > 0]["Cycle Number"].unique()
214)
215
216for 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
247peak_df = pd.DataFrame(peak_summary)
248
249# ---------------------------------------------------------
250# STEP 13 - Save peak summary
251# ---------------------------------------------------------
252print("Saving peak summary...")
253peak_output_file = (
254 f"Spring_{spring_name}_Peaks.csv"
255)
256
257peak_df.to_csv(
258 peak_output_file,
259 index=False
260)
261
262# Cycles per test count
263cycles_per_test = (
264 peak_df.groupby("Test").size()
265)
266
267print("Cycles Per Test:")
268
269for test, count in cycles_per_test.items():
270 print(f"Test {int(test)}: {count}")
271
272# ---------------------------------------------------------
273# STEP 14 - Report results
274# ---------------------------------------------------------
275
276total_cycles = int(
277 df["Cycle Number"].max()
278)
279
280print("\nAnalysis Complete")
281print(
282 f"Total Cycles Found: "
283 f"{total_cycles}"
284)
285
286print(
287 f"Total Peaks Found: "
288 f"{len(peak_summary)}"
289)
290
291print(
292 f"Analyzed File: "
293 f"{output_file}"
294)
295
296print(
297 f"Peak Summary File: "
298 f"{peak_output_file}"
299)
300
301input("\nPress Enter to exit")
SpringCleanAndAnalzye2.py Raw
1import pandas as pd
2import glob
3import os
4
5
6# ---------------------------------------------------------
7# STEP 1 - Ask user for settings that apply to all springs
8# ---------------------------------------------------------
9
10threshold = 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.
19generate_cleaned_analyzed = input(
20 "Generate cleaned and analyzed files? (y/n): "
21).strip().lower()
22
23save_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
35spring_list = []
36
37for 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
51def 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
368for 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
380print()
381print("Finished processing all springs.")
382
383input("\nPress Enter to exit")
errors.txt Raw
1---------------------------------------------------------
2Checking spring: 1090_02
3---------------------------------------------------------
4Found 3 file(s).
5Processing: Spring_1090_02_Test_01.csv
6Processing: Spring_1090_02_Test_02.csv
7Processing: Spring_1090_02_Test_03.csv
8
9Finished Cleaning in memory.
10Cleaned file was not saved because user selected no.
11Creating Above Threshold...
12Traceback (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
20KeyError: 'Extension (mm)'
21
22The above exception was the direct cause of the following exception:
23
24Traceback (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
43KeyError: 'Extension (mm)'