Compare commits

...

217 Commits

Author SHA1 Message Date
Rifqi D. Panuluh
6f83033fc0 feat: major chapter 4 2025-10-12 14:36:48 +00:00
Rifqi D. Panuluh
8fe7fb2d89 feat: chapter 3 figures 2025-10-10 19:40:03 +00:00
Rifqi D. Panuluh
6b629f6f7d fix(images): Update datalogger and specimen images for improved clarity 2025-10-10 02:39:27 +00:00
Rifqi D. Panuluh
0217abfb88 WIP: checkpoint methodology 2025-10-10 02:25:29 +00:00
Rifqi D. Panuluh
01c2a9d232 feat(latex): Add content for data acquisition, model development, and hyperparameter optimization in methodology chapter 2025-10-06 08:15:32 +00:00
Rifqi D. Panuluh
3258cd2e82 fix(latex): Add SmallCapsFont fallback for pseudocode package that use \textsc in Times New Roman 2025-10-05 11:25:52 +00:00
Rifqi D. Panuluh
9412f0f53f fix(latex): Fix the steps flow to follow common practice and reformat writing style 2025-09-06 04:28:57 +00:00
Rifqi D. Panuluh
d844fb8f66 fix(latex): Update damaged/undamaged figure references and captions for clarity in methodology section and optimize figures with guetzli 2025-09-06 04:26:01 +00:00
Rifqi D. Panuluh
b581b3c755 refactor(latex): Refactor chapter 3 to remove section headers from data analysis and materials files and optimize figures with guetzli 2025-09-06 04:23:31 +00:00
Rifqi D. Panuluh
9fc5da03c1 feat(gitattributes): Add LFS support for JPG, JPEG, and PDF files 2025-09-05 11:01:23 +00:00
Rifqi D. Panuluh
ebb2c0d686 refactor(latex): Refactor chapter 3 2025-09-05 10:57:00 +00:00
Rifqi D. Panuluh
c2f48694c9 Merge branch 'dev' of https://github.com/nuluh/thesis into dev 2025-08-30 00:24:05 +00:00
nuluh
f2d427f0e8 feat(gitattributes): Add LFS filters for SVG and PNG files 2025-08-29 10:49:18 +07:00
nuluh
cf4bdd43cd feat(notebooks): Enhance STFT preview functionality and improve plotting
- Updated `preview_stft` function to accept both DataFrame and list of DataFrames.
- Added support for multiple subplots when a list of DataFrames is provided.
- Improved color mapping and axis labeling in plots.
- Adjusted figure saving options for better output formats.
- Refactored code to reduce redundancy in plotting logic for Sensor A and Sensor B.
- Added predictions using SVM models for processed data.
2025-08-29 10:48:49 +07:00
Rifqi D. Panuluh
7ee6231017 Merge pull request #107 from nuluh/exp/74-exp-cross-dataset-validation
Exp/74 exp cross dataset validation
2025-08-28 12:09:16 +07:00
nuluh
b2bf1b0e31 feat(notebooks): Add type hints for data lists, create preview function for STFT visualization, and save plot for Sensor B. Introduce test section with AU data processing. 2025-08-28 10:39:56 +07:00
nuluh
7a7b2a41af fix(notebooks): update variable names for clarity and add timing evaluation for model predictions on Dataset B 2025-08-28 10:39:55 +07:00
nuluh
3ef656dd28 refactor(notebooks): remove redundant confusion matrix code for Sensor A and update reporting for Sensor B 2025-08-28 10:32:32 +07:00
Rifqi D. Panuluh
18edaaa7c9 refactor(latex): refactor introduction and results chapters to localization directory 2025-08-23 01:55:23 +00:00
nuluh
f45614b6d9 fix(notebooks): update import statement for hann function and add window variable display 2025-08-20 08:03:22 +07:00
nuluh
e2a4c80d49 Merge branch 'feat/103-feat-inference-function' into dev 2025-08-19 06:05:32 +07:00
Damar
d126559920 Merge pull request #105 from nuluh/feature/101-feat-time-elapsed-for-training-and-inference
Feat time elapsed for training and inference
2025-08-18 05:55:36 +07:00
nuluh
855114d633 refactor(notebooks): clean up imports, adjust damage case processing, and improve model training structure
- Removed unnecessary imports (os, pandas, numpy) from the STFT notebook.
- Adjusted the number of damage cases in the multiprocessing pool to correctly reflect the range.
- Updated model training code for Sensor B to ensure consistent naming and structure.
- Cleaned up commented-out code for clarity and maintainability.
2025-08-17 23:39:57 +07:00
nuluh
4a1c0ed83e feat(src): implement inference function with damage probability calculations and visualization
Closes #103
2025-08-17 22:21:17 +07:00
nuluh
274cd60d27 refactor(src): update generate_df_tuples function signature to include type hints for better clarity 2025-08-11 18:49:41 +07:00
nuluh
9f23d82fab fix(src): correct file writing method in process.stft.process_damage_case function to fix incorrect first column name
Closes #104
2025-08-11 13:17:46 +07:00
nuluh
a8288b1426 refactor(src): enhance compute_stft function with type hints, improved documentation by moving column renaming process from process_damage_case to compute_stft 2025-08-11 13:15:48 +07:00
nuluh
860542f3f9 refactor(src): restructure compute_stft function to be pure function and include return parameters and improve clarity 2025-08-10 20:02:45 +07:00
Rifqi D. Panuluh
e2cfd0329f feat(latex): modify \backmatter to change page numbering to roman while preserving frontmatter page count 2025-08-07 22:49:05 +00:00
Rifqi D. Panuluh
e183040c13 fix(latex): add heading to bibliography for inclusion in table of contents 2025-08-07 22:49:05 +00:00
Rifqi D. Panuluh
da5192a315 fix(latex): replace \input with \include and add [titles] options to tocloft package to automatically give \clearpage 2025-08-07 22:49:04 +00:00
Rifqi D. Panuluh
79da2e7bcc fix(chapters): correct capitalization in chapter titles 2025-08-07 22:49:04 +00:00
Rifqi D. Panuluh
5a9cc9eb06 chore(.gitignore): add latex build directory to ignore list 2025-08-07 22:49:04 +00:00
Rifqi D. Panuluh
7a447893cc fix(settings): update LaTeX output directory and use latexmk (xelatex) as default 2025-08-07 22:49:04 +00:00
Rifqi D. Panuluh
432d00b699 fix(settings): correct JSON formatting in VSCode settings 2025-08-07 22:49:04 +00:00
Rifqi D. Panuluh
16c171fb46 latex: Match with Overleaf current work 2025-08-07 22:49:04 +00:00
nuluh
0e28ed6dd0 feat(notebooks): add cross-dataset validation for Sensor A and Sensor B models
Closes #74
2025-07-28 16:41:54 +07:00
nuluh
3e2b153d11 refactor(stft): comment out unused imports and update SVM model loading for consistency 2025-07-28 05:22:24 +07:00
nuluh
3cbef17b0c feat(model_selection): add timing for model training and validation processes 2025-07-28 05:20:10 +07:00
Rifqi D. Panuluh
80d4a66925 Merge pull request #100 from nuluh/feature/99-exp-alternative-undamage-case-data
[EXP] Alterntive Undamage Case Data
2025-07-24 18:09:05 +07:00
nuluh
9b018efc15 refactor(notebooks): update STFT notebook to improve clarity and structure of sensor evaluation sections 2025-07-24 17:00:31 +07:00
nuluh
2fbdeac1eb refactor(test): update import statement to use data_preprocessing module 2025-07-18 19:29:02 +07:00
nuluh
086032c250 refactor(notebooks): clean up to be more readable notebooks 2025-07-18 19:28:43 +07:00
nuluh
f6c71739df refactor(ml): clean up model_selection.py by removing unused code and improving function structure 2025-07-18 19:27:46 +07:00
Rifqi D. Panuluh
2dc915949b chore(.gitignore): add additional LaTeX file types to ignore list 2025-07-17 14:05:59 +00:00
nuluh
18824e05c0 refactor(ml): update inference calls to use new model structure and improve clarity 2025-07-17 00:18:01 +07:00
nuluh
2504157b29 feat(src): replace convert.py to src/data_preprocessing.py and fix some functions prefix parameter 2025-07-02 03:25:18 +07:00
nuluh
5ba628b678 refactor(src): make compute_stft and process_damage_case to be pure function that explicitly need STFT arguments to be passed 2025-07-01 14:32:52 +07:00
nuluh
a93adc8af3 feat(notebooks): minimize stft.ipynb notebooks and add STFT data preview plot.
- Consolidated import statements for pandas and matplotlib.
- Updated STFT plotting for Sensor 1 and Sensor 2 datasets with improved visualization using pcolormesh.
- Enhanced subplot organization for better clarity in visual representation.
- Added titles and adjusted layout for all plots.
2025-06-30 01:36:44 +07:00
nuluh
c2df42cc2b feat(ml): add XGBoost model to inference options and update commented inference calls 2025-06-27 10:35:27 +07:00
nuluh
465ed121f9 feat(notebooks): training model with new alternative undamaged (label 0) data 2025-06-27 10:34:23 +07:00
nuluh
d6975b4817 feat(src): update damage base path and adjust test run logic for damage case processing for undamage case new method 2025-06-27 10:33:54 +07:00
nuluh
79070921d7 feat(data): add complement_pairs function to generate complement tuples for implementing alternative undamage case method 2025-06-27 10:33:36 +07:00
nuluh
e8eb07a91b refactor(data): improve variable naming in generate_df_tuples function for clarity 2025-06-26 10:53:10 +07:00
nuluh
c98c6a091b refactor(data): update generate_df_tuples function for improved readibility code 2025-06-26 10:51:29 +07:00
nuluh
9921d7663b feat(src): add inference script for model evaluation 2025-06-24 14:08:38 +07:00
nuluh
459fbcc17a refactor(notebooks): visualization for sensor analysis and streamline data processing 2025-06-24 14:08:02 +07:00
nuluh
5041ee3feb feat(src): add confusion matrix plotting and label percentage calculation 2025-06-24 14:06:56 +07:00
nuluh
114ab849b9 feat(src): Add confusion matrix plotting function for model evaluation 2025-06-24 00:27:15 +07:00
nuluh
6196523ea0 feat(notebooks): Add confusion matrix plotting loop for Sensor 1 models 2025-06-21 01:10:03 +07:00
Rifqi D. Panuluh
46b66e0a90 Merge pull request #98 from nuluh/feat/53-feat-include-undamaged-node-classification
Closes #53
2025-06-18 09:06:04 +07:00
nuluh
18892c1188 WIP(notebooks): Add SVM with StandardScaler and PCA to sensor model definitions 2025-06-18 08:31:55 +07:00
nuluh
d0b603ba9f fix(data): Update DataProcessor instantiation for new data preprocessing implementation 2025-06-18 08:30:12 +07:00
nuluh
a7d8f1ef56 fix(data): Fix pool mapping to include undamaged case and add csv header separator line for Excel compatibility 2025-06-18 08:25:01 +07:00
nuluh
1164627bac fix(data): Fix export_to_csv to adapt new added undamaged scenario and add new parameter include_time to include 'Time' data 2025-06-18 01:54:12 +07:00
nuluh
58a672a680 fix(data): Fix generate_df_tuples function output bug when special_groups args is passed 2025-06-17 13:20:27 +07:00
nuluh
24c1484300 feat(data): Enhance DataProcessor to support dynamic base path and improve data loading with error handling and memory efficiency 2025-06-16 17:35:27 +07:00
nuluh
60ff4e0fa9 feat(data): Propose new damage file index generation to improve structure and flexibility in DataFrame handling 2025-06-16 03:13:07 +07:00
nuluh
3e652accfb refactor(data): remove unnecessary variable declaration in DataProcessor for loading dataframes 2025-06-14 04:02:42 +07:00
nuluh
66a09e0ddf feat(data): Enhance damage file index generation with undamaged file handling and improved error management (WIP) 2025-06-14 04:02:42 +07:00
nuluh
195f8143f0 refactor(data): remove redundant column extraction method and simplify dataframe loading 2025-06-14 00:57:54 +07:00
nuluh
e7332252a6 Merge branch 'feat/90-feat-preserve-trained-model' into dev 2025-06-12 03:38:15 +07:00
nuluh
4b0819f94e feat(notebooks): Enhance STFT notebook and model selection functionality
- Updated paths in the STFT notebook to reflect new data files.
- Improved plotting aesthetics for combined plots and added grid lines.
- Introduced a 3D spectrogram visualization for better data representation.
- Refactored model training function to include error handling and model export functionality.
- Adjusted model training calls to include export paths for saved models. Closes #90
- Added additional markdown cells for better documentation and clarity in the notebook.
2025-06-12 03:35:21 +07:00
nuluh
7613c08ebd feat(figures): add data preprocessing illustration diagram 2025-06-10 17:21:49 +07:00
nuluh
ad6cda4270 fix(notebooks): update sensor data paths and improve plotting aesthetics 2025-06-10 17:20:13 +07:00
nuluh
ebaa263781 chore(convert): comment out create_damage_files obsolete function 2025-06-09 18:59:51 +07:00
nuluh
f5dada1b9c fix(latex): fix image path for flowchart in methodology section 2025-06-04 15:59:13 +07:00
nuluh
37c9a0765a fix(documentclass): remove language option from biblatex package 2025-06-04 15:53:57 +07:00
nuluh
8656289a1c chore(documentclass): comment out table of contents for temporary removal 2025-06-04 15:53:35 +07:00
nuluh
15fe8339ec feat(documentclass): add new glossary for notation 2025-06-04 15:31:00 +07:00
nuluh
44210ef372 chore(latex): comment out maketitle inputs for temporary 2025-06-04 11:27:56 +07:00
nuluh
9192d4c81c chore(documentclass): remove commented-out code for chapter formatting and header layout 2025-06-03 21:37:32 +07:00
nuluh
0373743ca7 fix(documentclass): enhance dot separation in ToC and add prefixes for figures and tables 2025-06-03 21:34:05 +07:00
nuluh
49d6395e6f fix(documentclass): add missing \RequirePackage{titling} for maketitle formatting 2025-06-03 21:16:34 +07:00
nuluh
bf9cca2d90 feat(documentclass): redefine metadata information to main.tex by consdolidate internal command inside thesis.cls and remove metadata.tex
Closes #96
2025-06-03 21:13:28 +07:00
nuluh
08420296e6 fix(documentclass): add missing \makeatother command to properly close the @ symbol 2025-06-03 20:59:11 +07:00
nuluh
1540213eec feat(documentclass): add commands for bilingual terms and acronyms with custom glossary entries 2025-06-03 20:58:18 +07:00
nuluh
6fd4b7465e feat(documentclass): add new glossary style 'supercol' for enhanced acronym formatting
Closes #85
2025-06-03 20:55:26 +07:00
nuluh
85a0aebf36 feat(documentclass): add custom glossary style 'altlong3customheader' for notation with three-column layout
Closes #95
2025-06-03 20:54:45 +07:00
nuluh
8d1edfdbf7 feat(glossaries): add glossary support with custom style for main glossaries entry and location header
Closes 84
2025-06-03 20:52:54 +07:00
nuluh
ff862d9467 fix(documentclass): adjust page layout by increasing left margin to 4cm 2025-06-03 20:39:03 +07:00
nuluh
dfb64db1d8 feat(documentclass): add draft watermark and optional line numbering with 'draftmark' option 2025-06-03 20:37:29 +07:00
Rifqi D. Panuluh
3e3de577ba Merge pull request #94 from nuluh/latex/91-bug-expose-maketitle
Maketitle Replaced with \input for Flexibility when integrated with latexdiff-latexpand Workflow
2025-06-03 20:16:30 +07:00
nuluh
76a09c0219 refactor(documentclass): update title handling by using input files for maketitle
Closes #91
2025-06-03 19:17:08 +07:00
nuluh
1a994fd59c fix(documentclass): restore and customize English bibliography strings 2025-06-03 19:10:01 +07:00
nuluh
cdb3010b78 fix(documentclass): fix redefined bibliography strings error 2025-06-03 19:05:43 +07:00
nuluh
8a3c1ae585 refactor(main): comment out unused input sections and update chapter includes 2025-06-03 16:37:15 +07:00
nuluh
7b934d3fba fix(acknowledgement): fix file naming 2025-06-03 15:02:12 +07:00
nuluh
aaccad7ae8 feat(glossaries): wip 2025-06-01 16:47:32 +07:00
Rifqi D. Panuluh
2c453ec403 Merge pull request #89 from nuluh/feature/88-refactor-training-cell
Closes #88
2025-05-29 23:04:24 +07:00
nuluh
7da3179d08 refactor(nb): Create and implement helper function train_and_evaluate_model 2025-05-29 22:57:28 +07:00
nuluh
254b24cb21 feat(viz): Update plotting for STFT data visualization with color map 'jet' and added color bar 2025-05-29 20:35:35 +07:00
Rifqi D. Panuluh
d151062115 Add Working Milestone with Initial Results and Model Inference (#82)
* wip: add function to create stratified train-test split from STFT data

* feat(src): implement working function for dataset B to create ready data from STFT files stft_files and add setup.py for package configuration

* feat(notebook): Update variable names for clarity, remove unused imports, and streamline data processing. Implement data concatenation using pandas concat for efficiency. Add validation steps for Dataset B and improve model training consistency across sensors.

* fix(.gitignore): add rule to ignore egg-info directories and ensure proper formatting

* docs(README): add instructions for running stft.ipynb notebook

* feat(notebook): Add evaluation metrics and confusion matrix visualizations for model predictions on Dataset B. Remove commented-out code and integrate data preparation using create_ready_data function.

---------

Co-authored-by: nuluh <dam.ar@outlook.com>
2025-05-24 01:30:10 +07:00
nuluh
a32415cebf feat: Update title page and add secondary title page template 2025-05-23 21:17:12 +07:00
nuluh
12669ed24c Squashed commit of the following:
commit 6fb3c103c7
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:29:16 2025 +0700

    fix: adjust subsection number width in table of contents

commit c29aab89e1
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:24:47 2025 +0700

    fix: adjust subsection indentation and dot separation in table of contents

commit 9d89e950ce
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:22:47 2025 +0700

    fix: adjust spacing for table of contents and list titles

commit f19b18ec8d
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:20:56 2025 +0700

    feat: adjust chapter title spacing and increase section numbering depth

    - Modify chapter title top spacing from 0pt to 0cm for consistency
    - Set section numbering depth to 3 levels (1.1.1 format)

commit 4be018fe57
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:17:02 2025 +0700

    feat: Update watermark text and settings for draft mode

commit 8e6b2fbb13
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:15:19 2025 +0700

    feat: Update language settings and bibliography strings for Indonesian and English

    Closes #81

commit 3af5a5dbb1
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:12:30 2025 +0700

    feat: Add documentclass scope to commit message template

commit c8f5662977
Author: nuluh <dam.ar@outlook.com>
Date:   Fri May 23 14:10:40 2025 +0700

    feat(documentclass): Add packages for SVG support, indentation, and float placement
2025-05-23 14:33:42 +07:00
nuluh
b0bdb67efb feat: Add bib entry 2025-05-23 03:39:59 +07:00
Damar
4d5de37e30 Add Literature Review (#80)
* feat(latex): add initial literature review paragraph from paper which data I used #67

* feat(latex): add Indonesian translation of structural health monitoring methods and related research findings

* feat(latex): add theoretical foundations and classification algorithms for damage localization in english version

* feat(latex): add initial content for literature review in index.tex

* Update latex/chapters/en/02_literature_review/index.tex

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-23 03:32:26 +07:00
Rifqi D. Panuluh
92fd3acd05 Add Chapter 3 Methodology (#79)
* feat(latex): initialize new structure for methodology chapter

* feat(latex): initialize sections for methodology chapter including data analysis, materials, and steps

* feat(latex): add detailed description and structure for materials section in methodology chapter

* fix(latex): correct section title from "Bahan dan Materi" to "Benda Uji" to give more context about the thesis

Closes #71

* feat(latex): add section for tools in methodology chapter

* feat(latex): initialize methodology steps with overall clue descriptions of research phases

* feat(latex): add specimen diagram with sensor notation for data representation in methodology chapter

* feat(latex): add diagram for joint and sensors placement in methodology chapter

* feat(latex): update dataset figure and add specimen image in methodology chapter

* feat(latex): expand data analysis section in methodology chapter

* fix(latex): fix citation format for secondary data source in methodology chapter

* feat(latex): add data acquisition section with dataset details and sampling information

* fix(latex): update input paths in methodology chapter for correct file referencing

* feat(latex): add hardware and software sections with detailed descriptions and components used in the research

* Update latex/chapters/id/03_methodology/tool/hardware.tex

fix(latex): Fix figure reference

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update latex/chapters/id/03_methodology/steps/index.tex

chore: remove double slash of image path

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update latex/chapters/id/03_methodology/data_analysis/index.tex

fix(latex): Fix typo

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: nuluh <dam.ar@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-23 03:25:23 +07:00
Damar
e0fade285a Add Theoretical Foundation (#78)
* feat(latex): add brief explanation of Short-Time Fourier Transform in theoretical foundation

* feat(latex): add brief evaluation of classic machine learning algorithms for damage localization

* fix(latex): correct STFT equation notation in theoretical foundation

Closes #72

* fix(latex): clarify STFT application in structural response analysis

* feat(latex): add explanation of windowing function in theoretical foundation

* feat(latex): expand classification algorithms section with additional methods and details

* feat(latex): add Hann window section with definition and application details

* feat(latex): enhance literature review with detailed SHM methods and STFT explanation
2025-05-23 03:13:34 +07:00
nuluh
b4fb0d64a2 feat(latex): add amsmath package for improved math support 2025-05-15 22:52:42 +07:00
nuluh
b1e1edee77 Merge branch 'main' of https://github.com/nuluh/thesis 2025-05-15 06:32:05 +07:00
Rifqi D. Panuluh
2016f4e780 Merge pull request #69 from nuluh/latex/68-feat-refactor-chapter-two
[FEAT] Refactor Chapter Two
2025-05-15 05:51:01 +07:00
nuluh
0cf2834095 refactor(latex): remove unused figure from literature review chapter 2025-05-15 02:04:17 +07:00
nuluh
d5f43ba48b refactor(latex): refactor literature review and theoretical foundations files structure with placeholder 2025-05-15 02:03:39 +07:00
nuluh
a872ae144c feat(latex): initialize new literature review files for comprehensive analysis 2025-05-15 01:59:00 +07:00
nuluh
452afd6580 Merge branch 'main' of https://github.com/nuluh/thesis 2025-05-14 18:53:58 +07:00
Rifqi D. Panuluh
3d2432f26e Merge pull request #66 from nuluh/latex/initial-template
Add Initial LaTeX Template
2025-05-14 18:41:52 +07:00
nuluh
1533a6ce46 fix(latex): add TOC entries for approval and originality sections 2025-05-14 17:59:36 +07:00
nuluh
471eccb12c fix(latex): remove new macro \frontmattersection to manually add \addcontentsline into each frontmatter to make hyperlink ToC jumpt into correct page.
Closes #65
2025-05-14 17:58:06 +07:00
nuluh
74ea4d412c fix(latex): update TOC title to use the correct language dynamically 2025-05-14 17:37:17 +07:00
nuluh
9d526971d9 feat(latex): add polyglossia package and set main language to Bahasa Indonesia 2025-05-14 17:34:56 +07:00
nuluh
49adb273d8 fix(latex): fix equation numbering to include chapter prefix in arabic
Closes #62
2025-05-14 12:21:21 +07:00
nuluh
ee004e55f4 fix(latex): add figure and table numbering prefixes to TOC 2025-05-13 02:02:41 +07:00
nuluh
f97c58e114 feat(latex): add styling for List of Figures and List of Tables titles 2025-05-13 01:42:16 +07:00
nuluh
190cd0904e fix(latex): fix merge conflicts 2025-05-12 00:45:30 +07:00
nuluh
6105da57f0 Merge branch 'latex/57-feat-add-dynamic-page-style-for-chapter-page' into latex/initial-template 2025-05-12 00:36:34 +07:00
nuluh
63da3b6308 fix(latex): remove titlepage environment from frontmattersection macro to make the \frontmatter and \mainmatter pagination number type change properly
Closes #57
2025-05-12 00:31:24 +07:00
nuluh
5634776d26 fix(latex): fix wrong endorsement content by moving it into approval sheet 2025-05-12 00:08:40 +07:00
nuluh
e65026f9ca feat(latex): add originality statement content 2025-05-12 00:06:24 +07:00
nuluh
eb1d2a87b4 refactor(latex): move figure numbering declaration 2025-05-11 23:05:13 +07:00
nuluh
1f275fad42 feat(latex): add figure and table numbering to include chapter numbern arabic despite the chapter number using roman and dummy figures to test 2025-05-11 22:57:26 +07:00
nuluh
07ed6a9a13 fix(latex): reorder document structure by moving \frontmatter and \mainmatter for proper page numbering 2025-05-11 22:54:02 +07:00
nuluh
1b20376700 Merge branch 'latex/initial-template' into latex/57-feat-add-dynamic-page-style-for-chapter-page 2025-05-11 22:15:40 +07:00
nuluh
104b72e624 fix(latex): remove second \hfill in the \cftaftertoctitle to fix the \contentsname with book document class 2025-05-11 22:15:05 +07:00
nuluh
e9568583e4 fix(latex): change document class from report to book for having access to \frontmatter, \mainmatter, and \backmatter 2025-05-11 22:13:46 +07:00
nuluh
ae201d61fa Merge branch 'latex/initial-template' into latex/57-feat-add-dynamic-page-style-for-chapter-page 2025-05-11 21:56:14 +07:00
nuluh
921dc9245c fix(latex): add draft watermark functionality with conditional loading 2025-05-11 19:32:13 +07:00
nuluh
bf3c43639d fix(latex): update page layout margins to 3cm for all sides 2025-05-11 18:26:46 +07:00
nuluh
f38d44df1d fix(latex): add dummy introductory chapter and sections for doing unittest of new implemented page number and chapter numbering 2025-05-11 13:00:53 +07:00
nuluh
5c70d7db51 fix(latex): ensure fancyplain page style preset is applied before content inclusion so it use top right number for non-first-page chapter 2025-05-11 12:54:55 +07:00
nuluh
702760cc5e fix(latex): assign fancyhdr preset page style to frontmatter section macro 2025-05-11 12:52:52 +07:00
nuluh
43a0f40182 fix(latex): creating header and footer styles preset 2025-05-11 12:51:23 +07:00
nuluh
92a7143d90 fix(latex): update frontmatter section command to correctly add TOC entries as chapters 2025-05-11 11:38:53 +07:00
nuluh
5e08d4f8c6 fix(latex): remove custom table of contents command since it doesnt give any effects when directly \renewcommand without through packages 2025-05-11 11:21:50 +07:00
nuluh
907f725fa7 fix(latex): remove redundant command for chapter dot separation in TOC 2025-05-11 11:13:20 +07:00
nuluh
676b2b1a87 fix(latex): remove accidental prefix 'chapter' string in TOC and fix the section numbering to keep using chapter's counter in arabic instead of inherited in roman 2025-05-11 11:12:50 +07:00
nuluh
e0fbc23257 fix(latex): ensure TOC and references respect custom numbering by redefining \thechapter to preserve the roman in TOC 2025-05-11 11:09:24 +07:00
nuluh
39f966e71b chore(latex): clarify comment for TOC title styling in thesis class 2025-05-11 10:56:32 +07:00
nuluh
740680d1c7 fix(latex): fix \contentsname to keep the title centered by adding dummy second \hfill in the \cftaftertoctitle when using \fancypagestyle or other fancyhdr effects 2025-05-11 10:45:42 +07:00
nuluh
2db5170366 fix(latex): correct chapter dot leaders and page font in table of contents to be all normalfont for all level instead of bfseries 2025-05-11 10:41:40 +07:00
nuluh
f83b890055 fix(latex): add tocbibind package to include toc itself in the toc and give dot leaders to it. 2025-05-11 10:23:30 +07:00
nuluh
7820dd580a feat(latex): add endorsement page with committee approval details and department head information 2025-05-11 08:37:19 +07:00
nuluh
6c0fb67b86 refactor(latex): refactor metadata commands for thesis information and load from external file to implement reusability 2025-05-11 01:08:49 +07:00
nuluh
792ed64027 fix(latex): adjust section number width in table of contents for best desired looks 2025-05-11 00:48:57 +07:00
nuluh
c57a916a1a fixlatex): fix chapter formatting and spacing in thesis class to be aligned at before chapter number and restyle \chapter to be centered and use hardcoded prefix "BAB" following with roman numbering 2025-05-10 18:50:41 +07:00
nuluh
ca668ffc5f feat(latex): add endorsement and originality statements to the document 2025-05-10 17:39:36 +07:00
nuluh
8d09adefd4 fix(latex): rename endorsement page command to avoid core LaTeX primitive for ending environments.
Closes #56
2025-05-10 17:36:15 +07:00
nuluh
05926e3857 feat(latex): add originality frontmatter file 2025-05-10 17:20:25 +07:00
nuluh
d13dfdc34e feat(latex): add frontmatter macros for frontmatters pages (endorsement, originality, approval, acknowledgement etc.) 2025-05-10 17:17:51 +07:00
nuluh
6b866b9ed5 feat(latex): create thesis class and initial document structure with title page and macros 2025-05-10 16:23:39 +07:00
nuluh
4a796694bf feat(latex): add new research papers to appendix with detailed summaries and findings 2025-05-07 00:41:09 +07:00
nuluh
6357136e6c fix(latex): add gap researsch table and adjust column widths in summary table for better layout 2025-05-07 00:37:25 +07:00
nuluh
c7584e2dd8 fix(latex): adjust column count for continuation message in summary table 2025-05-06 16:37:58 +07:00
nuluh
80ee9a3ec4 refactor(latex): update table into new format and comments in summary related paper document 2025-05-06 16:31:36 +07:00
nuluh
f9f346a57e feat(latex): add initial template summary related paper document with structured references 2025-05-06 16:09:51 +07:00
nuluh
c8509aa728 fix(notebooks): fix out of index stft plotting iteration 2025-04-22 10:55:34 +07:00
nuluh
4ebfb52635 Merge branch '40-feat-add-export-to-csv-method-for-dataprocessor-in-convertpy' 2025-04-21 00:16:39 +07:00
nuluh
cb380219f9 test(notebooks): update file paths for sensor data loading and add markdown for clarity 2025-04-21 00:07:06 +07:00
nuluh
804c178175 fix(notebooks): remove erroneous line and add markdown for testing outside training data 2025-04-20 16:32:31 +07:00
nuluh
1511012e11 refactor(test): update test script to generate damage files index for dataset_B and adjust export path for processed data 2025-04-20 16:02:16 +07:00
nuluh
db2947abdf fix(data): fix the incorrect output of scipy.stft() data to be pandas.DataFrame shaped (513,513) along with its frequencies as the index and times as the columns (transposed) instead of just the magnitude that being flattened out; add checks for empty data and correct file paths for sensor data loading.
Closes #43
2025-04-20 14:45:38 +07:00
nuluh
36b36c41ba feat(data): add export_to_csv method for saving processed data into individuals sensor end and update test script
Closes #40
2025-04-17 10:10:19 +07:00
Rifqi D. Panuluh
28681017ad Merge pull request #39 from nuluh/feature/38-feat-redesign-convertpy
Feature/38 feat redesign `convert.py`
2025-03-22 19:57:20 +07:00
nuluh
ff64f3a3ab refactor(data): update type annotations for damage files index and related classes. Need better implementation 2025-03-22 19:48:50 +07:00
nuluh
58a316d9c8 feat(data): implement damage files index generation and data processing
Closes #38
2025-03-21 15:58:50 +07:00
Rifqi D. Panuluh
020028eed8 Merge pull request #36 from nuluh/35-bug-oserror-for-non-existent-folder-when-running-convertpy
fix(data): ensure output directories are created before saving files
2025-03-16 18:45:36 +07:00
nuluh
35e25ba4c6 fix(data): ensure output directories are created before saving files
Closes #35
2025-03-16 18:30:52 +07:00
nuluh
8ed1437d6d Merge branch 'main' of https://github.com/nuluh/thesis 2025-03-16 14:12:11 +07:00
nuluh
96556a1186 ```
No code changes detected.
```
2025-03-16 14:07:56 +07:00
Rifqi D. Panuluh
0a63aab211 Merge pull request #34 from nuluh/stft
fix(data): update output file naming to include customizable prefix
2025-03-16 14:01:58 +07:00
nuluh
c8653f53ea fix(data): update output file naming to include customizable prefix 2025-03-16 13:58:50 +07:00
Rifqi D. Panuluh
48ea879863 Create documentation.yml 2025-03-16 12:39:10 +07:00
Rifqi D. Panuluh
69afdb1ad1 Create experiment.yml 2025-03-16 12:38:41 +07:00
Rifqi D. Panuluh
db2d9299e6 Create feature_request.yml 2025-03-16 12:38:14 +07:00
Rifqi D. Panuluh
d5ba1ac0cd Create bug_report.yml 2025-03-16 12:37:38 +07:00
Rifqi D. Panuluh
144f406226 Create config.yml 2025-03-16 12:36:46 +07:00
Rifqi D. Panuluh
e6f8820989 Merge pull request #33 from nuluh/stft
chore: add .gitattributes and .gitmessage for commit message guidelines
2025-03-16 12:17:55 +07:00
nuluh
59aa124305 chore: add .gitattributes and .gitmessage for commit message guidelines 2025-03-16 12:16:23 +07:00
Rifqi D. Panuluh
2de04a6ea6 Create CONTRIBUTING.md 2025-03-16 12:02:35 +07:00
Rifqi D. Panuluh
48075a590e Merge pull request #32 from nuluh/stft
Stft
2025-03-16 11:49:44 +07:00
nuluh
c28e79b022 feat(convert): add prefix parameter to create_damage_files for customizable file naming
Closes #31
2025-03-16 10:57:13 +07:00
nuluh
b890e556cf fix(notebook): correct execution counts and update file naming conventions for STFT processing
Closes #27
2025-03-11 19:08:56 +07:00
nuluh
fa6e1ff72b refactor(notebook): seperate process_stft function to individual code cell. 2025-03-08 11:04:37 +07:00
nuluh
a2e339a0a0 feat: Implement STFT verification for individual test runs against aggregated data 2024-12-13 16:30:06 +07:00
nuluh
2decff0cfb Closes #24
feat(stft): Implement STFT processing for vibration data with multiprocessing support to include all the data for training process instead of just using `TEST1` only
2024-12-13 16:29:08 +07:00
nuluh
8b4eedab8a Closes #26
feat: Specify `fs` when calling `scipy.signal.stft`
2024-12-09 00:49:25 +07:00
nuluh
a1fbe8bd93 feat(convert): Update damage scenarios and output file naming conventions 2024-12-08 18:08:59 +07:00
nuluh
832b6c49db feat(notebook): Implement STFT with Hann windowing. Closes #22 2024-10-21 19:08:46 +07:00
nuluh
9618714d3c feat: Prepare all damage cases vibration record data to be merged inside two variables "signal_sensor1" and "signal_sensor2". Closes #23 2024-10-19 15:32:05 +07:00
Rifqi D. Panuluh
b229967e05 Update README.md 2024-09-09 23:14:01 +07:00
Rifqi D. Panuluh
f41edaaa91 Update README.md 2024-09-09 23:13:03 +07:00
Panuluh
e9c06e1ac1 Update LICENSE 2024-09-07 09:13:57 +07:00
nuluh
2f54e91197 feat: Add absolute value option to time feature extraction 2024-09-03 15:39:44 +07:00
nuluh
758255a24e feat(notebooks): Implement Time-domain feature extraction with real data from QUGS 2024-09-03 12:52:40 +07:00
nuluh
ff5578652f fix(script): Fix bugs taking incorrect column by changing columns and sensor_end_map index number to take the loop of enumeration. 2024-09-03 12:08:53 +07:00
nuluh
db2c5d3a4e feat(script): Update output directory in convert.py 2024-09-03 11:50:44 +07:00
nuluh
ea978de872 - 2024-09-03 11:43:46 +07:00
nuluh
465d257850 feat(script): Add zero-padding to converted CSV filenames for standardize processing pipeline 2024-09-03 11:38:49 +07:00
nuluh
d12eea0acf feat(data-processing): Implement CSV data transformation for SVM analysis
Introduce a Python script for transforming QUGS 2D grid structure data into a simplified 1D beam format suitable for SVM-based damage detection. The script efficiently slices original CSV files into smaller, manageable sets, correlating specific damage scenarios with their corresponding sensor data. This change addresses the challenge of retaining critical damage localization information during the data conversion process, ensuring high-quality, relevant data for 1D analysis.

Closes #20
2024-09-03 11:33:23 +07:00
nuluh
0306f28a68 docs(notebooks): add extract_numbers docstring 2024-09-03 11:09:47 +07:00
Panuluh
9da3dae709 Merge pull request #18 from nuluh/feature/15-normalize-dataset-by-preprocess-relatives-value-between-two-acceloremeter-sensors
Feature/15 normalize dataset by preprocess relatives value between two acceloremeter sensors
2024-09-03 08:43:44 +07:00
nuluh
41086e95ad chore: Ignore .venv/ directory and update .gitignore due to error numpy error ValueError: numpy.ndarray size changed, may indicate binary incompatibility. by creating venv. 2024-09-01 14:50:24 +07:00
nuluh
adde35ed7e feat(notebook): Normalize the data by calculating the relative value between two sensors. Along with it, MinMaxScaler and StandardScaler are applied and visualize with Seaborn's Pair Plot.
Closes #15
2024-09-01 14:50:04 +07:00
nuluh
b2684c23f6 feat(script): Add zero-padding to CSV filenames to include sensors number 2024-08-27 10:11:39 +07:00
Panuluh
8a499a04fb Merge pull request #17 from nuluh/feature/csv-padding-naming
Feature/csv padding naming
2024-08-27 09:23:44 +07:00
nuluh
3860f2cc5b fix(docs): The readme.md should belong to raw data since the script is intended to simulate raw data that coming from accelerometer sensors instead of processed data that should be generated by simulating frequency domain data instead. 2024-08-18 10:34:22 +07:00
nuluh
553140fe3c feat(script): add zero-padding to CSV filenames and change the output generated csv as raw data in raw folder 2024-08-17 19:51:42 +07:00
177 changed files with 13311 additions and 1328 deletions

6
.gitattributes vendored Normal file
View File

@@ -0,0 +1,6 @@
*.ipynb filter=nbstripout
*.svg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text

115
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,115 @@
name: Bug Report
description: Report a bug or unexpected behavior
title: "[BUG] "
labels: ["bug"]
assignees:
- ${{github.actor}}
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Bug Description
description: A clear and concise description of what the bug is
placeholder: When I run the script, it crashes when processing large datasets...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to Reproduce
description: Steps to reproduce the behavior
placeholder: |
1. Go to notebook '...'
2. Run cell #...
3. See error
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: What did you expect to happen?
placeholder: The analysis should complete successfully and generate the visualization
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual Behavior
description: What actually happened?
placeholder: The script crashes with a memory error after processing 1000 samples
validations:
required: true
- type: textarea
id: logs
attributes:
label: Error Logs
description: Paste any relevant logs or error messages
render: shell
placeholder: |
Traceback (most recent call last):
File "script.py", line 42, in <module>
main()
File "script.py", line 28, in main
process_data(data)
MemoryError: ...
validations:
required: false
- type: dropdown
id: component
attributes:
label: Component
description: Which part of the thesis project is affected?
options:
- LaTeX Document
- Python Source Code
- Jupyter Notebook
- Data Processing
- ML Model
- Visualization
- Build/Environment
validations:
required: true
- type: input
id: version
attributes:
label: Version/Commit
description: Which version or commit hash are you using?
placeholder: v0.2.3 or 8d5b9a7
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: Information about your environment
placeholder: |
- OS: [e.g. Ubuntu 22.04]
- Python: [e.g. 3.9.5]
- Relevant packages and versions:
- numpy: 1.22.3
- scikit-learn: 1.0.2
- tensorflow: 2.9.1
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional Context
description: Any other context or screenshots about the problem
placeholder: Add any other context about the problem here...
validations:
required: false

12
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
blank_issues_enabled: false
contact_links:
- name: Documentation
url: ../docs/README.md
about: Check the documentation before creating an issue
# Template configurations
templates:
- name: bug_report.yml
- name: feature_request.yml
- name: experiment.yml
- name: documentation.yml

116
.github/ISSUE_TEMPLATE/documentation.yml vendored Normal file
View File

@@ -0,0 +1,116 @@
name: Documentation
description: Improvements or additions to documentation
title: "[DOC] "
labels: ["documentation"]
assignees:
- ${{github.actor}}
body:
- type: markdown
attributes:
value: |
Use this template for documentation-related tasks for your thesis project.
- type: dropdown
id: doc_type
attributes:
label: Documentation Type
description: What type of documentation is this issue about?
options:
- Thesis Chapter/Section
- Code Documentation
- Experiment Documentation
- README/Project Documentation
- Literature Review
- Methodology Description
- Results Analysis
- API Reference
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: Describe what needs to be documented
placeholder: Need to document the data preprocessing pipeline including all transformation steps and rationale
validations:
required: true
- type: textarea
id: current_state
attributes:
label: Current State
description: What's the current state of the documentation (if any)?
placeholder: Currently there are some comments in the code but no comprehensive documentation of the preprocessing steps
validations:
required: false
- type: textarea
id: proposed_changes
attributes:
label: Proposed Changes
description: What specific documentation changes do you want to make?
placeholder: |
1. Create a dedicated markdown file describing each preprocessing step
2. Add docstrings to all preprocessing functions
3. Create a diagram showing the data flow
4. Document parameter choices and their justification
validations:
required: true
- type: input
id: location
attributes:
label: Documentation Location
description: Where will this documentation be stored?
placeholder: docs/data_preprocessing.md or src/preprocessing/README.md
validations:
required: true
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this documentation?
options:
- Critical (required for thesis)
- High (important for understanding)
- Medium (helpful but not urgent)
- Low (nice to have)
validations:
required: true
- type: dropdown
id: audience
attributes:
label: Target Audience
description: Who is the primary audience for this documentation?
options:
- Thesis Committee/Reviewers
- Future Self
- Other Researchers
- Technical Readers
- Non-technical Readers
- Multiple Audiences
validations:
required: true
- type: textarea
id: references
attributes:
label: References
description: Any papers, documentation or other materials related to this documentation task
placeholder: |
- Smith et al. (2022). "Best practices in machine learning documentation"
- Code in src/preprocessing/normalize.py
validations:
required: false
- type: textarea
id: notes
attributes:
label: Additional Notes
description: Any other relevant information
placeholder: This documentation will be referenced in Chapter 3 of the thesis
validations:
required: false

124
.github/ISSUE_TEMPLATE/experiment.yml vendored Normal file
View File

@@ -0,0 +1,124 @@
# .github/ISSUE_TEMPLATE/experiment.yml
name: Experiment
description: Document a new ML experiment
title: "[EXP] "
labels: ["experiment"]
assignees:
- ${{github.actor}}
body:
- type: markdown
attributes:
value: |
Use this template to document a new experiment for your thesis.
- type: textarea
id: hypothesis
attributes:
label: Hypothesis
description: What is the hypothesis you're testing with this experiment?
placeholder: Using a deeper network with residual connections will improve accuracy on the imbalanced dataset without increasing overfitting
validations:
required: true
- type: textarea
id: background
attributes:
label: Background & Motivation
description: Background context and why this experiment is important
placeholder: Previous experiments showed promising results but suffered from overfitting. Recent literature suggests that...
validations:
required: true
- type: textarea
id: dataset
attributes:
label: Dataset
description: What data will you use for this experiment?
placeholder: |
- Dataset: MNIST with augmentation
- Preprocessing: Standardization + random rotation
- Train/Test Split: 80/20
- Validation strategy: 5-fold cross-validation
validations:
required: true
- type: textarea
id: methodology
attributes:
label: Methodology
description: How will you conduct the experiment?
placeholder: |
1. Implement ResNet architecture with varying depths (18, 34, 50)
2. Train with early stopping (patience=10)
3. Compare against baseline CNN from experiment #23
4. Analyze learning curves and performance metrics
validations:
required: true
- type: textarea
id: parameters
attributes:
label: Parameters & Hyperparameters
description: List the key parameters for this experiment
placeholder: |
- Learning rate: 0.001 with Adam optimizer
- Batch size: 64
- Epochs: Max 100 with early stopping
- Dropout rate: 0.3
- L2 regularization: 1e-4
validations:
required: true
- type: textarea
id: metrics
attributes:
label: Evaluation Metrics
description: How will you evaluate the results?
placeholder: |
- Accuracy
- F1-score (macro-averaged)
- ROC-AUC
- Training vs. validation loss curves
- Inference time
validations:
required: true
- type: input
id: notebook
attributes:
label: Notebook Location
description: Where will the experiment notebook be stored?
placeholder: notebooks/experiment_resnet_comparison.ipynb
validations:
required: false
- type: textarea
id: dependencies
attributes:
label: Dependencies
description: What other issues or tasks does this experiment depend on?
placeholder: |
- Depends on issue #42 (Data preprocessing pipeline)
- Requires completion of issue #51 (Baseline model)
validations:
required: false
- type: textarea
id: references
attributes:
label: References
description: Any papers, documentation or other materials relevant to this experiment
placeholder: |
- He et al. (2016). "Deep Residual Learning for Image Recognition"
- My previous experiment #23 (baseline CNN)
validations:
required: false
- type: textarea
id: notes
attributes:
label: Additional Notes
description: Any other relevant information
placeholder: This experiment may require significant GPU resources. Expected runtime is ~3 hours on Tesla V100.
validations:
required: false

View File

@@ -0,0 +1,99 @@
# .github/ISSUE_TEMPLATE/feature_request.yml
name: Feature Request
description: Suggest a new feature or enhancement
title: "[FEAT] "
labels: ["enhancement"]
assignees:
- ${{github.actor}}
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to propose a new feature!
- type: textarea
id: problem
attributes:
label: Problem Statement
description: What problem are you trying to solve with this feature?
placeholder: I'm frustrated when trying to analyze different model results because I need to manually compare them...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to implement
placeholder: Create a visualization utility that automatically compares results across multiple models and experiments
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Describe alternatives you've considered
placeholder: I considered using an external tool, but integrating directly would provide better workflow
validations:
required: false
- type: dropdown
id: component
attributes:
label: Component
description: Which part of the thesis project would this feature affect?
options:
- LaTeX Document
- Python Source Code
- Jupyter Notebook
- Data Processing
- ML Model
- Visualization
- Build/Environment
- Multiple Components
validations:
required: true
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this feature for your thesis progression?
options:
- Critical (blocks progress)
- High (significantly improves workflow)
- Medium (nice to have)
- Low (minor improvement)
validations:
required: true
- type: textarea
id: implementation
attributes:
label: Implementation Ideas
description: Any initial thoughts on how to implement this feature?
placeholder: |
- Could use matplotlib's subplot feature
- Would need to standardize the model output format
- Should include statistical significance tests
validations:
required: false
- type: textarea
id: benefits
attributes:
label: Expected Benefits
description: How will this feature benefit your thesis work?
placeholder: This will save time in analysis and provide more consistent comparisons across experiments
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional Context
description: Any other context, screenshots, or reference material
placeholder: Here's a paper that uses a similar approach...
validations:
required: false

16
.gitignore vendored
View File

@@ -1,4 +1,18 @@
# Ignore CSV files in the data directory and all its subdirectories
data/**/*.csv
.venv/
*.pyc
*.egg-info/
*.pyc
# Latex
*.aux
*.log
*.out
*.toc
*.bbl
*.blg
*.fdb_latexmk
*.fls
*.synctex.gz
*.dvi
latex/.build/*

31
.gitmessage Normal file
View File

@@ -0,0 +1,31 @@
# .gitmessage
# <type>(<scope>): <subject>
# |<---- Using a Maximum Of 50 Characters ---->|
#
# Explain the problem that this commit is solving. Focus on why you
# are making this change as opposed to how. Use clear, concise language.
# |<---- Try To Limit Each Line to a Maximum Of 72 Characters ---->|
#
# -- COMMIT END --
# Types:
# feat (new feature)
# fix (bug fix)
# refactor (refactoring code)
# style (formatting, no code change)
# doc (changes to documentation)
# test (adding or refactoring tests)
# perf (performance improvements)
# chore (routine tasks, dependencies)
# exp (experimental work/exploration)
#
# Scope:
# latex (changes to thesis LaTeX)
# documentclass (LaTeX in-house document class changes)
# src (changes to Python source code)
# nb (changes to notebooks)
# ml (ML model specific changes)
# data (data processing/preparation)
# viz (visualization related)
# all (changes spanning entire repository)
# --------------------

28
.vscode/settings.json vendored
View File

@@ -1,3 +1,29 @@
{
"python.analysis.extraPaths": ["./code/src/features"]
"files.autoSave": "off", // Disable autosave
"python.analysis.extraPaths": [
"./code/src/features",
"${workspaceFolder}/code/src"
],
"jupyter.notebookFileRoot": "${workspaceFolder}/code",
"latex-workshop.latex.outDir": "./.build",
// "latex-workshop.latex.tools": [
// {
// "name": "xelatex",
// "command": "xelatex",
// "args": [
// "-synctex=1",
// "-interaction=nonstopmode",
// "-output-directory=./latex/.build",
// "%DOC%"
// ]
// }
// ],
// "latex-workshop.latex.recipes": [
// {
// "name": "xelatex",
// "tools": ["xelatex"]
// }
// ],
"latex-workshop.latex.recipe.default": "latexmk (xelatex)", // Optional: Use the last used recipe
}

View File

@@ -0,0 +1,7 @@
Copyright 2024 Rifqi D. Panuluh
All Rights Reserved.
This repository is for viewing purposes only. No part of this repository, including but not limited to the code, files, and documentation, may be copied, reproduced, modified, or distributed in any form or by any means without the prior written permission of the copyright holder.
Unauthorized use, distribution, or modification of this repository may result in legal action.

View File

@@ -0,0 +1,23 @@
## Summary
This repository contains the work related to my thesis, which focuses on damage localization prediction. The research explores the application of machine learning techniques to structural health monitoring.
**Note:** This repository does not contain the secondary data used in the analysis. The code is designed to work with data from the [QUGS (Qatar University Grandstand Simulator)](https://www.structuralvibration.com/benchmark/qugs/) dataset, which is not included here.
The repository is private and access is restricted only to those who have been given explicit permission by the owner. Access is provided solely for the purpose of brief review or seeking technical guidance.
## Restrictions
- **No Derivative Works or Cloning:** Any form of copying, cloning, or creating derivative works based on this repository is strictly prohibited.
- **Limited Access:** Use beyond brief review or collaboration is not allowed without prior permission from the owner.
---
All contents of this repository, including the thesis idea, code, and associated data, are copyrighted © 2024 by Rifqi Panuluh. Unauthorized use or duplication is prohibited.
[LICENSE](https://github.com/nuluh/thesis?tab=License-1-ov-file#readme)
## How to Run `stft.ipynb`
1. run `pip install -e .` in root project first
2. run the notebook

File diff suppressed because one or more lines are too long

1162
code/notebooks/stft.ipynb Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,357 @@
import pandas as pd
import os
import re
import sys
import numpy as np
from colorama import Fore, Style, init
from typing import TypedDict, Dict, List
from joblib import load
from pprint import pprint
# class DamageFilesIndices(TypedDict):
# damage_index: int
# files: list[int]
OriginalSingleDamageScenarioFilePath = str
DamageScenarioGroupIndex = int
OriginalSingleDamageScenario = pd.DataFrame
SensorIndex = int
VectorColumnIndex = List[SensorIndex]
VectorColumnIndices = List[VectorColumnIndex]
DamageScenarioGroup = List[OriginalSingleDamageScenario]
GroupDataset = List[DamageScenarioGroup]
class DamageFilesIndices(TypedDict):
damage_index: int
files: List[str]
def complement_pairs(n, prefix, extension):
"""
Return the four complement tuples for zzzBD<n>.TXT
"""
filename = f"{prefix}{n}.{extension}" # TODO: shouldnt be hardcoded
orig_a = (n - 1) % 5 + 1 # 1 … 5
for a in range(1, 6): # a = 1 … 5
if a != orig_a: # skip original a
yield (filename, [a, a + 25]) # use yield instead of return to return a generator of tuples
def generate_df_tuples(prefix: str, total_dfs: int=30, extension: str="TXT", first_col_start: int=1, last_col_offset: int=25,
group_size: int=5, special_groups: list=None, group: bool=True):
"""
Generate a structured list of tuples containing DataFrame references and column indices.
Parameters:
-----------
total_dfs : int, default 30
Total number of DataFrames to include in the tuples
group_size : int, default 5
Number of DataFrames in each group (determines the pattern repeat)
prefix : str
Prefix for DataFrame variable names
first_col_start : int, default 1
Starting value for the first column index (1-indexed)
last_col_offset : int, default 25
Offset to add to first_col_start to get the last column index
special_groups : list of dict, optional
List of special groups to insert, each dict should contain:
- 'df_name': The DataFrame name to use for all tuples in this group
- 'position': Where to insert this group (0 for beginning)
- 'size': Size of this group (default: same as group_size)
Returns:
--------
list
List of tuples, where each tuple contains (df_name, [first_col, last_col])
"""
result = []
if group:
# Group tuples into sublists of group_size
for g in range(6): # TODO: shouldnt be hardcoded
group = []
for i in range(1, 6): # TODO: shouldnt be hardcoded
n = g * 5 + i
bottom_end = i # 1, 2, 3, 4, 5
top_end = bottom_end + 25 # 26, 27, 28, 29, 30 # TODO: shouldnt be hardcoded
group.append((f"{prefix}{n}.{extension}", [bottom_end, top_end]))
result.append(group)
# Add special groups at specified positions (other than beginning)
if special_groups:
result.insert(0, special_groups)
return result
# file_path = os.path.join(base_path, f"zzz{prefix}D{file_index}.TXT")
# df = pd.read_csv(file_path, sep="\t", skiprows=10) # Read with explicit column names
class DataProcessor:
def __init__(self, file_index, cache_path: str = None, base_path: str = None, include_time: bool = False):
self.file_index = file_index
self.base_path = base_path
self.include_time = include_time
if cache_path:
self.data = load(cache_path)
else:
self.data = self.load_data()
def load_data(self):
for idxs, group in enumerate(self.file_index):
for idx, tuple in enumerate(group):
file_path = os.path.join(self.base_path, tuple[0]) # ('zzzAD1.TXT')
if self.include_time:
col_indices = [0] + tuple[1] # [1, 26] + [0] -> [0, 1, 26]
else:
col_indices = tuple[1] # [1, 26]
try:
# Read the CSV file
df = pd.read_csv(file_path, delim_whitespace=True, skiprows=10, header=0, memory_map=True)
self.file_index[idxs][idx] = df.iloc[:, col_indices].copy() # Extract the specified columns
print(f"Processed {file_path}, extracted columns: {col_indices}")
except Exception as e:
print(f"Error processing {file_path}: {str(e)}")
def _load_dataframe(self, file_path: str) -> OriginalSingleDamageScenario:
"""
Loads a single data file into a pandas DataFrame.
:param file_path: Path to the data file.
:return: DataFrame containing the numerical data.
"""
df = pd.read_csv(file_path, delim_whitespace=True, skiprows=10, header=0, memory_map=True, nrows=1)
return df
def _load_all_data(self) -> GroupDataset:
"""
Loads all data files based on the grouping dictionary and returns a nested list.
:return: A nested list of DataFrames where the outer index corresponds to group_idx - 1.
"""
data = []
# Find the maximum group index to determine the list size
max_group_idx = len(self.file_index) if self.file_index else 0
# Handle case when file_index is empty
if max_group_idx == 0:
raise ValueError("No file index provided; file_index is empty.")
# Initialize empty lists
for _ in range(max_group_idx):
data.append([])
# Fill the list with data
for group_idx, file_list in self.file_index.items():
group_idx -= 1 # adjust due to undamage file
data[group_idx] = [self._load_dataframe(file) for file in file_list]
return data
def get_group_data(self, group_idx: int) -> List[pd.DataFrame]:
"""
Returns the list of DataFrames for the given group index.
:param group_idx: Index of the group.
:return: List of DataFrames.
"""
return self.data.get([group_idx, []])
def get_column_names(self, group_idx: int, file_idx: int = 0) -> List[str]:
"""
Returns the column names for the given group and file indices.
:param group_idx: Index of the group.
:param file_idx: Index of the file in the group.
:return: List of column names.
"""
if group_idx in self.data and len(self.data[group_idx]) > file_idx:
return self.data[group_idx][file_idx].columns.tolist()
return []
def get_data_info(self):
"""
Print information about the loaded data structure.
Adapted for when self.data is a List instead of a Dictionary.
"""
if isinstance(self.data, list):
# For each sublist in self.data, get the type names of all elements
pprint(
[
(
[type(item).__name__ for item in sublist]
if isinstance(sublist, list)
else type(sublist).__name__
)
for sublist in self.data
]
)
else:
pprint(
{
key: [type(df).__name__ for df in value]
for key, value in self.data.items()
}
if isinstance(self.data, dict)
else type(self.data).__name__
)
def _create_vector_column_index(self) -> VectorColumnIndices:
vector_col_idx: VectorColumnIndices = []
y = 0
for data_group in self.data: # len(data_group[i]) = 5
for j in data_group: # len(j[i]) =
c: VectorColumnIndex = []
x = 0
for _ in range(6): # TODO: range(6) should be dynamic and parameterized
c.append(x + y)
x += 5
vector_col_idx.append(c)
y += 1
return vector_col_idx # TODO: refactor this so that it returns just from first data_group without using for loops through the self.data that seems unnecessary
def create_vector_column(self, overwrite=True) -> List[List[List[pd.DataFrame]]]:
"""
Create a vector column from the loaded data.
:param overwrite: Overwrite the original data with vector column-based data.
"""
idxs = self._create_vector_column_index()
for i, group in enumerate(self.data):
# add 1 to all indices to account for 'Time' being at position 0
for j, df in enumerate(group):
idx = [_ + 1 for _ in idxs[j]]
# slice out the desired columns, copy into a fresh DataFrame,
# then overwrite self.data[i][j] with it
self.data[i][j] = df.iloc[:, idx].copy()
# TODO: if !overwrite:
def create_limited_sensor_vector_column(self, overwrite=True):
"""
Create a vector column from the loaded data.
:param overwrite: Overwrite the original data with vector column-based data.
"""
idx = self._create_vector_column_index()
# if overwrite:
for i in range(len(self.data)): # damage(s)
for j in range(len(self.data[i])): # col(s)
# Get the appropriate indices for slicing from idx
indices = idx[j]
# Get the current DataFrame
df = self.data[i][j]
# Keep the 'Time' column and select only specifid 'Real' colmns
# First, we add 1 to all indices to acount for 'Time' being at positiion 0
real_indices = [index + 1 for index in indices]
# Create list with Time column index (0) and the adjustedd Real indices
all_indices = [0] + [real_indices[0]] + [real_indices[-1]]
# Apply the slicing
self.data[i][j] = df.iloc[:, all_indices]
# TODO: if !overwrite:
def export_to_csv(self, output_dir: str, file_prefix: str = "DAMAGE"):
"""
Export the processed data to CSV files in the required folder structure.
:param output_dir: Directory to save the CSV files.
:param file_prefix: Prefix for the output filenames.
"""
for group_idx, group in enumerate(self.file_index, start=0):
group_folder = os.path.join(output_dir, f"{file_prefix}_{group_idx}")
os.makedirs(group_folder, exist_ok=True)
for test_idx, df in enumerate(group, start=1):
out1 = os.path.join(group_folder, f"{file_prefix}_{group_idx}_TEST{test_idx}_01.csv")
cols_to_export = [0, 1] if self.include_time else [1]
df.iloc[:, cols_to_export].to_csv(out1, index=False)
out2 = os.path.join(group_folder, f"{file_prefix}_{group_idx}_TEST{test_idx}_02.csv")
cols_to_export = [0, 2] if self.include_time else [2]
df.iloc[:, cols_to_export].to_csv(out2, index=False)
# def create_damage_files(base_path, output_base, prefix):
# # Initialize colorama
# init(autoreset=True)
# # Generate column labels based on expected duplication in input files
# columns = ["Real"] + [
# f"Real.{i}" for i in range(1, 30)
# ] # Explicitly setting column names
# sensor_end_map = {
# 1: "Real.25",
# 2: "Real.26",
# 3: "Real.27",
# 4: "Real.28",
# 5: "Real.29",
# }
# # Define the damage scenarios and the corresponding original file indices
# damage_scenarios = {
# 1: range(1, 6), # Damage 1 files from zzzAD1.csv to zzzAD5.csv
# 2: range(6, 11), # Damage 2 files from zzzAD6.csv to zzzAD10.csv
# 3: range(11, 16), # Damage 3 files from zzzAD11.csv to zzzAD15.csvs
# 4: range(16, 21), # Damage 4 files from zzzAD16.csv to zzzAD20.csv
# 5: range(21, 26), # Damage 5 files from zzzAD21.csv to zzzAD25.csv
# 6: range(26, 31), # Damage 6 files from zzzAD26.csv to zzzAD30.csv
# }
# damage_pad = len(str(len(damage_scenarios)))
# test_pad = len(str(30))
# for damage, files in damage_scenarios.items():
# for i, file_index in enumerate(files, start=1):
# # Load original data file
# file_path = os.path.join(base_path, f"zzz{prefix}D{file_index}.TXT")
# df = pd.read_csv(
# file_path, sep="\t", skiprows=10
# ) # Read with explicit column names
# top_sensor = columns[i - 1]
# print(top_sensor, type(top_sensor))
# output_file_1 = os.path.join(
# output_base, f"DAMAGE_{damage}", f"DAMAGE{damage}_TEST{i}_01.csv"
# )
# print(f"Creating {output_file_1} from taking zzz{prefix}D{file_index}.TXT")
# print("Taking datetime column on index 0...")
# print(f"Taking `{top_sensor}`...")
# os.makedirs(os.path.dirname(output_file_1), exist_ok=True)
# df[["Time", top_sensor]].to_csv(output_file_1, index=False)
# print(Fore.GREEN + "Done")
# bottom_sensor = sensor_end_map[i]
# output_file_2 = os.path.join(
# output_base, f"DAMAGE_{damage}", f"DAMAGE{damage}_TEST{i}_02.csv"
# )
# print(f"Creating {output_file_2} from taking zzz{prefix}D{file_index}.TXT")
# print("Taking datetime column on index 0...")
# print(f"Taking `{bottom_sensor}`...")
# os.makedirs(os.path.dirname(output_file_2), exist_ok=True)
# df[["Time", bottom_sensor]].to_csv(output_file_2, index=False)
# print(Fore.GREEN + "Done")
# print("---")
def main():
if len(sys.argv) < 2:
print("Usage: python convert.py <path_to_csv_files>")
sys.exit(1)
base_path = sys.argv[1]
output_base = sys.argv[2]
prefix = sys.argv[3] # Define output directory
# Create output folders if they don't exist
# for i in range(1, 7):
# os.makedirs(os.path.join(output_base, f'DAMAGE_{i}'), exist_ok=True)
create_damage_files(base_path, output_base, prefix)
print(Fore.YELLOW + Style.BRIGHT + "All files have been created successfully.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,192 @@
import numpy as np
import pandas as pd
from scipy.fft import fft, fftfreq
def get_mean_freq(signal, frame_size, hop_length):
mean = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
current_mean = np.sum(y)/frame_size
mean.append(current_mean)
return np.array(mean)
def get_variance_freq(signal, frame_size, hop_length):
var = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
current_var = (np.sum((y - (np.sum(y)/frame_size))**2))/(frame_size-1)
var.append(current_var)
return np.array(var)
def get_third_freq(signal, frame_size, hop_length):
third = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
current_third = (np.sum((y - (np.sum(y)/frame_size))**3))/(frame_size * (np.sqrt((np.sum((y - (np.sum(y)/frame_size))**2))/(frame_size-1)))**3)
third.append(current_third)
return np.array(third)
def get_forth_freq(signal, frame_size, hop_length):
forth = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
current_forth = (np.sum((y - (np.sum(y)/frame_size))**4))/(frame_size * ((np.sum((y - (np.sum(y)/frame_size))**2))/(frame_size-1))**2)
forth.append(current_forth)
return np.array(forth)
def get_grand_freq(signal, frame_size, hop_length):
grand = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_grand = np.sum(f * y)/np.sum(y)
grand.append(current_grand)
return np.array(grand)
def get_std_freq(signal, frame_size, hop_length):
std = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_std = np.sqrt(np.sum((f-(np.sum(f * y)/np.sum(y)))**2 * y)/frame_size)
std.append(current_std)
return np.array(std)
def get_Cfactor_freq(signal, frame_size, hop_length):
cfactor = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_cfactor = np.sqrt(np.sum(f**2 * y)/np.sum(y))
cfactor.append(current_cfactor)
return np.array(cfactor)
def get_Dfactor_freq(signal, frame_size, hop_length):
dfactor = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_dfactor = np.sqrt(np.sum(f**4 * y)/np.sum(f**2 * y))
dfactor.append(current_dfactor)
return np.array(dfactor)
def get_Efactor_freq(signal, frame_size, hop_length):
efactor = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_efactor = np.sqrt(np.sum(f**2 * y)/np.sqrt(np.sum(y) * np.sum(f**4 * y)))
efactor.append(current_efactor)
return np.array(efactor)
def get_Gfactor_freq(signal, frame_size, hop_length):
gfactor = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_gfactor = (np.sqrt(np.sum((f-(np.sum(f * y)/np.sum(y)))**2 * y)/frame_size))/(np.sum(f * y)/np.sum(y))
gfactor.append(current_gfactor)
return np.array(gfactor)
def get_third1_freq(signal, frame_size, hop_length):
third1 = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_third1 = np.sum((f - (np.sum(f * y)/np.sum(y)))**3 * y)/(frame_size * (np.sqrt(np.sum((f-(np.sum(f * y)/np.sum(y)))**2 * y)/frame_size))**3)
third1.append(current_third1)
return np.array(third1)
def get_forth1_freq(signal, frame_size, hop_length):
forth1 = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_forth1 = np.sum((f - (np.sum(f * y)/np.sum(y)))**4 * y)/(frame_size * (np.sqrt(np.sum((f-(np.sum(f * y)/np.sum(y)))**2 * y)/frame_size))**4)
forth1.append(current_forth1)
return np.array(forth1)
def get_Hfactor_freq(signal, frame_size, hop_length):
hfactor = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_hfactor = np.sum(np.sqrt(abs(f - (np.sum(f * y)/np.sum(y)))) * y)/(frame_size * np.sqrt(np.sqrt(np.sum((f-(np.sum(f * y)/np.sum(y)))**2 * y)/frame_size)))
hfactor.append(current_hfactor)
return np.array(hfactor)
def get_Jfactor_freq(signal, frame_size, hop_length):
jfactor = []
for i in range(0, len(signal), hop_length):
L = len(signal[i:i+frame_size])
y = abs(np.fft.fft(signal[i:i+frame_size]/L))[:int(L/2)]
f = np.fft.fftfreq (L,.1/25600)[:int(L/2)]
current_jfactor = np.sum(np.sqrt(abs(f - (np.sum(f * y)/np.sum(y)))) * y)/(frame_size * np.sqrt(np.sqrt(np.sum((f-(np.sum(f * y)/np.sum(y)))**2 * y)/frame_size)))
jfactor.append(current_jfactor)
return np.array(jfactor)
class FrequencyFeatureExtractor:
def __init__(self, data):
# Assuming data is a numpy array
self.x = data
# Perform FFT and compute magnitude of frequency components
self.frequency_spectrum = np.abs(fft(self.x))
self.n = len(self.frequency_spectrum)
self.mean_freq = np.mean(self.frequency_spectrum)
self.variance_freq = np.var(self.frequency_spectrum)
self.std_freq = np.std(self.frequency_spectrum)
# Calculate the required frequency features
self.features = self.calculate_features()
def calculate_features(self):
S_mu = self.mean_freq
S_MAX = np.max(self.frequency_spectrum)
S_SBP = np.sum(self.frequency_spectrum)
S_Peak = np.max(self.frequency_spectrum)
S_V = np.sum((self.frequency_spectrum - S_mu) ** 2) / (self.n - 1)
S_Sigma = np.sqrt(S_V)
S_Skewness = np.sum((self.frequency_spectrum - S_mu) ** 3) / (self.n * S_Sigma ** 3)
S_Kurtosis = np.sum((self.frequency_spectrum - S_mu) ** 4) / (self.n * S_Sigma ** 4)
S_RSPPB = S_Peak / S_mu
return {
'Mean of band Power Spectrum (S_mu)': S_mu,
'Max of band power spectrum (S_MAX)': S_MAX,
'Sum of total band power (S_SBP)': S_SBP,
'Peak of band power (S_Peak)': S_Peak,
'Variance of band power (S_V)': S_V,
'Standard Deviation of band power (S_Sigma)': S_Sigma,
'Skewness of band power (S_Skewness)': S_Skewness,
'Kurtosis of band power (S_Kurtosis)': S_Kurtosis,
'Relative Spectral Peak per Band Power (S_RSPPB)': S_RSPPB
}
def __repr__(self):
result = "Frequency Domain Feature Extraction Results:\n"
for feature, value in self.features.items():
result += f"{feature}: {value:.4f}\n"
return result
def ExtractFrequencyFeatures(object):
data = pd.read_csv(object, skiprows=1) # Skip the header row separator char info
extractor = FrequencyFeatureExtractor(data.iloc[:, 1].values) # Assuming the data is in the second column
features = extractor.features
return features
# Usage Example
# extractor = FrequencyFeatureExtractor('path_to_your_data.csv')
# print(extractor)

View File

@@ -36,9 +36,12 @@ class FeatureExtractor:
result += f"{feature}: {value:.4f}\n"
return result
def ExtractTimeFeatures(object):
def ExtractTimeFeatures(object, absolute):
data = pd.read_csv(object, skiprows=1) # Skip the header row separator char info
extractor = FeatureExtractor(data.iloc[:, 1].values) # Assuming the data is in the second column
if absolute:
extractor = FeatureExtractor(np.abs(data.iloc[:, 1].values)) # Assuming the data is in the second column
else:
extractor = FeatureExtractor(data.iloc[:, 1].values)
features = extractor.features
return features
# Save features to a file

190
code/src/ml/inference.py Normal file
View File

@@ -0,0 +1,190 @@
from joblib import load
import pandas as pd
from src.data_preprocessing import *
from src.process_stft import compute_stft
from typing import List, Tuple
from sklearn.base import BaseEstimator
import json
def probability_damage(pred: Tuple[np.ndarray, np.ndarray], model_classes: BaseEstimator, percentage=False) -> Dict[str, int]:
"""
Process the prediction output to return unique labels and their counts.
"""
labels, counts = np.unique(pred, return_counts=True)
label_counts = dict(zip(labels, counts))
# init all models classes probability of damage with 0 in dictionary
pod: Dict[np.ndarray, int] = dict.fromkeys(model_classes.classes_, 0)
# update corresponding data
pod.update(label_counts)
# turn the value into ratio instead of prediction counts
for label, count in pod.items():
ratio: float = count/np.sum(counts)
if percentage:
pod[label] = ratio * 100
else:
pod[label] = ratio
return pod
def convert_keys_to_strings(obj):
"""
Recursively convert all dictionary keys to strings.
"""
if isinstance(obj, dict):
return {str(key): convert_keys_to_strings(value) for key, value in obj["data"].items()}
elif isinstance(obj, list):
return [convert_keys_to_strings(item) for item in obj["data"]]
else:
return obj
def inference(model_sensor_A_path: str, model_sensor_B_path: str, file_path: str):
# Generate column indices
column_index: List[Tuple[int, int]] = [
(i + 1, i + 26)
for i in range(5)
]
# Load a single case data
df: pd.DataFrame = pd.read_csv(file_path, delim_whitespace=True, skiprows=10, header=0, memory_map=True)
# Take case name
case_name: str = file_path.split("/")[-1].split(".")[0]
# Extract relevant columns for each sensor
column_data: List[Tuple[pd.Series[float], pd.Series[float]]] = [
(df.iloc[:, i[0]], df.iloc[:, i[1]])
for i in column_index
]
column_data_stft: List[Tuple[pd.DataFrame, pd.DataFrame]] = [
(compute_stft(sensor_A), compute_stft(sensor_B))
for (sensor_A, sensor_B) in column_data
]
# Load the model
model_sensor_A = load(model_sensor_A_path)
model_sensor_B = load(model_sensor_B_path)
res = {}
for i, (stft_A, stft_B) in enumerate(column_data_stft):
# Make predictions using the model
pred_A: list[int] = model_sensor_A.predict(stft_A)
pred_B: list[int] = model_sensor_B.predict(stft_B)
percentage_A = probability_damage(pred_A, model_sensor_A)
percentage_B = probability_damage(pred_B, model_sensor_B)
res[f"Column_{i+1}"] = {
"Sensor_A": {
# "Predictions": pred_A,
"PoD": percentage_A
},
"Sensor_B": {
# "Predictions": pred_B,
"PoD": percentage_B
}
}
final_res = {"data": res, "case": case_name}
return final_res
def heatmap(result, damage_classes: list[int] = [1, 2, 3, 4, 5, 6]):
from scipy.interpolate import RectBivariateSpline
resolution = 300
y = list(range(1, len(damage_classes)+1))
# length of column
x = list(range(len(result["data"])))
# X, Y = np.meshgrid(x, y)
Z = []
for _, column_data in result["data"].items():
sensor_a_pod = column_data['Sensor_A']['PoD']
Z.append([sensor_a_pod.get(cls, 0) for cls in damage_classes])
Z = np.array(Z).T
y2 = np.linspace(1, len(damage_classes), resolution)
x2 = np.linspace(0,4,resolution)
f = RectBivariateSpline(x, y, Z.T, kx=2, ky=2) # 2nd degree quadratic spline interpolation
Z2 = f(x2, y2).T.clip(0, 1) # clip to ignores negative values from cubic interpolation
X2, Y2 = np.meshgrid(x2, y2)
# breakpoint()
c = plt.pcolormesh(X2, Y2, Z2, cmap='jet', shading='auto')
# Add a colorbar
plt.colorbar(c, label='Probability of Damage (PoD)')
plt.gca().invert_xaxis()
plt.grid(True, linestyle='-', alpha=0.7)
plt.xticks(np.arange(int(X2.min()), int(X2.max())+1, 1))
plt.xlabel("Column Index")
plt.ylabel("Damage Index")
plt.title(result["case"])
# plt.xticks(ticks=x2, labels=[f'Col_{i+1}' for i in range(len(result))])
# plt.gca().xaxis.set_major_locator(MultipleLocator(65/4))
plt.show()
if __name__ == "__main__":
import matplotlib.pyplot as plt
import json
from scipy.interpolate import UnivariateSpline
result = inference(
"D:/thesis/models/Sensor A/SVM with StandardScaler and PCA.joblib",
"D:/thesis/models/Sensor B/SVM with StandardScaler and PCA.joblib",
"D:/thesis/data/dataset_B/zzzBD19.TXT"
)
# heatmap(result)
# Convert all keys to strings before dumping to JSON
# result_with_string_keys = convert_keys_to_strings(result)
# print(json.dumps(result_with_string_keys, indent=4))
# Create a 5x2 subplot grid (5 rows for each column, 2 columns for sensors)
fig, axes = plt.subplots(nrows=5, ncols=2, figsize=(5, 50))
# # Define damage class labels for x-axis
damage_classes = [1, 2, 3, 4, 5, 6]
# # Loop through each column in the data
for row_idx, (column_name, column_data) in enumerate(result['data'].items()):
# Plot Sensor A in the first column of subplots
sensor_a_pod = column_data['Sensor_A']['PoD']
x_values = list(range(len(damage_classes)))
y_values = [sensor_a_pod.get(cls, 0) for cls in damage_classes]
# x2 = np.linspace(1, 6, 100)
# interp = UnivariateSpline(x_values, y_values, s=0)
axes[row_idx, 0].plot(x_values, y_values, '-', linewidth=2, markersize=8)
axes[row_idx, 0].set_title(f"{column_name} - Sensor A", fontsize=10)
axes[row_idx, 0].set_xticks(x_values)
axes[row_idx, 0].set_xticklabels(damage_classes)
axes[row_idx, 0].set_ylim(0, 1.05)
axes[row_idx, 0].set_ylabel('Probability')
axes[row_idx, 0].set_xlabel('Damage Class')
axes[row_idx, 0].grid(True, linestyle='-', alpha=0.5)
# Plot Sensor B in the second column of subplots
sensor_b_pod = column_data['Sensor_B']['PoD']
y_values = [sensor_b_pod.get(cls, 0) for cls in damage_classes]
axes[row_idx, 1].plot(x_values, y_values, '-', linewidth=2, markersize=8)
axes[row_idx, 1].set_title(f"{column_name} - Sensor B", fontsize=10)
axes[row_idx, 1].set_xticks(x_values)
axes[row_idx, 1].set_xticklabels(damage_classes)
axes[row_idx, 1].set_ylim(0, 1.05)
axes[row_idx, 1].set_ylabel('Probability')
axes[row_idx, 1].set_xlabel('Damage Class')
axes[row_idx, 1].grid(True, linestyle='-', alpha=0.5)
# Adjust layout to prevent overlap
fig.tight_layout(rect=[0, 0, 1, 0.96]) # Leave space for suptitle
plt.subplots_adjust(hspace=1, wspace=0.3) # Adjust spacing between subplots
plt.suptitle(f"Case {result['case']}", fontsize=16, y=0.98) # Adjust suptitle position
plt.show()

View File

@@ -0,0 +1,271 @@
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from joblib import load
def create_ready_data(
stft_data_path: str,
stratify: np.ndarray = None,
) -> tuple[pd.DataFrame, np.ndarray]:
"""
Create a stratified train-test split from STFT data.
Parameters:
-----------
stft_data_path : str
Path to the directory containing STFT data files (e.g. 'data/converted/raw/sensor1')
stratify : np.ndarray, optional
Labels to use for stratified sampling
Returns:
--------
tuple
(pd.DataFrame, np.ndarray) - Combined data and corresponding labels
"""
ready_data = []
for file in os.listdir(stft_data_path):
ready_data.append(pd.read_csv(os.path.join(stft_data_path, file), skiprows=1))
y_data = [i for i in range(len(ready_data))] # TODO: Should be replaced with actual desired labels
# Combine all dataframes in ready_data into a single dataframe
if ready_data: # Check if the list is not empty
# Use pandas concat function instead of iterative concatenation
combined_data = pd.concat(ready_data, axis=0, ignore_index=True)
print(f"Type of combined data: {type(combined_data)}")
print(f"Shape of combined data: {combined_data.shape}")
else:
print("No data available in ready_data list")
combined_data = pd.DataFrame()
# Store the result in x1a for compatibility with subsequent code
X = combined_data
for i in range(len(y_data)):
y_data[i] = [y_data[i]] * ready_data[i].shape[0]
y_data[i] = np.array(y_data[i])
if y_data:
# Use numpy concatenate function instead of iterative concatenation
y = np.concatenate(y_data, axis=0)
else:
print("No labels available in y_data list")
y = np.array([])
return X, y
def train_and_evaluate_model(
model, model_name, sensor_label, x_train, y_train, x_test, y_test, export=None
):
"""
Train a machine learning model, evaluate its performance, and optionally export it.
This function trains the provided model on the training data, evaluates its
performance on test data using accuracy score, and can save the trained model
to disk if an export path is provided.
Parameters
----------
model : estimator object
The machine learning model to train.
model_name : str
Name of the model, used for the export filename and in the returned results.
sensor_label : str
Label identifying which sensor's data the model is being trained on.
x_train : array-like or pandas.DataFrame
The training input samples.
y_train : array-like
The target values for training.
x_test : array-like or pandas.DataFrame
The test input samples.
y_test : array-like
The target values for testing.
export : str, optional
Directory path where the trained model should be saved. If None, model won't be saved.
Returns
-------
dict
Dictionary containing:
- 'model': model_name (str)
- 'sensor': sensor_label (str)
- 'accuracy': accuracy percentage (float)
Example
-------
>>> from sklearn.svm import SVC
>>> from sklearn.model_selection import train_test_split
>>> X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2)
>>> result = train_and_evaluate_model(
... SVC(),
... "SVM",
... "sensor1",
... X_train,
... y_train,
... X_test,
... y_test,
... export="models/sensor1"
... )
>>> print(f"Model accuracy: {result['accuracy']:.2f}%")
"""
from sklearn.metrics import accuracy_score
result = {"model": model_name, "sensor": sensor_label, "success": False}
try:
import time
start_time = time.time()
# Train the model
model.fit(x_train, y_train)
result["elapsed_time_training"] = time.time() - start_time
try:
# Predict on the test set (validation)
start_time = time.time()
y_pred = model.predict(x_test)
result["elapsed_time_validation"] = time.time() - start_time
result["y_pred"] = y_pred # Convert to numpy array
except Exception as e:
result["error"] = f"Prediction error: {str(e)}"
return result
# Calculate accuracy
try:
accuracy = accuracy_score(y_test, y_pred) * 100
result["accuracy"] = accuracy
except Exception as e:
result["error"] = f"Accuracy calculation error: {str(e)}"
return result
# Export model if requested
if export:
try:
import joblib
full_path = os.path.join(export, f"{model_name}.joblib")
os.makedirs(os.path.dirname(full_path), exist_ok=True)
joblib.dump(model, full_path)
print(f"Model saved to {full_path}")
except Exception as e:
print(f"Warning: Failed to export model to {export}: {str(e)}")
result["export_error"] = str(e)
# Continue despite export error
result["success"] = True
return result
except Exception as e:
result["error"] = f"Training error: {str(e)}"
return result
def plot_confusion_matrix(results_sensor, y_test, title):
"""
Plot confusion matrices for each model in results_sensor1.
Parameters:
-----------
results_sensor1 : list
List of dictionaries containing model results.
x_test1 : array-like
Test input samples.
y_test : array-like
True labels for the test samples.
Returns:
--------
None
This function will display confusion matrices for each model in results_sensor1.
Example
-------
>>> results_sensor1 = [
... {'model': 'model1', 'accuracy': 95.0},
... {'model': 'model2', 'accuracy': 90.0}
... ]
>>> x_test1 = np.random.rand(100, 10) # Example test data
>>> y_test = np.random.randint(0, 2, size=100) # Example true labels
>>> plot_confusion_matrix(results_sensor1, x_test1, y_test)
"""
# Iterate through each model result and plot confusion matrix
for i in results_sensor:
model = load(f"D:/thesis/models/{i['sensor']}/{i['model']}.joblib")
cm = confusion_matrix(y_test, i['y_pred']) # -> ndarray
# get the class labels
labels = model.classes_
# Plot
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)
disp.plot(cmap=plt.cm.Blues) # You can change colormap
plt.title(f"{title}")
def calculate_label_percentages(labels):
"""
Calculate and print the percentage distribution of unique labels in a numpy array.
Parameters:
labels (np.array): Input array of labels.
Returns:
None
"""
# Count occurrences of each unique label
unique, counts = np.unique(labels, return_counts=True)
# Calculate percentages
percentages = (counts / len(labels)) * 100
# Build and print the result string
result = "\n".join([f"Label {label}: {percentage:.2f}%" for label, percentage in zip(unique, percentages)])
return print(result)
def inference_model(
models, raw_file, column_question: int = None
):
"""
Perform inference using a trained machine learning model on a raw vibration data file with questioned column grid.
Parameters
----------
model : dict with some exported model path
The trained machine learning model to use for inference.
x_test : array-like or pandas.DataFrame
The input samples for which predictions are to be made.
export : str, optional
Directory path where the predictions should be saved. If None, predictions won't be saved.
Returns
-------
np.ndarray
Array of predicted values.
Example
-------
>>> from sklearn.svm import SVC
>>> model = {"SVM": "models/sensor1/SVM.joblib", "SVM with PCA": "models/sensor1/SVM_with_PCA.joblib"}
>>> inference_model(model["SVM"], "zzzAD1.TXT", column_question=1)
"""
df = pd.read_csv(raw_file, delim_whitespace=True, skiprows=10, header=0, memory_map=True)
col_idx = []
for i in range(1,6):
idx = [i, i+5, i+10, i+15, i+20, i+25]
col_idx.append(idx)
vibration_data = df.iloc[:, column_question].values
# Perform STFT
from scipy.signal import stft, hann
freq, times, Zxx = stft(
vibration_data,
fs=1024,
window=hann(1024),
nperseg=1024,
noverlap=1024-512
)
data = pd.DataFrame(np.abs(Zxx).T, columns=[f"Freq_{freq:.2f}" for freq in np.linspace(0, 1024/2, Zxx.shape[1])])
data = data.rename(columns={"Freq_0.00": "00"}) # To match the model input format
model = load(models) # Load the model from the provided path
return calculate_label_percentages(model.predict(data.iloc[:21,:]))

156
code/src/process_stft.py Normal file
View File

@@ -0,0 +1,156 @@
import os
import pandas as pd
import numpy as np
from scipy.signal import stft
from scipy.signal.windows import hann
import glob
import multiprocessing # Added import for multiprocessing
from typing import Union, Tuple
# Define the base directory where DAMAGE_X folders are located
damage_base_path = 'D:/thesis/data/converted/raw'
# Define output directories for each sensor
output_dirs = {
'sensor1': os.path.join(damage_base_path, 'sensor1'),
'sensor2': os.path.join(damage_base_path, 'sensor2')
}
# Create output directories if they don't exist
for dir_path in output_dirs.values():
os.makedirs(dir_path, exist_ok=True)
# Define STFT parameters
# Number of damage cases (adjust as needed)
num_damage_cases = 6 # Change to 30 if you have 30 damage cases
# Function to perform STFT and return magnitude
def compute_stft(vibration_data: np.ndarray, return_param: bool = False) -> Union[pd.DataFrame, Tuple[pd.DataFrame, list[int, int, int]]]:
"""
Computes the Short-Time Fourier Transform (STFT) magnitude of the input vibration data.
Parameters
----------
vibration_data : numpy.ndarray
The input vibration data as a 1D NumPy array.
return_param : bool, optional
If True, the function returns additional STFT parameters (window size, hop size, and sampling frequency).
Defaults to False.
Returns
-------
pd.DataFrame
The transposed STFT magnitude, with frequencies as columns, if `return_param` is False.
tuple
If `return_param` is True, returns a tuple containing:
- pd.DataFrame: The transposed STFT magnitude, with frequencies as columns.
- list[int, int, int]: A list of STFT parameters [window_size, hop_size, Fs].
"""
window_size = 1024
hop_size = 512
window = hann(window_size)
Fs = 1024
frequencies, times, Zxx = stft(
vibration_data,
fs=Fs,
window=window,
nperseg=window_size,
noverlap=window_size - hop_size
)
stft_magnitude = np.abs(Zxx)
# Convert STFT result to DataFrame
df_stft = pd.DataFrame(
stft_magnitude.T,
columns=[f"Freq_{freq:.2f}" for freq in np.linspace(0, Fs/2, stft_magnitude.shape[1])]
)
# breakpoint()
if return_param:
return df_stft, [window_size, hop_size, Fs]
else:
return df_stft
def process_damage_case(damage_num):
damage_folder = os.path.join(damage_base_path, f'DAMAGE_{damage_num}')
if damage_num == 0:
# Number of test runs per damage case
num_test_runs = 120
else:
num_test_runs = 5
# Check if the damage folder exists
if not os.path.isdir(damage_folder):
print(f"Folder {damage_folder} does not exist. Skipping...")
return
# Process Sensor 1 and Sensor 2 separately
for sensor_num in [1, 2]:
aggregated_stft = [] # List to hold STFTs from all test runs
# Iterate over all test runs
for test_num in range(1, num_test_runs + 1):
# Construct the filename based on sensor number
# Sensor 1 corresponds to '_01', Sensor 2 corresponds to '_02'
sensor_suffix = f'_0{sensor_num}'
file_name = f'DAMAGE_{damage_num}_TEST{test_num}{sensor_suffix}.csv'
file_path = os.path.join(damage_folder, file_name)
# Check if the file exists
if not os.path.isfile(file_path):
print(f"File {file_path} does not exist. Skipping...")
continue
# Read the CSV file
try:
df = pd.read_csv(file_path)
except Exception as e:
print(f"Error reading {file_path}: {e}. Skipping...")
continue
# Ensure the CSV has exactly two columns: 'Timestamp (s)' and 'Sensor X'
if df.shape[1] != 2:
print(f"Unexpected number of columns in {file_path}. Expected 2, got {df.shape[1]}. Skipping...")
continue
vibration_data = df.iloc[:, 1].values
# Perform STFT
df_stft = compute_stft(vibration_data)
# only inlcude 21 samples vector features for first 45 num_test_runs else include 22 samples vector features
if damage_num == 0:
print(f"Processing damage_num = 0, test_num = {test_num}")
if test_num <= 45:
df_stft = df_stft.iloc[:22, :]
print(f"Reduced df_stft shape (21 samples): {df_stft.shape}")
else:
df_stft = df_stft.iloc[:21, :]
print(f"Reduced df_stft shape (22 samples): {df_stft.shape}")
# Append to the aggregated list
aggregated_stft.append(df_stft)
print(sum(df.shape[0] for df in aggregated_stft))
# Concatenate all STFT DataFrames vertically
if aggregated_stft:
df_aggregated = pd.concat(aggregated_stft, ignore_index=True)
# Define output filename
output_file = os.path.join(
output_dirs[f'sensor{sensor_num}'],
f'stft_data{sensor_num}_{damage_num}.csv'
)
# Save the aggregated STFT to CSV
with open(output_file, 'w') as file:
file.write('sep=,\n')
df_aggregated.to_csv(file, index=False)
print(f"Saved aggregated STFT for Sensor {sensor_num}, Damage {damage_num} to {output_file}")
else:
print(f"No STFT data aggregated for Sensor {sensor_num}, Damage {damage_num}.")
if __name__ == "__main__": # Added main guard for multiprocessing
with multiprocessing.Pool() as pool:
pool.map(process_damage_case, range(num_damage_cases + 1))

133
code/src/verify_stft.py Normal file
View File

@@ -0,0 +1,133 @@
import os
import pandas as pd
import numpy as np
from scipy.signal import stft, hann
import glob
# Define the base directory where DAMAGE_X folders are located
damage_base_path = 'D:/thesis/data/converted/raw/'
# Define sensor directories
sensor_dirs = {
'sensor1': os.path.join(damage_base_path, 'sensor1'),
'sensor2': os.path.join(damage_base_path, 'sensor2')
}
# Define STFT parameters
window_size = 1024
hop_size = 512
window = hann(window_size)
Fs = 1024
def verify_stft(damage_num, test_num, sensor_num):
"""
Verifies the STFT of an individual test run against the aggregated STFT data.
Parameters:
- damage_num (int): Damage case number.
- test_num (int): Test run number.
- sensor_num (int): Sensor number (1 or 2).
"""
# Mapping sensor number to suffix
sensor_suffix = f'_0{sensor_num}'
# Construct the file name for the individual test run
individual_file_name = f'DAMAGE_{damage_num}_TEST{test_num}{sensor_suffix}.csv'
individual_file_path = os.path.join(damage_base_path, f'DAMAGE_{damage_num}', individual_file_name)
# Check if the individual file exists
if not os.path.isfile(individual_file_path):
print(f"File {individual_file_path} does not exist. Skipping verification for this test run.")
return
# Read the individual test run CSV
try:
df_individual = pd.read_csv(individual_file_path)
except Exception as e:
print(f"Error reading {individual_file_path}: {e}. Skipping verification for this test run.")
return
# Ensure the CSV has exactly two columns: 'Timestamp (s)' and 'Sensor X'
if df_individual.shape[1] != 2:
print(f"Unexpected number of columns in {individual_file_path}. Expected 2, got {df_individual.shape[1]}. Skipping.")
return
# Extract vibration data
vibration_data = df_individual.iloc[:, 1].values
# Perform STFT
frequencies, times, Zxx = stft(
vibration_data,
fs=Fs,
window=window,
nperseg=window_size,
noverlap=window_size - hop_size
)
# Compute magnitude and transpose
stft_magnitude = np.abs(Zxx).T # Shape: (513, 513)
# Select random row indices to verify (e.g., 3 random rows)
np.random.seed(42) # For reproducibility
sample_row_indices = np.random.choice(stft_magnitude.shape[0], size=3, replace=False)
# Read the aggregated STFT CSV
aggregated_file_name = f'stft_data{sensor_num}_{damage_num}.csv'
aggregated_file_path = os.path.join(sensor_dirs[f'sensor{sensor_num}'], aggregated_file_name)
if not os.path.isfile(aggregated_file_path):
print(f"Aggregated file {aggregated_file_path} does not exist. Skipping verification for this test run.")
return
try:
df_aggregated = pd.read_csv(aggregated_file_path)
except Exception as e:
print(f"Error reading {aggregated_file_path}: {e}. Skipping verification for this test run.")
return
# Calculate the starting row index in the aggregated CSV
# Each test run contributes 513 rows
start_row = (test_num - 1) * 513
end_row = start_row + 513 # Exclusive
# Ensure the aggregated CSV has enough rows
if df_aggregated.shape[0] < end_row:
print(f"Aggregated file {aggregated_file_path} does not have enough rows for Test {test_num}. Skipping.")
return
# Extract the corresponding STFT block from the aggregated CSV
df_aggregated_block = df_aggregated.iloc[start_row:end_row].values # Shape: (513, 513)
# Compare selected rows
all_match = True
for row_idx in sample_row_indices:
individual_row = stft_magnitude[row_idx]
aggregated_row = df_aggregated_block[row_idx]
# Check if the rows are almost equal within a tolerance
if np.allclose(individual_row, aggregated_row, atol=1e-6):
verification_status = "MATCH"
else:
verification_status = "MISMATCH"
all_match = False
# Print the comparison details
print(f"Comparing Damage {damage_num}, Test {test_num}, Sensor {sensor_num}, Row {row_idx}: {verification_status}")
print(f"Individual STFT Row {row_idx}: {individual_row[:5]} ... {individual_row[-5:]}")
print(f"Aggregated STFT Row {row_idx + start_row}: {aggregated_row[:5]} ... {aggregated_row[-5:]}\n")
# If all sampled rows match, print a verification success message
if all_match:
print(f"STFT of DAMAGE_{damage_num}_TEST{test_num}_{sensor_num}.csv is verified. On `stft_data{sensor_num}_{damage_num}.csv` start at rows {start_row} to {end_row} with 513 rows.\n")
else:
print(f"STFT of DAMAGE_{damage_num}_TEST{test_num}_{sensor_num}.csv has discrepancies in `stft_data{sensor_num}_{damage_num}.csv` start at rows {start_row} to {end_row} with 513 rows.\n")
# Define the number of damage cases and test runs
num_damage_cases = 6 # Adjust to 30 as per your dataset
num_test_runs = 5
# Iterate through all damage cases, test runs, and sensors
for damage_num in range(1, num_damage_cases + 1):
for test_num in range(1, num_test_runs + 1):
for sensor_num in [1, 2]:
verify_stft(damage_num, test_num, sensor_num)

52
data/QUGS/test.py Normal file
View File

@@ -0,0 +1,52 @@
from data_preprocessing import *
from joblib import dump, load
# b = generate_damage_files_index(
# num_damage=6,
# file_index_start=1,
# col=5,
# base_path="D:/thesis/data/dataset_B",
# prefix="zzzBD",
# # undamage_file="zzzBU.TXT"
# )
# Example: Generate tuples with a special group of df0 at the beginning
special_groups_A = [
{'df_name': 'zzzAU.TXT', 'position': 0, 'size': 5} # Add at beginning
]
special_groups_B = [
{'df_name': 'zzzBU.TXT', 'position': 0, 'size': 5} # Add at beginning
]
# Generate the tuples with the special group
a_complement = [(comp)
for n in range(1, 31)
for comp in complement_pairs(n)]
a = generate_df_tuples(special_groups=a_complement, prefix="zzzAD")
# b_complement = [(comp)
# for n in range(1, 31)
# for comp in complement_pairs(n)]
# b = generate_df_tuples(special_groups=b_complement, prefix="zzzBD")
# a = generate_damage_files_index(
# num_damage=6,
# file_index_start=1,
# col=5,
# base_path="D:/thesis/data/dataset_A",
# prefix="zzzAD",
# # undamage_file="zzzBU.TXT"
# )
data_A = DataProcessor(file_index=a, base_path="D:/thesis/data/dataset_A", include_time=True)
# data_A.create_vector_column(overwrite=True)
# # data_A.create_limited_sensor_vector_column(overwrite=True)
data_A.export_to_csv("D:/thesis/data/converted/raw")
# data_B = DataProcessor(file_index=b, base_path="D:/thesis/data/dataset_B", include_time=True)
# data_B.create_vector_column(overwrite=True)
# # data_B.create_limited_sensor_vector_column(overwrite=True)
# data_B.export_to_csv("D:/thesis/data/converted/raw_B")
# a = load("D:/cache.joblib")
# breakpoint()

View File

@@ -1,8 +1,8 @@
# Processed Data Directory
# Raw Data Directory
## Overview
This `data/processed` directory contains structured data that has been processed and formatted for analysis. Each subdirectory within `processed` represents a different level of simulated damage, and each contains multiple test files from experiments conducted under that specific damage scenario.
This `data/raw` directory contains structured data that has been processed and formatted for analysis. Each subdirectory within `raw` represents a different level of simulated damage, and each contains multiple test files from experiments conducted under that specific damage scenario.
## Directory Structure
@@ -12,12 +12,12 @@ The directory is organized as follows:
data
└── processed
├── DAMAGE_1
│ ├── D1_TEST1.csv
│ ├── D1_TEST2.csv
├── D1_TEST1.csv
├── D1_TEST2.csv
│ ...
│ └── D1_TEST10.csv
└── D1_TEST10.csv
├── DAMAGE_2
│ ├── D2_TEST1.csv
├── D2_TEST1.csv
│ ...
├── DAMAGE_3
│ ...

66
docs/CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,66 @@
This document outlines the process for developing and contributing to my own thesis project. By following these guidelines, this will ensure consistent quality and maintain a clear development history.
## Development Workflow
### 1. Issue Creation
Before working on any new feature, experiment, or bug fix:
- Create a GitHub issue using the appropriate template
- Assign it to myself
- Add relevant labels
- Link it to the project board if applicable
### 2. Branching Strategy
Use the following branch naming convention:
- `feature/<issue-number>-short-description`
- `bugfix/<issue-number>-short-description`
- `experiment/<issue-number>-short-description`
- `doc/<issue-number>-short-description`
Always branch from `main` for new features/experiments.
### 3. Development Process
- Make regular, atomic commits following the commit message template
- Include the issue number in commit messages (e.g., "#42")
- Push changes at the end of each work session
### 4. Code Quality
- Follow PEP 8 guidelines for Python code
- Document functions with docstrings
- Maintain test coverage for custom functions
- Keep notebooks clean and well-documented
### 5. Pull Requests
Even working alone, use PRs for significant changes:
- Create a PR from your feature branch to `main`
- Reference the issue(s) it resolves
- Include a summary of changes
- Self-review the PR before merging
### 6. Versioning
Follow semantic versioning:
- Major version: Significant thesis milestones or structural changes
- Minor version: New experiments, features, or chapters
- Patch version: Bug fixes and minor improvements
### 7. Documentation
Update documentation with each significant change:
- Keep README current
- Update function documentation
- Maintain clear experiment descriptions in notebooks
- Record significant decisions and findings
## LaTeX Guidelines
- Use consistent citation style
- Break long sections into multiple files
- Use meaningful label names for cross-references
- Consider using version-control friendly LaTeX practices (one sentence per line)
## Experiment Tracking
For each experiment:
- Create an issue documenting the experiment design
- Reference related papers and previous experiments
- Document parameters and results in the notebook
- Summarize findings in the issue before closing
## Commit Categories
Use the categories defined in the commit template to clearly classify changes.

View File

@@ -13,29 +13,38 @@ processed_path = os.path.join(base_path, "processed")
os.makedirs(raw_path, exist_ok=True)
os.makedirs(processed_path, exist_ok=True)
for damage in range(1, 6): # 5 Damage levels
damage_folder = f"DAMAGE_{damage}"
damage_path = os.path.join(processed_path, damage_folder)
# Define the number of zeros to pad
num_damages = 5
num_tests = 10
num_sensors = 2
damage_pad = len(str(num_damages))
test_pad = len(str(num_tests))
sensor_pad = len(str(num_sensors))
for damage in range(1, num_damages + 1): # 5 Damage levels starts from 1
damage_folder = f"DAMAGE_{damage:0{damage_pad}}"
damage_path = os.path.join(raw_path, damage_folder)
os.makedirs(damage_path, exist_ok=True)
for test in range(1, 11): # 10 Tests per damage level
# Filename for the CSV
csv_filename = f"D{damage}_TEST{test}.csv"
csv_path = os.path.join(damage_path, csv_filename)
for sensor in range(1, 3): # 2 Sensors per test
# Filename for the CSV
csv_filename = f"D{damage:0{damage_pad}}_TEST{test:0{test_pad}}_{sensor:0{sensor_pad}}.csv"
csv_path = os.path.join(damage_path, csv_filename)
# Generate dummy data
num_rows = 10
start_time = datetime.now()
timestamps = [start_time + timedelta(seconds=i*0.0078125) for i in range(num_rows)]
values = np.random.randn(num_rows) # Random float values
# Generate dummy data
num_rows = 10
start_time = datetime.now()
timestamps = [start_time + timedelta(seconds=i*0.0078125) for i in range(num_rows)]
values = np.random.randn(num_rows) # Random float values
# Create DataFrame
df = pd.DataFrame({
"Time": timestamps,
"Value": values
})
# Create DataFrame
df = pd.DataFrame({
"Time": timestamps,
"Value": values
})
# Save the CSV file with a custom header
with open(csv_path, 'w') as file:
file.write('sep=,\n') # Writing the separator hint
df.to_csv(file, index=False)
# Save the CSV file with a custom header
with open(csv_path, 'w') as file:
file.write('sep=,\n') # Writing the separator hint
df.to_csv(file, index=False)

View File

@@ -0,0 +1,41 @@
2 %Nomor
%for mult rows
& %Judul Jurnal
Real-time vibration-based structural damage detection using one-dimensional convolutional neural networks \href{https://doi.org/10.1016/j.jsv.2016.10.043}{10.1016/j.jsv.
2016.10.043}
%for mult rows
% & %Author
% % Satish B Satpal; Yogesh Khandare; Anirban Guha; Sauvik Banerjee
% %for mult rows
% & %Nama Jurnal
% International Journal of Advanced Structural Engineering (IJASE)
% %for mult rows
% & %Sumber
% \href{http://dx.doi.org/10.1186/2008-6695-5-2}{ResearchGate}
% %for mult rows
% & %Tahun
% 2020
% %for mult rows
& %Tujuan penelitian
Mengidentifikasi lokasi kerusakan struktur secara \textit{real-time} dengan memproses sinyal getaran mentah yang diambil dari jaringan-jaringan akselerometer pada setiap titik tanpa proses tambahan atau ekstraksi fitur.
& %Kesimpulan
% Studi ini menilai kemampuan mesin vektor pendukung untuk memprediksi intensitas kerusakan dan lokasi pada balok kantilever. Meskipun berhasil memprediksi kerusakan dengan sedikit kesalahan, tingkat kebisingan dan lokasi kerusakan memengaruhi keakuratan. Tingkat kebisingan yang tinggi mempengaruhi kinerja secara signifikan, terutama pada intensitas kerusakan yang lebih rendah.
& % Gap Research
\begin{enumerate}
\item Riset ini hanya dilakukan dengan \textit{full-grid array} akselerometer yang diletakkan pada setiap \textit{node} kerusakan, sehingga memerlukan banyak perangkat akselerometer.
\item Tidak ada komparasi performa efisiensi dan akurasi dengan algoritma pembelajaran mesin lain yang lebih populer sebelumnya.
\end{enumerate}

View File

@@ -0,0 +1,68 @@
1
%for mult rows
&
Statistical Feature Extraction in Machine Fault Detection using Vibration Signal (\href{https://doi.org/10.1109/ICTC49870.2020.9289285}{10.1109/ICTC49870.
2020.9289285})
%for mult rows
% &
% Donghui Xu; Xiang Xu; Michael C. Forde; Antonio Caballero
%for mult rows
% &
% Construction and Building Materials
% %for mult rows
% &
% \href{https://doi.org/10.1016/j.conbuildmat.2023.132596}{ScienceDirect}
% %for mult rows
% &
% 2023
% %for mult rows
&
\begin{enumerate}[series=enum]
\item Menginvestigasi cara mengklasifikasi kondisi \textit{gearbox} normal dan rusak menggunakan sinyal getaran berbasis pada kombinasi antara analisis statistik dan FFT dengan algoritma pembelajaran mesin (ANN, Logistic Regression, dan SVM)
\item Mengurangi waktu latih dan kompleksitas kalkulasi dengan analisis statistik sebagai input data meliputi sembilan fitur: mean, median, min, max, kurtosis, \textit{skewness}, \textit{standard deviation}, and \textit{range}.
\end{enumerate}
&
\begin{enumerate}[series=enum2]
\item Nilai \textit{maximum} dan kurtosis adalah fitur yang paling signifikan untuk mengklasifikasi kelas label pembelajaran mesin.
\item ANN meraih akurasi 100\% pada input FFT penuh dan analisis statistik, sedangkan Regresi Logistik (LR) dan SVM meraih akurasi 100\% dengan input FFT penuh namun hanya mendapat akurasi 91\% dengan input analisis statistik
\end{enumerate}
&
\begin{enumerate}
\item Lorem
\item Ipsum
\end{enumerate}
%-------------page break----------------
% \\
% &
% &
% &
% &
% &
% &
% &
% \begin{enumerate}[resume=enum]
% \item Menyajikan berbagai perkembangan penelitian, mendiskusikan dan membandingkannya kelebihan dan kekurangannya
% \item Meringkas kesesuaian berbagai metode pembelajaran mesin untuk masalah SHM yang berbeda
% \item Terakhir, tren masa depan
% \end{enumerate}
% &
% \begin{enumerate}[resume=enum2]
% \item SVM dan hutan acak kurang mendapat perhatian dibandingkan dengan jaringan saraf. Ini digunakan untuk klasifikasi kerusakan. Namun, pemrosesan awal data jauh lebih rumit.
% \end{enumerate}

View File

@@ -0,0 +1,509 @@
\documentclass[12pt,a4paper]{report}
\usepackage{hyperref}
\usepackage[top=1cm,right=3cm,bottom=1cm,left=3cm]{geometry}
\usepackage{multirow}
\usepackage{array}
% \usepackage{makecell}
\usepackage{pdflscape}
\usepackage{longtable,booktabs}
\usepackage{colortbl,xcolor}
\usepackage{enumitem}
\usepackage{pdfpages}
\usepackage{caption}
\usepackage[bahasa]{babel}
\usepackage{xpatch,csquotes}
\usepackage[backend=biber]{biblatex}
\addbibresource{export.bib}
\DeclareSourcemap{
\maps[datatype = bibtex]{
\map{
\step[fieldsource = abstract,
match = \regexp{([^\\])\%},
replace = \regexp{\$1\\\%}]
}
}
}
% \usepackage{tablefootnote}
% \usepackage{showframe}
\definecolor{Gray}{gray}{0.95}
\newcolumntype{a}{>{\columncolor{Gray}}p}
\renewcommand{\thefootnote}{\textit{\alph{footnote}}}
% \newcolumntype{b}{>{\raggedright\arraybackslash}p}
\title{Tugas 2 \\ Metode Penelitian}
\author{Rifqi Damar Panuluh \\ 20210110224}
\begin{document}
\maketitle
\begin{landscape}
% Table generated by Excel2LaTeX from sheet 'Sheet1'
% \begin{table}[h]
\centering
\begin{longtable}{
>{\raggedleft\arraybackslash}p{0.02\linewidth} %1
>{\raggedright\arraybackslash}a{0.1\linewidth} %2
% >{\raggedright\arraybackslash}p{0.1\linewidth} %3
% >{\raggedright\arraybackslash}a{0.075\linewidth} %4
% p{0.065\linewidth} %5
% >{\raggedleft\arraybackslash}p{0.05\linewidth} %6
>{\raggedright\arraybackslash}p{0.25\linewidth} %7
>{\raggedright\arraybackslash}a{0.25\linewidth} %8
>{\raggedright\arraybackslash}p{0.25\linewidth} %9
}
\caption{Tinjauan pustaka, topik: pemanfaatan data getaran untuk monitor kesehatan struktur jembatan}
\label{tab:my_label}
\\
\toprule
\toprule
\rowcolor{white}
No. %1
&
Judul %2
% &
% Nama Penulis %3
% &
% Nama Jurnal %4
% &
% Sumber %5
% &
% Tahun %6
&
Tujuan Penelitian %7
&
Kesimpulan %8
&
Gap Research %9
\\\midrule
\endfirsthead
\toprule
\rowcolor{white}
No. %1
&
Judul %2
% &
% Nama Penulis %3
% &
% Nama Jurnal %4
% &
% Sumber %5
% &
% Tahun %6
&
Tujuan Penelitian %7
&
Kesimpulan %8
\\\midrule
\endhead
\midrule
\multicolumn{4}{r}{\textit{berlanjut di halaman berikutnya}}
\endfoot
\bottomrule
\bottomrule
\endlastfoot
%-----1
\input{important/van2020}
\\
%-----2
\input{important/abdeljaber2017}
\\
%------3
\\
3
& %Judul Jurnal
Real-time nondestructive structural health monitoring using support vector machines and wavelets (Ahmet Bulut; Ambuj K. Singh; Peter Shin; Tony Fountain; Hector Jasso; Linjun Yan; Ahmed Elgamal)
%for mult rows
% & %Author
% Ahmet Bulut; Ambuj K. Singh; Peter Shin; Tony Fountain; Hector Jasso; Linjun Yan; Ahmed Elgamal
%for mult rows
% & %Nama Jurnal
% Case Studies in Construction Materials 13 (2020) e00406
% %for mult rows
% & %Sumber
% SPIE
% %for mult rows
% & %Tahun
% 2005
%for mult rows
& %Tujuan penelitian
Eksplorasi efektivitas SVM dalam deteksi kerusakan; Validasi model SVM dengan data nyata jembatan
& %Kesimpulan
\begin{enumerate} [series=enum]
\item SVM menunjukkan akurasi tinggi dalam mengidentifikasi lokasi kerusakan
\item Rekomendasi untuk penyetelan parameter SVM
\end{enumerate}
%-----------4
\\
4
& %Judul Jurnal
A novel approach of Structural Health Monitoring by the application of FFT and wavelet transform using an index of frequency dispersion (Fragkiskos P. Pentaris; John Stonham; John P. Makris)
%for mult rows
% & %Author
% Fragkiskos P. Pentaris; John Stonham; John P. Makris
%for mult rows
% & %Nama Jurnal
% International Journal of Geology
% %for mult rows
% & %Sumber
% Research Gate
% %for mult rows
% & %Tahun
% 2013
%for mult rows
& %Tujuan penelitian
\begin{enumerate}
\item Memeriksa peran FFT dalam pemrosesan awal data getaran
\item Menilai dampak FFT terhadap keakuratan deteksi kerusakan
\end{enumerate}
& %Kesimpulan
\begin{enumerate} [series=enum]
\item FFT meningkatkan rasio \textit{signal-to-noise} dan meningkatkan deteksi kerusakan.
\item Menyarankan integrasi dengan algoritme lain untuk meningkatkan akurasi.
\end{enumerate}
\\ %-------------page break----------------
%-----------4
\\
5
& %Judul Jurnal
Review of Vibration-Based Structural Health Monitoring Using Deep Learning (Gyungmin Toh; Junhong Park)
%for mult rows
% & %Author
% Gyungmin Toh;
% Junhong Park
% %for mult rows
% & %Nama Jurnal
% Apllied Sciences
% %for mult rows
% & %Sumber
% MDPI
% %for mult rows
% & %Tahun
% 2020
%for mult rows
& %Tujuan penelitian
\begin{enumerate}
\item ringkasan studi penerapan algoritma pembelajaran mesin untuk kesalahan pemantauan (\textit{monitoring}) menggunakan faktor getaran untuk mengkategorikan penelitian.
\item Menyediakan interpretasi singkat tentang jaringan saraf dalam untuk pengaplikasian lebih lanjut dalam analisis getaran struktural.
\end{enumerate}
& %Kesimpulan
\begin{enumerate} [series=enum]
\item Deep learning has the advantage of being able to perform health monitoring on complex structures with high accuracy.
\end{enumerate}
%-------------page break----------------
%-----------4
\\
6
& %Judul Jurnal
A deep learning approach to condition monitoring of cantilever beams via time-frequency extended signatures (Habil. Darian M. Onchis)
%for mult rows
% & %Author
% Habil. Darian M. Onchis
% %for mult rows
% & %Nama Jurnal
% Computers in Industry
% %for mult rows
% & %Sumber
% Science Direct
% %for mult rows
% & %Tahun
% 2019
%for mult rows
& %Tujuan penelitian
\begin{enumerate}
\item ringkasan studi penerapan algoritma pembelajaran mesin untuk kesalahan pemantauan (\textit{monitoring}) menggunakan faktor getaran untuk mengkategorikan penelitian.
\item Menyediakan interpretasi singkat tentang jaringan saraf dalam untuk pengaplikasian lebih lanjut dalam analisis getaran struktural.
\end{enumerate}
& %Kesimpulan
\begin{enumerate} [series=enum]
\item Deep learning has the advantage of being able to perform health monitoring on complex structures with high accuracy.
\end{enumerate}
\\ %-------------page break----------------
% %------------5
% 5
% & %Judul Jurnal
% Advances and development trends in eco-friendly pavements
% %for mult rows
% & %Author
% Aimin Sha, Zhuangzhuang Liu, Wei Jiang, Lin Qi, Liqun Hu, Wenxiu Jiao ,Diego Maria Barbieri
% %for mult rows
% & %Nama Jurnal
% Journal of Road Engineering 1 (2021)
% %for mult rows
% & %Sumber
% ScienceDirect
% %for mult rows
% & %Tahun
% 2021
% %for mult rows
% & %Tujuan penelitian
% Mengembangkan solusi teknis untuk mengatasi tantangan yang terkait dengan penciptaan infrastruktur hijau dan berkelanjutan, misalnya, pengurangan dampak lingkungan, peningkatan keselamatan lalu lintas, dan efisiensi transportasi, dll.\cite{Sha2021}
% &
% \begin{enumerate} [series=enum]
% \item Temuan penelitian terbaru terkait jalan ramah lingkungan
% trotoar diringkas dan dibahas sesuai dengan enam kunci yang berbeda
% karakteristik: permeabel, pengurangan kebisingan, luminescence diri, knalpot
% dekomposisi, penyerapan panas rendah serta \textit{anti-icing} / \textit{de-icing}.\cite{Sha2021}
% \end{enumerate}
% \\
% & %Judul Jurnal
% Advances and development trends in eco-friendly pavements
% %for mult rows
% & %Author
% Aimin Sha, Zhuangzhuang Liu, Wei Jiang, Lin Qi, Liqun Hu, Wenxiu Jiao ,Diego Maria Barbieri
% %for mult rows
% & %Nama Jurnal
% Journal of Road Engineering 1 (2021)
% %for mult rows
% & %Sumber
% ScienceDirect
% %for mult rows
% & %Tahun
% 2021
% %for mult rows
% & %Tujuan penelitian
% Mengembangkan solusi teknis untuk mengatasi tantangan yang terkait dengan penciptaan infrastruktur hijau dan berkelanjutan, misalnya, pengurangan dampak lingkungan, peningkatan keselamatan lalu lintas, dan efisiensi transportasi, dll.\cite{Sha2021}
% &
% \begin{enumerate}[resume=enum]
% \item Teknologi ini dapat memecahkan beberapa tantangan utama yang terkait dengan konstruksi jalan dan lalu lintas (misalnya, kebisingan, efek pulau panas, dan pembangkitan polusi). Sebagian besar solusi saat ini hanya tersedia menampilkan satu fungsi ramah lingkungan pada satu waktu.\cite{Sha2021}
% \end{enumerate}
% %-----------5
% \\
% 5
% & %Judul Jurnal
% Micromobility injury events: Motor vehicle crashes and other transportation systems factors
% %for mult rows
% & %Author
% Kevin Fang
% %for mult rows
% & %Nama Jurnal
% Transportation Research Interdisciplinary Perspectives 14 (2022) 100574
% %for mult rows
% & %Sumber
% ScienceDirect
% %for mult rows
% & %Tahun
% 2022
% %for mult rows
% & %Tujuan penelitian
% Menginformasikan transportasi strategi kebijakan untuk mencoba dan meningkatkan kinerja keselamatan, Dengan cara mengeksplorasi keadaan di mana cedera pengendara mikromobilitas mengalami cederanya, dengan fokus pada faktor-faktor yang berkaitan dengan sistem transportasi.\cite{Fang2022}
% &
% \begin{enumerate} [series=enum]
% \item Kecelakaan kendaraan bermotor secara mengejutkan menjulang sebagai sesuatu yang kemungkinan adalah faktor umum dalam cedera mikromobilitas. Masalah perkerasan, konflik
% dengan pengguna non-otomatis, dan medan juga muncul sebagai faktor cedera yang terukur.\cite{Fang2022}
% \end{enumerate}
% \\
% & %Judul Jurnal
% Micromobility injury events: Motor vehicle crashes and other transportation systems factors
% %for mult rows
% & %Author
% Kevin Fang
% %for mult rows
% & %Nama Jurnal
% Transportation Research Interdisciplinary Perspectives 14 (2022) 100574
% %for mult rows
% & %Sumber
% ScienceDirect
% %for mult rows
% & %Tahun
% 2022
% %for mult rows
% & %Tujuan penelitian
% Menginformasikan transportasi strategi kebijakan untuk mencoba dan meningkatkan kinerja keselamatan, Dengan cara mengeksplorasi keadaan di mana cedera pengendara mikromobilitas mengalami cederanya, dengan fokus pada faktor-faktor yang berkaitan dengan sistem transportasi.\cite{Fang2022}
% &
% \begin{enumerate} [resume=enum]
% \item Di antara faktor-faktor yang berhubungan dengan transportasi, analisis regresi
% menunjukkan bahwa terluka dalam kecelakaan kendaraan bermotor atau di medan berbukit
% sesuai dengan kemungkinan yang lebih besar dari rawat inap dan cedera kepala.\cite{Fang2022}
% \end{enumerate}
% \\
% & %Judul Jurnal
% Micromobility injury events: Motor vehicle crashes and other transportation systems factors
% %for mult rows
% & %Author
% Kevin Fang
% %for mult rows
% & %Nama Jurnal
% Transportation Research Interdisciplinary Perspectives 14 (2022) 100574
% %for mult rows
% & %Sumber
% ScienceDirect
% %for mult rows
% & %Tahun
% 2022
% %for mult rows
% & %Tujuan penelitian
% Menginformasikan transportasi strategi kebijakan untuk mencoba dan meningkatkan kinerja keselamatan, Dengan cara mengeksplorasi keadaan di mana cedera pengendara mikromobilitas mengalami cederanya, dengan fokus pada faktor-faktor yang berkaitan dengan sistem transportasi.\cite{Fang2022}
% &
% \begin{enumerate} [resume=enum]
% \item Mitigasi yang berhasil yang memaksimalkan kinerja mode keselamatan mikromobilitas dapat membantu menarik dan mempertahankan pengguna dan menjaga kepercayaan dari pembuat kebijakan yang peduli keselamatan.\cite{Fang2022}
% \end{enumerate}
% \end{tabular}
\end{longtable}
% \end{table}
\end{landscape}
\clearpage
\pagenumbering{roman}
\setcounter{page}{2}
\thispagestyle{empty}
\printbibliography
\clearpage
\begin{titlepage}
\
\vfill
\centering\noindent \Huge{LAMPIRAN}
\vfill
\
\end{titlepage}
% \clearpage
% \thispagestyle{empty}
% \centering
% \frame{\includegraphics[page=1,scale=.7]{assets/1-s2.0-S2095756420300295-main.pdf}}
% \captionof{figure}{Halaman pertama jurnal pertama}
% \clearpage
% \thispagestyle{empty}
% \centering
% \frame{\includegraphics[page=1,scale=.7]{assets/1-s2.0-S2214509520300024-main.pdf}}
% \captionof{figure}{Halaman pertama jurnal kedua}
% \clearpage
% \thispagestyle{empty}
% \centering
% \frame{\includegraphics[page=1,scale=.7]{assets/1-s2.0-S2214509520300784-main.pdf}}
% \captionof{figure}{Halaman pertama jurnal ketiga}
% \clearpage
% \thispagestyle{empty}
% \centering
% \frame{\includegraphics[page=1,scale=.7]{assets/1-s2.0-S2097049821000044-main.pdf}}
% \captionof{figure}{Halaman pertama jurnal keempat}
% \clearpage
% \thispagestyle{empty}
% \centering
% \frame{\includegraphics[page=1,scale=.7]{assets/1-s2.0-S2590198222000379-main.pdf}}
% \captionof{figure}{Halaman pertama jurnal kelima}
\end{document}

373
latex/bahasa-apa.lbx Normal file
View File

@@ -0,0 +1,373 @@
\ProvidesFile{bahasa-apa.lbx}[2023/03/20\space v9.17\space APA biblatex localisation]
\InheritBibliographyExtras{bahasa}
\NewBibliographyString{publication}
\NewBibliographyString{jourarticle}
\NewBibliographyString{revisededition}
\NewBibliographyString{typevolume}
\NewBibliographyString{typevolumes}
\NewBibliographyString{typeseries}
\NewBibliographyString{typeseriess}
\NewBibliographyString{typevolseries}
\NewBibliographyString{typevolseriess}
\NewBibliographyString{chair}
\NewBibliographyString{chairs}
\NewBibliographyString{on}
\NewBibliographyString{retrieved}
\NewBibliographyString{available}
\NewBibliographyString{from}
\NewBibliographyString{archivedat}
\NewBibliographyString{origyear}
\NewBibliographyString{reviewof}
\NewBibliographyString{with}
\NewBibliographyString{supplement}
\NewBibliographyString{commenton}
\NewBibliographyString{manunpub}
\NewBibliographyString{maninprep}
\NewBibliographyString{mansub}
\NewBibliographyString{producer}
\NewBibliographyString{producers}
\NewBibliographyString{execproducer}
\NewBibliographyString{execproducers}
\NewBibliographyString{director}
\NewBibliographyString{directors}
\NewBibliographyString{execdirector}
\NewBibliographyString{execdirectors}
\NewBibliographyString{writer}
\NewBibliographyString{writers}
\NewBibliographyString{host}
\NewBibliographyString{hosts}
\NewBibliographyString{guestexpert}
\NewBibliographyString{guestexperts}
\NewBibliographyString{narrator}
\NewBibliographyString{narrators}
\NewBibliographyString{film}
\NewBibliographyString{tvseries}
\NewBibliographyString{tvepisode}
\NewBibliographyString{video}
\NewBibliographyString{song}
\NewBibliographyString{album}
\NewBibliographyString{podcast}
\NewBibliographyString{podcastepisode}
\NewBibliographyString{interview}
\NewBibliographyString{speech}
\NewBibliographyString{lithograph}
\NewBibliographyString{map}
\NewBibliographyString{lecturenotes}
\NewBibliographyString{powerpoint}
\NewBibliographyString{photograph}
\NewBibliographyString{photographs}
\NewBibliographyString{present}
\NewBibliographyString{painting}
\NewBibliographyString{article}
\NewBibliographyString{execorder}
\NewBibliographyString{senate}
\NewBibliographyString{resolution}
\NewBibliographyString{houseofrepresentatives}
\NewBibliographyString{report}
\NewBibliographyString{us}
\NewBibliographyString{southcarolina}
\NewBibliographyString{constitution}
\NewBibliographyString{section}
\NewBibliographyString{amendment}
\NewBibliographyString{proposed}
\NewBibliographyString{repealed}
\NewBibliographyString{unitednations}
\NewBibliographyString{charter}
\NewBibliographyString{ofthe}
\NewBibliographyString{tothe}
\NewBibliographyString{alabama}
\NewBibliographyString{alaska}
\NewBibliographyString{arizona}
\NewBibliographyString{arkansas}
\NewBibliographyString{california}
\NewBibliographyString{colorado}
\NewBibliographyString{connecticut}
\NewBibliographyString{delaware}
\NewBibliographyString{florida}
\NewBibliographyString{georgia}
\NewBibliographyString{hawaii}
\NewBibliographyString{idaho}
\NewBibliographyString{illinois}
\NewBibliographyString{indiana}
\NewBibliographyString{iowa}
\NewBibliographyString{kansas}
\NewBibliographyString{kentucky}
\NewBibliographyString{louisiana}
\NewBibliographyString{maine}
\NewBibliographyString{maryland}
\NewBibliographyString{massachusetts}
\NewBibliographyString{michigan}
\NewBibliographyString{minnesota}
\NewBibliographyString{mississippi}
\NewBibliographyString{missouri}
\NewBibliographyString{montana}
\NewBibliographyString{nebraska}
\NewBibliographyString{nevada}
\NewBibliographyString{newhampshire}
\NewBibliographyString{newjersey}
\NewBibliographyString{newmexico}
\NewBibliographyString{newyork}
\NewBibliographyString{northcarolina}
\NewBibliographyString{northdakota}
\NewBibliographyString{ohio}
\NewBibliographyString{oklahoma}
\NewBibliographyString{oregon}
\NewBibliographyString{pennsylvania}
\NewBibliographyString{rhodeisland}
\NewBibliographyString{southcarolina}
\NewBibliographyString{southdakota}
\NewBibliographyString{tennessee}
\NewBibliographyString{texas}
\NewBibliographyString{utah}
\NewBibliographyString{vermont}
\NewBibliographyString{virginia}
\NewBibliographyString{washington}
\NewBibliographyString{westvirginia}
\NewBibliographyString{wisconsin}
\NewBibliographyString{wyoming}
\DeclareBibliographyStrings{%
inherit = {bahasa},
jourarticle = {{artikel}{artikel}},
ofthe = {{dari}{dari}},
tothe = {{ke}{ke}},
unitednations = {{Perserikatan Bangsa-Bangsa}{P\adddot B\adddot B\adddot}},
charter = {{piagam}{piagam}},
proposed = {{diusulkan}{diusulkan}},
repealed = {{dicabut pada}{dicabut}},
execorder = {{Perintah Eksekutif}{Per\adddot\ Eksekutif}},
senate = {{Senate}{S\adddot}},
resolution = {{Resolusi}{Res\adddot}},
houseofrepresentatives = {{House\space of\space Representatives}{H\adddot R\adddot}},
report = {{Laporan}{Lap\adddot}},
us = {{A\adddot S\adddot}{A\adddot S\adddot}},
southcarolina = {{South\space Carolina}{S\adddot C\adddot}},
constitution = {{Constitution}{Const\adddot}},
section = {{Bagian}{§}},
amendment = {{amendemen}{amend\adddot}},
article = {{pasal}{ps\adddot}},
painting = {{lukisan}{lukisan}},
present = {{saat ini}{saat ini}},
song = {{lagu}{lagu}},
album = {{album}{album}},
map = {{peta}{peta}},
photograph = {{foto}{foto}},
photographs = {{foto}{foto}},
powerpoint = {{Salindia Powerpoint}{Salindia Powerpoint}},
lecturenotes = {{catatan kuliah}{catatan kuliah}},
podcast = {{siniar audio}{siniar audio}},
podcastepisode = {{episode siniar audio}{episode siniar audio}},
interview = {{wawancara}{wawancara}},
speech = {{rekaman audio pidato}{rekaman audio pidato}},
lithograph = {{litograf}{litograf}},
video = {{video}{video}},
film = {{film}{film}},
tvseries = {{serial TV}{serial TV}},
tvepisode = {{episode serial TV}{episode serial TV}},
manunpub = {{naskah tidak diterbitkan}{naskah tidak diterbitkan}},
maninprep = {{naskah dalam persiapan}{naskah dalam persiapan}},
mansub = {{naskah diserahkan untuk publikasi}{naskah diserahkan untuk publikasi}},
supplement = {{suplemen}{supl\adddot}},
revisededition = {{Edisi Revisi}{Ed\adddot\ Rev\adddot}},
reviewof = {{tinjauan atas}{tinjauan atas}},
page = {{Halaman}{hlm\adddot}},
pages = {{Halaman}{hlm\adddot}},
on = {{pada}{pada}},
retrieved = {{Diakses}{Diakses}},
available = {{Tersedia}{Tersedia}},
from = {{dari}{dari}},
archivedat = {{Diarsipkan di}{Diarsipkan di}},
with = {{dengan}{dengan}},
reprintas = {{dicetak ulang sebagai}{dicetak ulang sbg\adddot}},
reprintfrom = {{dicetak ulang dari}{dicetak ulang dari}},
commenton = {{komentar pada}{komentar pada}},
part = {{bagian}{bag\adddot}},
paragraph = {{Paragraf}{par\adddot}},
paragraphs = {{Paragraf}{par\adddot}},
narrator = {{narator}{nar\adddot}},
narrators = {{narator}{nar\adddot}},
producer = {{produser}{produser}},
producers = {{produser}{produser}},
execproducer = {{Produser Eksekutif}{Prod\adddot\ Eks\adddot}},
execproducers = {{Produser Eksekutif}{Prod\adddot\ Eks\adddot}},
execdirector = {{Direktur Eksekutif}{Dir\adddot\ Eks\adddot}},
execdirectors = {{Direktur Eksekutif}{Dir\adddot\ Eks\adddot}},
chair = {{Ketua}{Ketua}},
chairs = {{Ketua}{Ketua}},
director = {{sutradara}{sut\adddot}},
directors = {{sutradara}{sut\adddot}},
writer = {{penulis}{penulis}},
writers = {{penulis}{penulis}},
host = {{pembawa acara}{pembawa acara}},
hosts = {{pembawa acara}{pembawa acara}},
guestexpert = {{Pakar Tamu}{Pakar Tamu}},
guestexperts = {{Pakar Tamu}{Pakar Tamu}},
mathesis = {{Tesis magister}{Tesis magister}},
phdthesis = {{Disertasi doktoral}{Disertasi doktoral}},
origyear = {{karya asli terbit}{karya asli terbit}},
typevolume = {{Penyunting Volume}{Peny\adddot\ Vol\adddot}},
typevolumes = {{Penyunting Volume}{Peny\adddot\ Vol\adddot}},
typeseries = {{Penyunting Seri}{Peny\adddot\ Seri}},
typeseriess = {{Penyunting Seri}{Peny\adddot\ Seri}},
typevolseries = {{Penyunting Seri dan Volume}{Peny\adddot\ Seri & Vol\adddot}},
typevolseriess = {{Penyunting Seri dan Volume}{Peny\adddot\ Seri & Vol\adddot}},
annodomini = {{Masehi}{M\adddot}},
beforechrist = {{Sebelum Masehi}{SM\adddot}},
commonera = {{Masehi}{M\adddot}},
beforecommonera = {{Sebelum Masehi}{SM\adddot}},
alabama = {{Alabama}{{A\adddot L\adddot}}},
alaska = {{Alaska}{{A\adddot K\adddot}}},
arizona = {{Arizona}{{A\adddot Z\adddot}}},
arkansas = {{Arkansas}{{A\adddot R\adddot}}},
california = {{California}{{C\adddot A\adddot}}},
colorado = {{Colorado}{{C\adddot O\adddot}}},
connecticut = {{Connecticut}{{C\adddot T\adddot}}},
delaware = {{Delaware}{{D\adddot E\adddot}}},
florida = {{Florida}{{F\adddot L\adddot}}},
georgia = {{Georgia}{{G\adddot A\adddot}}},
hawaii = {{Hawaii}{{H\adddot I\adddot}}},
idaho = {{Idaho}{{I\adddot D\adddot}}},
illinois = {{Illinois}{{I\adddot L\adddot}}},
indiana = {{Indiana}{{I\adddot N\adddot}}},
iowa = {{Iowa}{{I\adddot A\adddot}}},
kansas = {{Kansas}{{K\adddot S\adddot}}},
kentucky = {{Kentucky}{{K\adddot Y\adddot}}},
louisiana = {{Louisiana}{{L\adddot A\adddot}}},
maine = {{Maine}{{M\adddot E\adddot}}},
maryland = {{Maryland}{{M\adddot D\adddot}}},
massachusetts = {{Massachusetts}{{M\adddot A\adddot}}},
michigan = {{Michigan}{{M\adddot I\adddot}}},
minnesota = {{Minnesota}{{M\adddot N\adddot}}},
mississippi = {{Mississippi}{{M\adddot S\adddot}}},
missouri = {{Missouri}{{M\adddot O\adddot}}},
montana = {{Montana}{{M\adddot T\adddot}}},
nebraska = {{Nebraska}{{N\adddot E\adddot}}},
nevada = {{Nevada}{{N\adddot V\adddot}}},
newhampshire = {{New Hampshire}{{N\adddot H\adddot}}},
newjersey = {{New Jersey}{{N\adddot J\adddot}}},
newmexico = {{New Mexico}{{N\adddot M\adddot}}},
newyork = {{New York}{{N\adddot Y\adddot}}},
northcarolina = {{North Carolina}{{N\adddot C\adddot}}},
northdakota = {{North Dakota}{{N\adddot D\adddot}}},
ohio = {{Ohio}{{O\adddot H\adddot}}},
oklahoma = {{Oklahoma}{{O\adddot K\adddot}}},
oregon = {{Oregon}{{O\adddot R\adddot}}},
pennsylvania = {{Pennsylvania}{{P\adddot A\adddot}}},
rhodeisland = {{Rhode Island}{{R\adddot I\adddot}}},
southcarolina = {{South Carolina}{{S\adddot C\adddot}}},
southdakota = {{South Dakota}{{S\adddot D\adddot}}},
tennessee = {{Tennessee}{{T\adddot N\adddot}}},
texas = {{Texas}{{T\adddot X\adddot}}},
utah = {{Utah}{{U\adddot T\adddot}}},
vermont = {{Vermont}{{V\adddot T\adddot}}},
virginia = {{Virginia}{{V\adddot A\adddot}}},
washington = {{Washington}{{W\adddot A\adddot}}},
westvirginia = {{West Virginia}{{W\adddot V\adddot}}},
wisconsin = {{Wisconsin}{{W\adddot I\adddot}}},
wyoming = {{Wyoming}{{W\adddot Y\adddot}}},
publication = {{Publikasi}{Publikasi}}
}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Drop end* when they are the same as *
% You must use \print*date to get here otherwise it will be ignored
\DeclareBibliographyExtras{%
\def\urldatecomma{\addcomma\addspace}%
\protected\def\mkbibdateapalong#1#2#3#4{%
% As per 10.1, Articles only have year
\ifboolexpr{ (test {\ifentrytype{article}}
or (test {\ifentrytype{inbook}} and not test {\ifnameundef{editor}}))
and not test {\iffieldequalstr{entrysubtype}{nonacademic}} }
{\clearfield{labelmonth}%
\clearfield{labelday}}
{}%
\iffieldundef{#1}% YEAR
{}%
{\iffieldbibstring{#1}{\bibncpstring{\thefield{#1}}}{\thefield{#1}}}%
\iffieldundef{#2}% YEARDIVISION
{}%
{\iffieldundef{#1}%
{}%
{\addcomma\addspace}%
\iffieldbibstring{#2}{\bibcplstring{\thefield{#2}}}{\thefield{#2}}}%
\iffieldundef{#3}% MONTH
{}%
{\iffieldundef{#1}%
{}%
{\addcomma\addspace}%
\mkbibmonth{\thefield{#3}}}%
\iffieldundef{#4}% DAY
{}%
{\iffieldundef{#3}%
{}%
{\addspace}%
\stripzeros{\thefield{#4}}}}%
\protected\def\mkbibdateapalongextra#1#2#3#4{%
% As per 10.1, Articles only have year
\ifboolexpr{ (test {\ifentrytype{article}}
or (test {\ifentrytype{inbook}} and not test {\ifnameundef{editor}}))
and not test {\iffieldequalstr{entrysubtype}{nonacademic}} }
{\clearfield{labelmonth}%
\clearfield{labelday}}
{}%
\iffieldundef{#1}% YEAR
{}%
{\iffieldbibstring{#1}{\bibncpstring{\thefield{#1}}}{\thefield{#1}}\printfield{extradate}}%
\iffieldundef{#2}% YEARDIVISION
{}%
{\iffieldundef{#1}%
{}%
{\addcomma\addspace}%
\iffieldbibstring{#2}{\bibcplstring{\thefield{#2}}}{\thefield{#2}}}%
\iffieldundef{#3}% MONTH
{}%
{\iffieldundef{#1}%
{}%
{\addcomma\addspace}%
\mkbibmonth{\thefield{#3}}}%
\iffieldundef{#4}% DAY
{}%
{\iffieldundef{#3}%
{}%
{\addspace}%
\stripzeros{\thefield{#4}}}}%
\protected\def\mkbibdateapalongmdy#1#2#3#4{%
% As per 10.1, Articles only have year
\ifboolexpr{ (test {\ifentrytype{article}}
or (test {\ifentrytype{inbook}} and not test {\ifnameundef{editor}}))
and not test {\iffieldequalstr{entrysubtype}{nonacademic}} }
{\clearfield{labelmonth}%
\clearfield{labelday}}
{}%
\iffieldundef{#2}% YEARDIVISION
{}%
{\iffieldundef{#1}%
{}%
{\addcomma\addspace}%
\iffieldbibstring{#2}{\bibcplstring{\thefield{#2}}}{\thefield{#2}}}%
\iffieldundef{#3}% MONTH
{}%
{\mkbibmonth{\thefield{#3}}}%
\iffieldundef{#4}% DAY
{}%
{\addspace}%
\stripzeros{\thefield{#4}}%
\iffieldundef{#1}% YEAR
{}%
{\iffieldundef{#4}%
{\iffieldundef{#3}%
{}%
{\addspace}}%
{\addcomma\addspace}%
\iffieldbibstring{#1}{\bibncpstring{\thefield{#1}}}{\thefield{#1}}}}}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\endinput

747
latex/bahasa.lbx Normal file
View File

@@ -0,0 +1,747 @@
\ProvidesFile{bahasa.lbx}
[\abx@lbxid]
\DeclareRedundantLanguages{english,american}{english,american,british,
canadian,australian,newzealand,USenglish,UKenglish}
\DeclareBibliographyExtras{%
\renewrobustcmd*{\bibdatesep}{-}%
\protected\def\bibrangedash{%
\textendash\penalty\hyphenpenalty}% breakable dash
\def\finalandcomma{\addcomma}%
\def\finalandsemicolon{\addsemicolon}%
\protected\def\mkbibordinal#1{%
\begingroup
\@tempcnta0#1\relax\number\@tempcnta
\@whilenum\@tempcnta>100\do{\advance\@tempcnta-100\relax}%
\ifnum\@tempcnta>20
\@whilenum\@tempcnta>9\do{\advance\@tempcnta-10\relax}%
\fi
\ifcase\@tempcnta th\or st\or nd\or rd\else th\fi
\endgroup}%
\protected\def\mkbibmascord{\mkbibordinal}%
\protected\def\mkbibfemord{\mkbibordinal}%
\protected\def\mkbibneutord{\mkbibordinal}%
\protected\def\mkbibdatelong#1#2#3{%
\iffieldundef{#2}
{}
{\mkbibmonth{\thefield{#2}}%
\iffieldundef{#3}
{\iffieldundef{#1}{}{\space}}
{\nobreakspace}}%
\iffieldundef{#3}
{}
{\stripzeros{\thefield{#3}}%
\iffieldundef{#1}{}{,\space}}%
\iffieldbibstring{#1}
{\bibstring{\thefield{#1}}}
{\dateeraprintpre{#1}\stripzeros{\thefield{#1}}}}%
\protected\def\mkbibdateshort#1#2#3{%
\iffieldundef{#3}
{}
{\mkdayzeros{\thefield{#3}}%
\iffieldundef{#2}
{\iffieldundef{#1}{}{\bibdatesep}}
{-}}%
\iffieldundef{#2}
{}
{\mkmonthzeros{\thefield{#2}}%
\iffieldundef{#1}{}{\bibdatesep}}%
\iffieldbibstring{#1}
{\bibstring{\thefield{#1}}}
{\dateeraprintpre{#1}\mkyearzeros{\thefield{#1}}}}%
\expandafter\protected\expandafter\def\csname mkbibtime24h\endcsname#1#2#3#4{%
\iffieldundef{#1}
{}
{\mktimezeros{\thefield{#1}}%
\iffieldundef{#2}{}{\bibtimesep}}%
\iffieldundef{#2}
{}
{\mktimezeros{\thefield{#2}}%
\iffieldundef{#3}{}{\bibtimesep}}%
\iffieldundef{#3}
{}
{\mktimezeros{\thefield{#3}}}%
\iffieldundef{#4}{}
{\bibtimezonesep
\mkbibtimezone{\thefield{#4}}}}%
\expandafter\protected\expandafter\def\csname mkbibtime12h\endcsname#1#2#3#4{%
\stripzeros{\mktimehh{\thefield{#1}}}%
\bibtimesep
\forcezerosmdt{\thefield{#2}}%
\iffieldundef{#3}{}
{\bibtimesep
\forcezerosmdt{\thefield{#3}}}%
\space
\ifnumless{\thefield{#1}}{12}
{\bibstring{am}}
{\bibstring{pm}}%
\iffieldundef{#4}{}
{\space\bibtimezonesep
\parentext{\mkbibtimezone{\thefield{#4}}}}}%
\protected\def\mkbibyeardivisiondateshort#1#2{%
\mkbibyeardivision{\thefield{#2}}%
\iffieldundef{#1}{}{\space}%
\dateeraprintpre{#1}\mkyearzeros{\thefield{#1}}}%
\protected\def\mkbibyeardivisiondatelong#1#2{%
\mkbibyeardivision{\thefield{#2}}%
\iffieldundef{#1}{}{\space}%
\dateeraprintpre{#1}\mkyearzeros{\thefield{#1}}}%
\savecommand\mkdaterangecomp
\savecommand\mkdaterangecompextra
\savecommand\mkdaterangeterse
\savecommand\mkdaterangeterseextra
\protected\def\mkdaterangecomp{%
\lbx@us@mkdaterangetrunc@long{long}}%
\protected\def\mkdaterangeterse{%
\lbx@us@mkdaterangetrunc@short{short}}%
\protected\def\mkdaterangecompextra{%
\lbx@us@mkdaterangetruncextra@long{long}}%
\protected\def\mkdaterangeterseextra{%
\lbx@us@mkdaterangetruncextra@short{short}}%
}
\UndeclareBibliographyExtras{%
\restorecommand\mkdaterangecomp
\restorecommand\mkdaterangecompextra
\restorecommand\mkdaterangeterse
\restorecommand\mkdaterangeterseextra
}
\DeclareBibliographyStrings{%
bibliography = {{Daftar Pustaka}{Daftar Pustaka}},
references = {{Referensi}{Referensi}},
shorthands = {{Daftar Singkatan}{Singkatan}},
editor = {{editor}{Ed\adddot}},
editors = {{editor}{Ed\adddot}},
compiler = {{penyusun}{pnysn\adddot}},
compilers = {{penyusun}{pnysn\adddot}},
redactor = {{redaktur}{red\adddot}},
redactors = {{redaktur}{red\adddot}},
reviser = {{perevisi}{perev\adddot}},
revisers = {{perevisi}{perev\adddot}},
founder = {{pendiri}{pendiri}},
founders = {{pendiri}{pendiri}},
continuator = {{pelanjut}{pelanj\adddot}}, % FIXME: unsure
continuators = {{pelanjut}{pelanj\adddot}}, % FIXME: unsure
collaborator = {{kolaborator}{kol\adddot}},
collaborators = {{kolaborator}{kol\adddot}},
translator = {{penerjemah}{penerj\adddot}},
translators = {{penerjemah}{penerj\adddot}},
commentator = {{komentator}{kom\adddot}},
commentators = {{komentator}{kom\adddot}},
annotator = {{anotator}{anot\adddot}},
annotators = {{anotator}{anot\adddot}},
commentary = {{komentar}{kom\adddot}},
annotations = {{anotasi}{anot\adddot}},
introduction = {{pengantar}{peng\adddot}},
foreword = {{kata pengantar}{kata peng\adddot}}, % FIXME: unsure shorthands
afterword = {{kata penutup}{kata pen\adddot}}, % FIXME: unsure shorthands
editortr = {{penyunting dan penerjemah}%
{peny\adddot\ dan penerj\adddot}},
editorstr = {{penyunting dan penerjemah}%
{peny\adddot\ dan penerj\adddot}},
editorco = {{penyunting dan komentator}%
{peny\adddot\ dan kom\adddot}},
editorsco = {{penyunting dan komentator}%
{peny\adddot\ dan kom\adddot}},
editoran = {{penyunting dan anotator}%
{peny\adddot\ dan anot\adddot}},
editorsan = {{penyunting dan anotator}%
{peny\adddot\ dan anot\adddot}},
editorin = {{penyunting dan pengantar}%
{peny\adddot\ dan peng\adddot}},
editorsin = {{penyunting dan pengantar}%
{peny\adddot\ dan peng\adddot}},
editorfo = {{penyunting dan kata pengantar}%
{peny\adddot\ dan kata peng\adddot}},
editorsfo = {{penyunting dan kata pengantar}%
{peny\adddot\ dan kata peng\adddot}},
editoraf = {{penyunting dan kata penutup}%
{peny\adddot\ dan kata pen\adddot}},
editorsaf = {{penyunting dan kata penutup}%
{peny\adddot\ dan kata pen\adddot}},
editortrco = {{penyunting, penerjemah, dan komentator}%
{peny\adddot, penerj\adddot, dan kom\adddot}},
editorstrco = {{penyunting, penerjemah, dan komentator}%
{peny\adddot, penerj\adddot, dan kom\adddot}},
editortran = {{penyunting, penerjemah, dan anotator}%
{peny\adddot, penerj\adddot, dan anot\adddot}},
editorstran = {{penyunting, penerjemah, dan anotator}%
{peny\adddot, penerj\adddot, dan anot\adddot}},
editortrin = {{penyunting, penerjemah, dan pengantar}%
{peny\adddot, penerj\adddot, dan peng\adddot}},
editorstrin = {{penyunting, penerjemah, dan pengantar}%
{peny\adddot, penerj\adddot, dan peng\adddot}},
editortrfo = {{penyunting, penerjemah, dan kata pengantar}%
{peny\adddot, penerj\adddot, dan kata peng\adddot}},
editorstrfo = {{penyunting, penerjemah, dan kata pengantar}%
{peny\adddot, penerj\adddot, dan kata peng\adddot}},
editortraf = {{penyunting, penerjemah, dan kata penutup}%
{peny\adddot, penerj\adddot, dan kata pen\adddot}},
editorstraf = {{penyunting, penerjemah, dan kata penutup}%
{peny\adddot, penerj\adddot, dan kata pen\adddot}},
editorcoin = {{penyunting, komentator, dan pengantar}%
{peny\adddot, kom\adddot, dan peng\adddot}},
editorscoin = {{penyunting, komentator, dan pengantar}%
{peny\adddot, kom\adddot, dan peng\adddot}},
editorcofo = {{penyunting, komentator, dan kata pengantar}%
{peny\adddot, kom\adddot, dan kata peng\adddot}},
editorscofo = {{penyunting, komentator, dan kata pengantar}%
{peny\adddot, kom\adddot, dan kata peng\adddot}},
editorcoaf = {{penyunting, komentator, dan kata penutup}%
{peny\adddot, kom\adddot, dan kata pen\adddot}},
editorscoaf = {{penyunting, komentator, dan kata penutup}%
{peny\adddot, kom\adddot, dan kata pen\adddot}},
editoranin = {{penyunting, anotator, dan pengantar}%
{peny\adddot, anot\adddot, dan peng\adddot}},
editorsanin = {{penyunting, anotator, dan pengantar}%
{peny\adddot, anot\adddot, dan peng\adddot}},
editoranfo = {{penyunting, anotator, dan kata pengantar}%
{peny\adddot, anot\adddot, dan kata peng\adddot}},
editorsanfo = {{penyunting, anotator, dan kata pengantar}%
{peny\adddot, anot\adddot, dan kata peng\adddot}},
editoranaf = {{penyunting, anotator, dan kata penutup}%
{peny\adddot, anot\adddot, dan kata pen\adddot}},
editorsanaf = {{penyunting, anotator, dan kata penutup}%
{peny\adddot, anot\adddot, dan kata pen\adddot}},
editortrcoin = {{penyunting, penerjemah, komentator, dan pengantar}%
{peny\adddot, penerj\adddot, kom\adddot, dan peng\adddot}},
editorstrcoin = {{penyunting, penerjemah, komentator, dan pengantar}%
{peny\adddot, penerj\adddot, kom\adddot, dan peng\adddot}},
editortrcofo = {{penyunting, penerjemah, komentator, dan kata pengantar}%
{peny\adddot, penerj\adddot, kom\adddot, dan kata peng\adddot}},
editorstrcofo = {{penyunting, penerjemah, komentator, dan kata pengantar}%
{peny\adddot, penerj\adddot, kom\adddot, dan kata peng\adddot}},
editortrcoaf = {{penyunting, penerjemah, komentator, dan kata penutup}%
{peny\adddot, penerj\adddot, kom\adddot, dan kata pen\adddot}},
editorstrcoaf = {{penyunting, penerjemah, komentator, dan kata penutup}%
{peny\adddot, penerj\adddot, kom\adddot, dan kata pen\adddot}},
editortranin = {{penyunting, penerjemah, anotator, dan pengantar}%
{peny\adddot, penerj\adddot, anot\adddot, dan peng\adddot}},
editorstranin = {{penyunting, penerjemah, anotator, dan pengantar}%
{peny\adddot, penerj\adddot, anot\adddot, dan peng\adddot}},
editortranfo = {{penyunting, penerjemah, anotator, dan kata pengantar}%
{peny\adddot, penerj\adddot, anot\adddot, dan kata peng\adddot}},
editorstranfo = {{penyunting, penerjemah, anotator, dan kata pengantar}%
{peny\adddot, penerj\adddot, anot\adddot, dan kata peng\adddot}},
editortranaf = {{penyunting, penerjemah, anotator, dan kata penutup}%
{peny\adddot, penerj\adddot, anot\adddot, dan kata pen\adddot}},
editorstranaf = {{penyunting, penerjemah, anotator, dan kata penutup}%
{peny\adddot, penerj\adddot, anot\adddot, dan kata pen\adddot}},
translatorco = {{penerjemah dan komentator}%
{penerj\adddot\ dan kom\adddot}},
translatorsco = {{penerjemah dan komentator}%
{penerj\adddot\ dan kom\adddot}},
translatoran = {{penerjemah dan anotator}%
{penerj\adddot\ dan anot\adddot}},
translatorsan = {{penerjemah dan anotator}%
{penerj\adddot\ dan anot\adddot}},
translatorin = {{penerjemahan dan pengantar}%
{penerj\adddot\ dan peng\adddot}},
translatorsin = {{penerjemahan dan pengantar}%
{penerj\adddot\ dan peng\adddot}},
translatorfo = {{penerjemahan dan kata pengantar}%
{penerj\adddot\ dan kata peng\adddot}},
translatorsfo = {{penerjemahan dan kata pengantar}%
{penerj\adddot\ dan kata peng\adddot}},
translatoraf = {{penerjemahan dan kata penutup}%
{penerj\adddot\ dan kata pen\adddot}},
translatorsaf = {{penerjemahan dan kata penutup}%
{penerj\adddot\ dan kata pen\adddot}},
translatorcoin = {{penerjemahan, komentar, dan pengantar}%
{penerj\adddot, kom\adddot, dan peng\adddot}},
translatorscoin = {{penerjemahan, komentar, dan pengantar}%
{penerj\adddot, kom\adddot, dan peng\adddot}},
translatorcofo = {{penerjemahan, komentar, dan kata pengantar}%
{penerj\adddot, kom\adddot, dan kata peng\adddot}},
translatorscofo = {{penerjemahan, komentar, dan kata pengantar}%
{penerj\adddot, kom\adddot, dan kata peng\adddot}},
translatorcoaf = {{penerjemahan, komentar, dan kata penutup}%
{penerj\adddot, kom\adddot, dan kata pen\adddot}},
translatorscoaf = {{penerjemahan, komentar, dan kata penutup}%
{penerj\adddot, kom\adddot, dan kata pen\adddot}},
translatoranin = {{penerjemahan, anotasi, dan pengantar}%
{penerj\adddot, anot\adddot, dan peng\adddot}},
translatorsanin = {{penerjemahan, anotasi, dan pengantar}%
{penerj\adddot, anot\adddot, dan peng\adddot}},
translatoranfo = {{penerjemahan, anotasi, dan kata pengantar}%
{penerj\adddot, anot\adddot, dan kata peng\adddot}},
translatorsanfo = {{penerjemahan, anotasi, dan kata pengantar}%
{penerj\adddot, anot\adddot, dan kata peng\adddot}},
translatoranaf = {{penerjemahan, anotasi, dan kata penutup}%
{penerj\adddot, anot\adddot, dan kata pen\adddot}},
translatorsanaf = {{penerjemahan, anotasi, dan kata penutup}%
{penerj\adddot, anot\adddot, dan kata pen\adddot}},
organizer = {{penyelenggara}{penyelenggara}},
organizers = {{penyelenggara}{penyelenggara}},
byorganizer = {{diselenggarakan oleh}{diselenggarakan oleh}},
byauthor = {{oleh}{oleh}},
byeditor = {{disunting oleh}{sun\adddot\ oleh}},
bycompiler = {{disusun oleh}{disusun oleh}},
byredactor = {{diredaksi oleh}{red\adddot\ oleh}},
byreviser = {{direvisi oleh}{direvisi oleh}},
byreviewer = {{ditinjau oleh}{ditinjau oleh}},
byfounder = {{didirikan oleh}{didirikan oleh}},
bycontinuator = {{dilanjutkan oleh}{dilanjutkan oleh}},
bycollaborator = {{berkolaborasi dengan}{berkolaborasi dengan}},
bytranslator = {{diterjemahkan \lbx@lfromlang\ oleh}{terj\adddot\ \lbx@sfromlang\ oleh}},
bycommentator = {{diberi komentar oleh}{diberi kom\adddot\ oleh}},
byannotator = {{dianotasi oleh}{dianotasi oleh}},
withcommentator = {{dengan komentar oleh}{dgn\adddot\ kom\adddot\ oleh}},
withannotator = {{dengan anotasi oleh}{dgn\adddot\ anot\adddot\ oleh}},
withintroduction = {{dengan pengantar oleh}{dgn\adddot\ peng\adddot\ oleh}},
withforeword = {{dengan kata pengantar oleh}{dgn\adddot\ kata peng\adddot\ oleh}},
withafterword = {{dengan kata penutup oleh}{dgn\adddot\ kata pen\adddot\ oleh}},
byeditortr = {{disunting dan diterjemahkan \lbx@lfromlang\ oleh}%
{sun\adddot\ dan terj\adddot\ \lbx@sfromlang\ oleh}},
byeditorco = {{disunting dan diberi komentar oleh}%
{sun\adddot\ dan diberi kom\adddot\ oleh}},
byeditoran = {{disunting dan dianotasi oleh}%
{sun\adddot\ dan dianotasi oleh}},
byeditorin = {{disunting, dengan pengantar, oleh}%
{sun\adddot, dgn\adddot\ peng\adddot, oleh}},
byeditorfo = {{disunting, dengan kata pengantar, oleh}%
{sun\adddot, dgn\adddot\ kata peng\adddot, oleh}},
byeditoraf = {{disunting, dengan kata penutup, oleh}%
{sun\adddot, dgn\adddot\ kata pen\adddot, oleh}},
byeditortrco = {{disunting, diterjemahkan \lbx@lfromlang, dan diberi komentar oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan diberi kom\adddot\ oleh}},
byeditortran = {{disunting, diterjemahkan \lbx@lfromlang, dan dianotasi oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan dianotasi oleh}},
byeditortrin = {{disunting dan diterjemahkan \lbx@lfromlang, dengan pengantar, oleh}%
{sun\adddot\ dan terj\adddot\ \lbx@sfromlang, dgn\adddot\ peng\adddot, oleh}},
byeditortrfo = {{disunting dan diterjemahkan \lbx@lfromlang, dengan kata pengantar, oleh}%
{sun\adddot\ dan terj\adddot\ \lbx@sfromlang, dgn\adddot\ kata peng\adddot, oleh}},
byeditortraf = {{disunting dan diterjemahkan \lbx@lfromlang, dengan kata penutup, oleh}%
{sun\adddot\ dan terj\adddot\ \lbx@sfromlang, dgn\adddot\ kata pen\adddot, oleh}},
byeditorcoin = {{disunting dan diberi komentar, dengan pengantar, oleh}%
{sun\adddot\ dan diberi kom\adddot, dgn\adddot\ peng\adddot, oleh}},
byeditorcofo = {{disunting dan diberi komentar, dengan kata pengantar, oleh}%
{sun\adddot\ dan diberi kom\adddot, dgn\adddot\ kata peng\adddot, oleh}},
byeditorcoaf = {{disunting dan diberi komentar, dengan kata penutup, oleh}%
{sun\adddot\ dan diberi kom\adddot, dgn\adddot\ kata pen\adddot, oleh}},
byeditoranin = {{disunting dan dianotasi, dengan pengantar, oleh}%
{sun\adddot\ dan dianotasi, dgn\adddot\ peng\adddot, oleh}},
byeditoranfo = {{disunting dan dianotasi, dengan kata pengantar, oleh}%
{sun\adddot\ dan dianotasi, dgn\adddot\ kata peng\adddot, oleh}},
byeditoranaf = {{disunting dan dianotasi, dengan kata penutup, oleh}%
{sun\adddot\ dan dianotasi, dgn\adddot\ kata pen\adddot, oleh}},
byeditortrcoin = {{disunting, diterjemahkan \lbx@lfromlang, dan diberi komentar, dengan pengantar, oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan diberi kom\adddot, dgn\adddot\ peng\adddot, oleh}},
byeditortrcofo = {{disunting, diterjemahkan \lbx@lfromlang, dan diberi komentar, dengan kata pengantar, oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan diberi kom\adddot, dgn\adddot\ kata peng\adddot, oleh}},
byeditortrcoaf = {{disunting, diterjemahkan \lbx@lfromlang, dan diberi komentar, dengan kata penutup, oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan diberi kom\adddot, dgn\adddot\ kata pen\adddot, oleh}},
byeditortranin = {{disunting, diterjemahkan \lbx@lfromlang, dan dianotasi, dengan pengantar, oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan dianotasi, dgn\adddot\ peng\adddot, oleh}},
byeditortranfo = {{disunting, diterjemahkan \lbx@lfromlang, dan dianotasi, dengan kata pengantar, oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan dianotasi, dgn\adddot\ kata peng\adddot, oleh}},
byeditortranaf = {{disunting, diterjemahkan \lbx@lfromlang, dan dianotasi, dengan kata penutup, oleh}%
{sun\adddot, terj\adddot\ \lbx@sfromlang, dan dianotasi, dgn\adddot\ kata pen\adddot, oleh}},
bytranslatorco = {{diterjemahkan \lbx@lfromlang\ dan diberi komentar oleh}%
{terj\adddot\ \lbx@sfromlang\ dan diberi kom\adddot\ oleh}},
bytranslatoran = {{diterjemahkan \lbx@lfromlang\ dan dianotasi oleh}%
{terj\adddot\ \lbx@sfromlang\ dan dianotasi oleh}},
bytranslatorin = {{diterjemahkan \lbx@lfromlang, dengan pengantar, oleh}%
{terj\adddot\ \lbx@sfromlang, dgn\adddot\ peng\adddot, oleh}},
bytranslatorfo = {{diterjemahkan \lbx@lfromlang, dengan kata pengantar, oleh}%
{terj\adddot\ \lbx@sfromlang, dgn\adddot\ kata peng\adddot, oleh}},
bytranslatoraf = {{diterjemahkan \lbx@lfromlang, dengan kata penutup, oleh}%
{terj\adddot\ \lbx@sfromlang, dgn\adddot\ kata pen\adddot, oleh}},
bytranslatorcoin = {{diterjemahkan \lbx@lfromlang\ dan diberi komentar, dengan pengantar, oleh}%
{terj\adddot\ \lbx@sfromlang, dan diberi kom\adddot, dgn\adddot\ peng\adddot, oleh}},
bytranslatorcofo = {{diterjemahkan \lbx@lfromlang\ dan diberi komentar, dengan kata pengantar, oleh}%
{terj\adddot\ \lbx@sfromlang, dan diberi kom\adddot, dgn\adddot\ kata peng\adddot, oleh}},
bytranslatorcoaf = {{diterjemahkan \lbx@lfromlang\ dan diberi komentar, dengan kata penutup, oleh}%
{terj\adddot\ \lbx@sfromlang, dan diberi kom\adddot, dgn\adddot\ kata pen\adddot, oleh}},
bytranslatoranin = {{diterjemahkan \lbx@lfromlang\ dan dianotasi, dengan pengantar, oleh}%
{terj\adddot\ \lbx@sfromlang, dan dianotasi, dgn\adddot\ peng\adddot, oleh}},
bytranslatoranfo = {{diterjemahkan \lbx@lfromlang\ dan dianotasi, dengan kata pengantar, oleh}%
{terj\adddot\ \lbx@sfromlang, dan dianotasi, dgn\adddot\ kata peng\adddot, oleh}},
bytranslatoranaf = {{diterjemahkan \lbx@lfromlang\ dan dianotasi, dengan kata penutup, oleh}%
{terj\adddot\ \lbx@sfromlang, dan dianotasi, dgn\adddot\ kata pen\adddot, oleh}},
and = {{dan}{dan}},
andothers = {{dan kawan-kawan}{dkk\adddot}},
andmore = {{dan kawan-kawan}{dkk\adddot}},
volume = {{volume}{vol\adddot}},
volumes = {{volume}{vol\adddot}},
involumes = {{dalam}{dalam}},
jourvol = {{volume}{vol\adddot}},
jourser = {{seri}{ser\adddot}},
book = {{buku}{buku}},
part = {{bagian}{bag\adddot}},
issue = {{nomor}{no\adddot}},
newseries = {{seri baru}{ser\adddot\ baru}},
oldseries = {{seri lama}{ser\adddot\ lama}},
edition = {{edisi}{ed\adddot}},
reprint = {{cetak ulang}{cet\adddot\ ul\adddot}},
reprintof = {{cetakan ulang dari}{cet\adddot\ ul\adddot\ dari}},
reprintas = {{dicetak ulang sebagai}{dicetak ulang sbg\adddot}},
reprintfrom = {{dicetak ulang dari}{dicetak ulang dari}},
reviewof = {{tinjauan dari}{tinjauan dari}},
translationof = {{terjemahan dari}{terj\adddot\ dari}},
translationas = {{diterjemahkan sebagai}{diterj\adddot\ sbg\adddot}},
translationfrom = {{diterjemahkan dari}{diterj\adddot\ dari}},
origpubas = {{pertama kali terbit sebagai}{pertama terbit sbg\adddot}},
origpubin = {{pertama kali terbit dalam}{pertama terbit dlm\adddot}},
astitle = {{sebagai}{sbg\adddot}},
bypublisher = {{oleh}{oleh}},
nodate = {{tanpa tanggal}{t.t\adddot}},
page = {{halaman}{hlm\adddot}},
pages = {{halaman}{hlm\adddot}},
column = {{kolom}{kol\adddot}},
columns = {{kolom}{kol\adddot}},
line = {{baris}{brs\adddot}},
lines = {{baris}{brs\adddot}},
verse = {{ayat}{ayat}},
verses = {{ayat}{ayat}},
section = {{bagian}{\S}},
sections = {{bagian}{\S\S}},
paragraph = {{paragraf}{par\adddot}},
paragraphs = {{paragraf}{par\adddot}},
pagetotal = {{halaman}{hlm\adddot}},
pagetotals = {{halaman}{hlm\adddot}},
columntotal = {{kolom}{kol\adddot}},
columntotals = {{kolom}{kol\adddot}},
linetotal = {{baris}{brs\adddot}},
linetotals = {{baris}{brs\adddot}},
versetotal = {{ayat}{ayat}},
versetotals = {{ayat}{ayat}},
sectiontotal = {{bagian}{\S}},
sectiontotals = {{bagian}{\S\S}},
paragraphtotal = {{paragraf}{par\adddot}},
paragraphtotals = {{paragraf}{par\adddot}},
in = {{dalam}{dalam}},
inseries = {{dalam seri}{dalam seri}},
ofseries = {{dari seri}{dari seri}},
number = {{nomor}{no\adddot}},
chapter = {{bab}{bab}},
bathesis = {{skripsi}{skripsi}},
mathesis = {{tesis}{tesis}},
phdthesis = {{disertasi}{disertasi}},
candthesis = {{tesis kandidat}{tesis kand\adddot}},% FIXME: unsure
resreport = {{laporan penelitian}{lap\adddot\ pen\adddot}},
techreport = {{laporan teknis}{lap\adddot\ tek\adddot}},
software = {{perangkat lunak}{perangkat lunak}},
datacd = {{CD-ROM}{CD-ROM}},
audiocd = {{CD audio}{CD audio}},
version = {{versi}{ver}},
url = {{URL}{URL}},
urlfrom = {{tersedia dari}{tersedia dari}},
urlseen = {{diakses pada}{diakses pada}},
inpreparation = {{dalam persiapan}{dalam persiapan}},
submitted = {{diserahkan}{diserahkan}},
forthcoming = {{akan terbit}{akan terbit}},
inpress = {{dalam proses cetak}{dalam proses cetak}},
prepublished = {{praterbit}{praterbit}},
citedas = {{selanjutnya dikutip sebagai}{selanjutnya dikutip sbg\adddot}},
thiscite = {{khususnya}{khususnya}},
seenote = {{lihat catatan}{lih\adddot\ ctt\adddot}},
quotedin = {{dikutip dalam}{dikutip dlm\adddot}},
idem = {{idem}{idem}},
idemsm = {{idem}{idem}},
idemsf = {{eadem}{eadem}},
idemsn = {{idem}{idem}},
idempm = {{eidem}{eidem}},
idempf = {{eaedem}{eaedem}},
idempn = {{eadem}{eadem}},
idempp = {{eidem}{eidem}},
ibidem = {{ibidem}{ibid\adddot}},
opcit = {{op\adddotspace cit\adddot}{op\adddotspace cit\adddot}},
loccit = {{loc\adddotspace cit\adddot}{loc\adddotspace cit\adddot}},
confer = {{bandingkan}{bdk\adddot}},
sequens = {{sq\adddot}{sq\adddot}},
sequentes = {{sqq\adddot}{sqq\adddot}},
passim = {{passim}{passim}},
see = {{lihat}{lih\adddot}},
seealso = {{lihat juga}{lih\adddot\ juga}},
backrefpage = {{dikutip pada halaman}{dikutip hlm\adddot}},
backrefpages = {{dikutip pada halaman}{dikutip hlm\adddot}},
january = {{Januari}{Jan\adddot}},
february = {{Februari}{Feb\adddot}},
march = {{Maret}{Mar\adddot}},
april = {{April}{Apr\adddot}},
may = {{Mei}{Mei}},
june = {{Juni}{Jun\adddot}},
july = {{Juli}{Jul\adddot}},
august = {{Agustus}{Ags\adddot}},
september = {{September}{Sep\adddot}},
october = {{Oktober}{Okt\adddot}},
november = {{November}{Nov\adddot}},
december = {{Desember}{Des\adddot}},
langamerican = {{Amerika}{Amerika}},
langbasque = {{Bask}{Bask}},
langbrazilian = {{Brasil}{Brasil}},
langbulgarian = {{Bulgaria}{Bulgaria}},
langcatalan = {{Katala}{Katala}},
langcroatian = {{Kroasia}{Kroasia}},
langczech = {{Ceko}{Ceko}},
langdanish = {{Denmark}{Denmark}},
langdutch = {{Belanda}{Belanda}},
langenglish = {{Inggris}{Inggris}},
langestonian = {{Estonia}{Estonia}},
langfinnish = {{Finlandia}{Finlandia}},
langfrench = {{Prancis}{Prancis}},
langgalician = {{Galisia}{Galisia}},
langgerman = {{Jerman}{Jerman}},
langgreek = {{Yunani}{Yunani}},
langhungarian = {{Hungaria}{Hungaria}},
langitalian = {{Italia}{Italia}},
langjapanese = {{Jepang}{Jepang}},
langlatin = {{Latin}{Latin}},
langlatvian = {{Latvia}{Latvia}},
langlithuanian = {{Lituania}{Lituania}},
langmarathi = {{Marathi}{Marathi}},
langnorwegian = {{Norwegia}{Norwegia}},
langpolish = {{Polandia}{Polandia}},
langportuguese = {{Portugis}{Portugis}},
langromanian = {{Rumania}{Rumania}},
langrussian = {{Rusia}{Rusia}},
langserbian = {{Serbia}{Serbia}},
langslovak = {{Slowakia}{Slowakia}},
langslovene = {{Slovenia}{Slovenia}},
langspanish = {{Spanyol}{Spanyol}},
langswedish = {{Swedia}{Swedia}},
langturkish = {{Turki}{Turki}},
langukrainian = {{Ukraina}{Ukraina}},
fromamerican = {{dari bahasa Amerika}{dari bahasa Amerika}},
frombasque = {{dari bahasa Bask}{dari bahasa Bask}},
frombrazilian = {{dari bahasa Brasil}{dari bahasa Brasil}},
frombulgarian = {{dari bahasa Bulgaria}{dari bahasa Bulgaria}},
fromcatalan = {{dari bahasa Katala}{dari bahasa Katala}},
fromcroatian = {{dari bahasa Kroasia}{dari bahasa Kroasia}},
fromczech = {{dari bahasa Ceko}{dari bahasa Ceko}},
fromdanish = {{dari bahasa Denmark}{dari bahasa Denmark}},
fromdutch = {{dari bahasa Belanda}{dari bahasa Belanda}},
fromenglish = {{dari bahasa Inggris}{dari bahasa Inggris}},
fromestonian = {{dari bahasa Estonia}{dari bahasa Estonia}},
fromfinnish = {{dari bahasa Finlandia}{dari bahasa Finlandia}},
fromfrench = {{dari bahasa Prancis}{dari bahasa Prancis}},
fromgalician = {{dari bahasa Galisia}{dari bahasa Galisia}},
fromgerman = {{dari bahasa Jerman}{dari bahasa Jerman}},
fromgreek = {{dari bahasa Yunani}{dari bahasa Yunani}},
fromhungarian = {{dari bahasa Hungaria}{dari bahasa Hungaria}},
fromitalian = {{dari bahasa Italia}{dari bahasa Italia}},
fromjapanese = {{dari bahasa Jepang}{dari bahasa Jepang}},
fromlatin = {{dari bahasa Latin}{dari bahasa Latin}},
fromlatvian = {{dari bahasa Latvia}{dari bahasa Latvia}},
fromlithuanian = {{dari bahasa Lituania}{dari bahasa Lituania}},
frommarathi = {{dari bahasa Marathi}{dari bahasa Marathi}},
fromnorwegian = {{dari bahasa Norwegia}{dari bahasa Norwegia}},
frompolish = {{dari bahasa Polandia}{dari bahasa Polandia}},
fromportuguese = {{dari bahasa Portugis}{dari bahasa Portugis}},
fromromanian = {{dari bahasa Rumania}{dari bahasa Rumania}},
fromrussian = {{dari bahasa Rusia}{dari bahasa Rusia}},
fromserbian = {{dari bahasa Serbia}{dari bahasa Serbia}},
fromslovak = {{dari bahasa Slowakia}{dari bahasa Slowakia}},
fromslovene = {{dari bahasa Slovenia}{dari bahasa Slovenia}},
fromspanish = {{dari bahasa Spanyol}{dari bahasa Spanyol}},
fromswedish = {{dari bahasa Swedia}{dari bahasa Swedia}},
fromturkish = {{dari bahasa Turki}{dari bahasa Turki}},
fromukrainian = {{dari bahasa Ukraina}{dari bahasa Ukraina}},
countryde = {{Jerman}{DE}},
countryeu = {{Uni Eropa}{UE}},
countryep = {{Uni Eropa}{UE}},
countryfr = {{Prancis}{FR}},
countryuk = {{Britania Raya}{GB}},
countryus = {{Amerika Serikat}{AS}},
patent = {{paten}{pat\adddot}},
patentde = {{paten Jerman}{pat\adddot\ Jerman}},
patenteu = {{paten Eropa}{pat\adddot\ Eropa}},
patentfr = {{paten Prancis}{pat\adddot\ Prancis}},
patentuk = {{paten Britania}{pat\adddot\ Britania}},
patentus = {{paten A.S.}{pat\adddot\ A\adddot S\adddot}},
patreq = {{permohonan paten}{permohonan pat\adddot}},
patreqde = {{permohonan paten Jerman}{permohonan pat\adddot\ Jerman}},
patreqeu = {{permohonan paten Eropa}{permohonan pat\adddot\ Eropa}},
patreqfr = {{permohonan paten Prancis}{permohonan pat\adddot\ Prancis}},
patrequk = {{permohonan paten Britania}{permohonan pat\adddot\ Britania}},
patrequs = {{permohonan paten A.S.}{permohonan pat\adddot\ A\adddot S\adddot}},
file = {{berkas}{berkas}},
library = {{perpustakaan}{perpustakaan}},
abstract = {{abstrak}{abstrak}},
annotation = {{anotasi}{anotasi}},
commonera = {{era umum}{CE}}, % FIXME: inconsistent shorthands
beforecommonera = {{sebelum era umum}{BCE}}, % FIXME: inconsistent shorthands
annodomini = {{masehi}{M}},
beforechrist = {{sebelum masehi}{SM}},
circa = {{circa}{ca\adddot}},
spring = {{musim semi}{musim semi}},% FIXME: unsure
summer = {{musim panas}{musim panas}},% FIXME: unsure
autumn = {{musim gugur}{musim gugur}},% FIXME: unsure
winter = {{musim dingin}{musim dingin}},% FIXME: unsure
springN = {{musim semi (belahan utara)}{musim semi (BU)}},% FIXME: unsure
summerN = {{musim panas (belahan utara)}{musim panas (BU)}},% FIXME: unsure
autumnN = {{musim gugur (belahan utara)}{musim gugur (BU)}},% FIXME: unsure
winterN = {{musim dingin (belahan utara)}{musim dingin (BU)}},% FIXME: unsure
springS = {{musim semi (belahan selatan)}{musim semi (BS)}},% FIXME: unsure
summerS = {{musim panas (belahan selatan)}{musim panas (BS)}},% FIXME: unsure
autumnS = {{musim gugur (belahan selatan)}{musim gugur (BS)}},% FIXME: unsure
winterS = {{musim dingin (belahan selatan)}{musim dingin (BS)}},% FIXME: unsure
Q1 = {{kuartal 1}{K1}},
Q2 = {{kuartal 2}{K2}},
Q3 = {{kuartal 3}{K3}},
Q4 = {{kuartal 4}{K4}},
QD1 = {{caturwulan 1}{QD1}},% FIXME: unsure
QD2 = {{caturwulan 2}{QD2}},% FIXME: unsure
QD3 = {{caturwulan 3}{QD3}},% FIXME: unsure
S1 = {{semester 1}{S1}},
S2 = {{semester 2}{S2}},
am = {{AM}{AM}},
pm = {{PM}{PM}},
}
\protected\gdef\lbx@us@mkdaterangetrunc@long#1#2{%
\blx@if@printanytimes{#2}
{\mkdaterangefull{#1}{#2}}
{\lbx@us@mkdaterangetrunc@long@i{#1}{#2}}}
\protected\gdef\lbx@us@mkdaterangetrunc@long@i#1#2{%
\begingroup
\blx@metadateinfo{#2}%
\iffieldundef{#2year}
{\blx@nounit}
{\printtext[{#2date}]{%
\datecircaprint
\iffieldundef{#2yeardivision}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibdate#1}{}{#2month}{#2day}}
{\csuse{mkbibdate#1}{#2year}{#2month}{#2day}%
\dateeraprint{#2year}}}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibyeardivisiondate#1}{}{#2yeardivision}}
{\csuse{mkbibyeardivisiondate#1}{#2year}{#2yeardivision}%
\dateeraprint{#2year}}}%
\dateuncertainprint
\iffieldundef{#2endyear}
{}
{\iffieldequalstr{#2endyear}{}
{\mbox{\bibdaterangesep}}
{\bibdaterangesep
\enddatecircaprint
\iffieldundef{#2endyeardivision}
{\ifdateyearsequal{#2}{#2end}
{\iffieldsequal{#2month}{#2endmonth}
{\csuse{mkbibdate#1}{#2endyear}{}{#2endday}}
{\csuse{mkbibdate#1}{#2endyear}{#2endmonth}{#2endday}}}
{\csuse{mkbibdate#1}{#2endyear}{#2endmonth}{#2endday}}}
{\csuse{mkbibyeardivisiondate#1}{#2endyear}{#2endyeardivision}}%
\enddateuncertainprint
\dateeraprint{#2endyear}}}}}%
\endgroup}
\protected\gdef\lbx@us@mkdaterangetrunc@short#1#2{%
\blx@if@printanytimes{#2}
{\mkdaterangefull{#1}{#2}}
{\lbx@us@mkdaterangetrunc@short@i{#1}{#2}}}
\protected\gdef\lbx@us@mkdaterangetrunc@short@i#1#2{%
\begingroup
\blx@metadateinfo{#2}%
\iffieldundef{#2year}
{\blx@nounit}
{\printtext[{#2date}]{%
\datecircaprint
\iffieldundef{#2yeardivision}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibdate#1}{}{#2month}{#2day}}
{\csuse{mkbibdate#1}{#2year}{#2month}{#2day}%
\dateeraprint{#2year}}}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibyeardivisiondate#1}{}{#2yeardivision}}
{\csuse{mkbibyeardivisiondate#1}{#2year}{#2yeardivision}%
\dateeraprint{#2year}}}%
\dateuncertainprint
\iffieldundef{#2endyear}
{}
{\iffieldequalstr{#2endyear}{}
{\mbox{\bibdaterangesep}}
{\bibdaterangesep
\enddatecircaprint
\iffieldundef{#2endyeardivision}
{\csuse{mkbibdate#1}{#2endyear}{#2endmonth}{#2endday}}
{\csuse{mkbibyeardivisiondate#1}{#2endyear}{#2endyeardivision}}%
\enddateuncertainprint
\dateeraprint{#2endyear}}}}}%
\endgroup}
\protected\gdef\lbx@us@mkdaterangetruncextra@long#1#2{%
\blx@if@printanytimes{#2}
{\mkdaterangefullextra{#1}{#2}}
{\lbx@us@mkdaterangetruncextra@long@i{#1}{#2}}}
\protected\gdef\lbx@us@mkdaterangetruncextra@long@i#1#2{%
\begingroup
\blx@metadateinfo{#2}%
\iffieldundef{#2year}
{\blx@nounit}
{\printtext[{#2date}]{%
\datecircaprint
\iffieldundef{#2yeardivision}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibdate#1}{}{#2month}{#2day}}
{\csuse{mkbibdate#1}{#2year}{#2month}{#2day}%
\dateeraprint{#2year}}}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibyeardivisiondate#1}{}{#2yeardivision}}
{\csuse{mkbibyeardivisiondate#1}{#2year}{#2yeardivision}%
\dateeraprint{#2year}}}%
\dateuncertainprint
\iffieldundef{#2endyear}
{\printfield{extradate}}
{\iffieldequalstr{#2endyear}{}
{\printfield{extradate}%
\mbox{\bibdaterangesep}}
{\bibdaterangesep
\enddatecircaprint
\iffieldundef{#2endyeardivision}
{\ifdateyearsequal{#2}{#2end}
{\iffieldsequal{#2month}{#2endmonth}
{\csuse{mkbibdate#1}{#2endyear}{}{#2endday}}
{\csuse{mkbibdate#1}{#2endyear}{#2endmonth}{#2endday}}}
{\csuse{mkbibdate#1}{#2endyear}{#2endmonth}{#2endday}}}
{\csuse{mkbibyeardivisiondate#1}{#2endyear}{#2endyeardivision}}%
\printfield{extradate}%
\enddateuncertainprint
\dateeraprint{#2endyear}}}}}%
\endgroup}
\protected\gdef\lbx@us@mkdaterangetruncextra@short#1#2{%
\blx@if@printanytimes{#2}
{\mkdaterangefullextra{#1}{#2}}
{\lbx@us@mkdaterangetruncextra@short@i{#1}{#2}}}
\protected\gdef\lbx@us@mkdaterangetruncextra@short@i#1#2{%
\begingroup
\blx@metadateinfo{#2}%
\iffieldundef{#2year}
{\blx@nounit}
{\printtext[{#2date}]{%
\datecircaprint
\iffieldundef{#2yeardivision}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibdate#1}{}{#2month}{#2day}}
{\csuse{mkbibdate#1}{#2year}{#2month}{#2day}%
\dateeraprint{#2year}}}
{\ifdateyearsequal{#2}{#2end}
{\csuse{mkbibyeardivisiondate#1}{}{#2yeardivision}}
{\csuse{mkbibyeardivisiondate#1}{#2year}{#2yeardivision}%
\dateeraprint{#2year}}}%
\dateuncertainprint
\iffieldundef{#2endyear}
{\printfield{extradate}}
{\iffieldequalstr{#2endyear}{}
{\printfield{extradate}%
\mbox{\bibdaterangesep}}
{\bibdaterangesep
\enddatecircaprint
\iffieldundef{#2endyeardivision}
{\csuse{mkbibdate#1}{#2endyear}{#2endmonth}{#2endday}}
{\csuse{mkbibyeardivisiondate#1}{#2endyear}{#2endyeardivision}}%
\printfield{extradate}%
\enddateuncertainprint
\dateeraprint{#2endyear}}}}}%
\endgroup}
\endinput

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,63 @@
\chapter{TINJAUAN PUSTAKA DAN LANDASAN TEORI}
\section{Tinjauan Pustaka}
\begin{figure}[!ht]
\centering
\includegraphics[width=0.5\linewidth]{frontmatter/img/slice1.jpg}
\caption{Enter Caption}
\label{fig:enter-label}
\end{figure}
\section{Dasar Teori}
This chapter discusses the theoretical basis used in this research, including signal processing techniques and machine learning algorithms. These foundations form the core of the method used for vibration-based damage localization in a beam structure.
\subsection{Short-Time Fourier Transform (STFT)}
The Short-Time Fourier Transform (STFT) is a fundamental technique used to analyze non-stationary signals, such as those generated by structures under dynamic load or white noise excitation. While the traditional Fourier Transform provides frequency-domain information, it lacks time resolution. STFT overcomes this limitation by applying the Fourier Transform over short overlapping segments of the signal, thereby producing a time-frequency representation.
Mathematically, the STFT of a signal $x(t)$ is given by:
\begin{equation}
X(t, \omega) = \int_{-\infty}^{\infty} x(\tau) w(\tau - t) e^{-j \omega \tau} d\tau
\end{equation}
where $w(\tau - t)$ is a window function centered at time $t$, and $\omega$ is the angular frequency.
In this study, the STFT is employed to extract the time-frequency features of the vibration signals collected from the structure. These features are then used as inputs to machine learning classifiers. This process captures localized frequency content over time, which is crucial in identifying structural changes due to damage.
\subsection{Classification Algorithms}
This research evaluates five classical machine learning algorithms to perform the classification task of damage localization. Each algorithm has different strengths and limitations, and their performance is benchmarked to identify the most suitable one for the given dataset.
\subsubsection{Support Vector Machine (SVM)}
SVM is a supervised learning algorithm that seeks an optimal hyperplane that separates data into classes with maximum margin. SVM performs well in high-dimensional spaces and is robust to overfitting, especially in cases with a clear margin of separation.
SVM is appropriate for vibration signal classification due to its capability to handle nonlinear decision boundaries when equipped with kernel functions.
\subsubsection{K-Nearest Neighbors (KNN)}
KNN is a non-parametric, instance-based learning algorithm. It classifies a new data point based on the majority vote of its $k$ nearest neighbors in the feature space. Although simple, KNN can be effective when the data is well-distributed and class boundaries are smooth.
Its performance is sensitive to the choice of $k$ and distance metric. For high-dimensional data like STFT features, dimensionality reduction or careful scaling may be required.
\subsubsection{Decision Tree (DT)}
Decision Tree is a rule-based classifier that splits data into classes using feature thresholds. It builds a tree where each internal node represents a feature, each branch a decision rule, and each leaf a class label. DTs are easy to interpret and can capture non-linear relationships.
However, they are prone to overfitting, especially with noisy or small datasets.
\subsubsection{Random Forest (RF)}
Random Forest is an ensemble learning method based on constructing multiple decision trees during training and outputting the mode of the classes for classification. It improves the generalization capability of individual trees and reduces overfitting.
RF is suitable for damage detection as it provides robustness to noise and variance, making it ideal for real-world sensor data.
\subsubsection{Naïve Bayes (NB)}
Naïve Bayes is a probabilistic classifier based on Bayes' theorem, assuming feature independence. Despite its simplicity, it often performs well in high-dimensional problems and with small datasets.
NB is particularly effective when class-conditional independence holds approximately, which may occur when STFT features are well-separated in distribution.
\bigskip
These theoretical foundations provide the methodological framework for implementing and evaluating the proposed damage localization system in this research. The combination of time-frequency analysis using STFT and classical machine learning classifiers enables an efficient and interpretable approach to structural health monitoring.
% \subsubsection{Dolor}

View File

@@ -0,0 +1,67 @@
\chapter{METODE PENELITIAN}
\section{Bahan dan Materi}
Penelitian ini menggunakan data sekunder dari \textcite{abdeljaber2017}, yang tersedia secara publik dan diperoleh melalui eksperimen menggunakan \textit{Queen's University Grandstand Simulator}. Adapun rincian data yang digunakan adalah sebagai berikut:
\begin{itemize}
\item Dataset terdiri atas rekaman respons getaran dari struktur rangka baja berukuran $6 \times 5$ yang dilengkapi dengan 30 akselerometer.
\item Setiap skenario dalam dataset mencakup satu kasus struktur tanpa kerusakan (healthy) dan 30 kasus kerusakan tunggal pada masing-masing sambungan (\textit{single-joint damage}).
\item Sinyal getaran direkam dengan frekuensi pengambilan sampel sebesar 1024 Hz selama durasi 256 detik untuk tiap skenario.
\item Kerusakan struktur disimulasikan dengan cara mengendurkan baut pada sambungan-sambungan tertentu.
\end{itemize}
Struktur dataset yang digunakan ditampilkan pada Gambar~\ref{fig:original-data}.
\begin{figure}[!ht]
\centering
\includegraphics[width=0.5\textwidth]{chapters/img/original_data.png}
\caption{Overview of the original data used from Abdeljaber et al. (2017)}
\label{fig:original-data}
\end{figure}
\clearpage
\section{Alat}
Berikut merupakan perangkat lunak yang digunakan selama proses penelitian ini:
\begin{itemize}
\item \textbf{Python 3.11} digunakan untuk proses pra-pemrosesan data, pemodelan, dan evaluasi.
\item \textbf{NumPy, SciPy, dan Pandas} digunakan untuk manipulasi sinyal dan perhitungan numerik.
\item \textbf{Matplotlib} digunakan untuk menghasilkan spektrum STFT (Short-Time Fourier Transform).
\item \textbf{PyTorch 2.3} digunakan untuk membangun dan melatih model dengan algoritma pemelajaran mesin klasik.
\item \textbf{Google Colab / Komputer Lokal} digunakan untuk pelatihan model dan percobaan eksperimental.
\end{itemize}
% \section{Place and Time}
% This research was conducted between [Month] and [Month] 2025 at the [Your Lab or Campus] using publicly available data. No new data collection was performed. All computational processes, including preprocessing, model training, and evaluation, were executed using Google Colab and a local machine.
\section{Langkah-Langkah Penelitian}
Alur keseluruhan penelitian ini dilakukan melalui tahapan-tahapan sebagai berikut:
\begin{enumerate}
\item \textbf{Akuisisi Data:} Mengunduh dataset dari Abdeljaber et al. yang berisi sinyal percepatan untuk 31 kondisi struktur (1 kondisi sehat dan 30 kondisi kerusakan tunggal).
\item \textbf{Seleksi Sensor:} Memilih sinyal dari sejumlah sensor terbatas pada garis vertikal tertentu (misalnya, node 1 dan 26) untuk mensimulasikan konfigurasi sensor yang direduksi.
\item \textbf{Pra-pemrosesan:} Melakukan normalisasi dan mengubah sinyal domain waktu mentah menjadi domain waktu-frekuensi menggunakan metode Short-Time Fourier Transform (STFT).
\item \textbf{Ekstraksi Fitur:} Menghasilkan \textit{data frame} frekuensi dalam domain waktu.
\item \textbf{Pengembangan Model:} Membangun dan melatih model klasifikasi berbasis algoritma pemelajaran mesin klasik (SVM, LDA, Bagged Trees, Random Forest, XGBoost) untuk mengklasifikasikan lokasi kerusakan struktur.
\item \textbf{Evaluasi:} Mengevaluasi kinerja model menggunakan metrik akurasi, presisi, dan confusion matrix pada berbagai skenario pengujian.
\end{enumerate}
\section{Data Analysis}
The processed data were analyzed using classification metrics. The trained model's output was evaluated based on the ability to correctly identify damaged vs. undamaged scenarios. The main metrics used were:
\begin{itemize}
\item \textbf{Accuracy:} Overall correct predictions across all classes.
\item \textbf{Confusion Matrix:} To visualize classification performance across damage cases.
\item \textbf{Precision and Recall:} For measuring the model's performance in detecting damage cases specifically.
\end{itemize}
Additionally, experiments were repeated for varying numbers of sensors to simulate reduced-sensor configurations, analyzing how model performance changed with less input data.

View File

@@ -0,0 +1,10 @@
\chapter{LITERATURE REVIEW AND THEORITICAL FOUNDATION}
\section{Literature Review}
\input{chapters/id/02_literature_review/literature_review/abdeljaber2017}
\section{Theoritical Foundation}
\input{chapters/id/02_literature_review/theoritical_foundation/stft}
\input{chapters/id/02_literature_review/theoritical_foundation/machine_learning}
\bigskip
These theoretical foundations provide the methodological framework for implementing and evaluating the proposed damage localization system in this research. The combination of time-frequency analysis using STFT and classical machine learning classifiers enables an efficient and interpretable approach to structural health monitoring.

View File

@@ -0,0 +1,6 @@
Traditional structural health monitoring methods often rely on hand-crafted features and manually tuned classifiers, which pose challenges in terms of generalization, reliability, and computational efficiency. As highlighted by [Author(s), Year], these approaches frequently require a trial-and-error process for feature and classifier selection, which not only reduces their robustness across structures but also hinders their deployment in real-time applications due to the computational load of the feature extraction phase.
[Author(s), Year] introduced a CNN-based structural damage detection approach validated through a large-scale grandstand simulator at Qatar University. The structure, designed to replicate modern stadiums, was equipped with 30 accelerometers and subjected to controlled damage by loosening beam-to-girder bolts. Acceleration data, collected under band-limited white noise excitation and sampled at 1024 Hz, were segmented into 128-sample frames for training localized 1D CNNs—one per joint—creating a decentralized detection system. Across two experimental phases, involving both partial and full-structure monitoring, the method demonstrated high accuracy in damage localization, achieving a training classification error of just 0.54\%. While performance remained strong even under double-damage scenarios, some misclassifications occurred in symmetric or adjacent damage cases. Overall, the proposed method presents a highly efficient and accurate solution for real-time SHM applications.
In the context of this thesis, the dataset and experimental setup introduced by [Author(s), Year] form the foundation for comparative analysis and algorithm testing. The authors have not only demonstrated the efficacy of a compact 1D CNN-based system for vibration-based structural damage detection, but also highlighted the value of using output-only acceleration data—a constraint shared in this thesiss methodology. The decentralized design of their system, which allows each CNN to process only locally available data, is particularly aligned with this thesis's focus on efficient, sensor-level data analysis without requiring full-system synchronization. Furthermore, since the authors indicate plans to publicly release their dataset and source code, this thesis leverages that open data for applying alternative analysis methods such as support vector machines (SVM) or frequency domain feature extraction techniques, allowing a direct performance comparison between classical and deep learning-based SHM approaches. Thus, this work serves as both a benchmark reference and a data source in the development and evaluation of more accessible, lower-complexity alternatives for structural health monitoring systems.

View File

@@ -0,0 +1,33 @@
\subsection{Classification Algorithms}
This research evaluates five classical machine learning algorithms to perform the classification task of damage localization. Each algorithm has different strengths and limitations, and their performance is benchmarked to identify the most suitable one for the given dataset.
\subsubsection{Support Vector Machine (SVM)}
SVM is a supervised learning algorithm that seeks an optimal hyperplane that separates data into classes with maximum margin. SVM performs well in high-dimensional spaces and is robust to overfitting, especially in cases with a clear margin of separation.
SVM is appropriate for vibration signal classification due to its capability to handle nonlinear decision boundaries when equipped with kernel functions.
\subsubsection{K-Nearest Neighbors (KNN)}
KNN is a non-parametric, instance-based learning algorithm. It classifies a new data point based on the majority vote of its $k$ nearest neighbors in the feature space. Although simple, KNN can be effective when the data is well-distributed and class boundaries are smooth.
Its performance is sensitive to the choice of $k$ and distance metric. For high-dimensional data like STFT features, dimensionality reduction or careful scaling may be required.
\subsubsection{Decision Tree (DT)}
Decision Tree is a rule-based classifier that splits data into classes using feature thresholds. It builds a tree where each internal node represents a feature, each branch a decision rule, and each leaf a class label. DTs are easy to interpret and can capture non-linear relationships.
However, they are prone to overfitting, especially with noisy or small datasets.
\subsubsection{Random Forest (RF)}
Random Forest is an ensemble learning method based on constructing multiple decision trees during training and outputting the mode of the classes for classification. It improves the generalization capability of individual trees and reduces overfitting.
RF is suitable for damage detection as it provides robustness to noise and variance, making it ideal for real-world sensor data.
\subsubsection{Naïve Bayes (NB)}
Naïve Bayes is a probabilistic classifier based on Bayes' theorem, assuming feature independence. Despite its simplicity, it often performs well in high-dimensional problems and with small datasets.
NB is particularly effective when class-conditional independence holds approximately, which may occur when STFT features are well-separated in distribution.

View File

@@ -0,0 +1,11 @@
\subsection{Short-Time Fourier Transform (STFT)}
The Short-Time Fourier Transform (STFT) is a fundamental technique used to analyze non-stationary signals, such as those generated by structures under dynamic load or white noise excitation. While the traditional Fourier Transform provides frequency-domain information, it lacks time resolution. STFT overcomes this limitation by applying the Fourier Transform over short overlapping segments of the signal, thereby producing a time-frequency representation.
Mathematically, the STFT of a signal $x(t)$ is given by:
\begin{equation}
X(t, \omega) = \int_{-\infty}^{\infty} x(\tau) w(\tau - t) e^{-j \omega \tau} d\tau
\end{equation}
where $w(\tau - t)$ is a window function centered at time $t$, and $\omega$ is the angular frequency.
In this study, the STFT is employed to extract the time-frequency features of the vibration signals collected from the structure. These features are then used as inputs to machine learning classifiers. This process captures localized frequency content over time, which is crucial in identifying structural changes due to damage.

View File

@@ -0,0 +1,88 @@
\chapter{Pendahuluan}
\section{Latar Belakang}
\indent Monitoring Kesehatan Struktur (\textit{Structural Health Monitoring} atau SHM) merupakan riset penting yang tersebar di berbagai disiplin ilmu, termasuk teknik dirgantara, teknik sipil, dan teknik mesin. Tujuan utama dari monitor kesehatan struktur adalah memastikan keamanan dan keandalan struktur dengan mendeteksi kerusakan sedini mungkin. Dengan mengombinasikan teknologi sensor yang canggih serta pengolahan data secara \textit{real-time}, sistem monitor kesehatan struktur menjadi kekuatan para insinyur untuk memonitor integritas struktur, strategi optimisasi \textit{maintenance}, dan memprediksi sisa umur struktur.
\indent Sistem SHM yang tangguh mengikuti \textit{framework} secara hierarkis untuk mengidentifikasi dan menilai kerusakan struktural. Menurut \textcite{rytter1993}, lima tahapan SHM tersebut adalah:
\begin{enumerate}
\item (Tingkat 1) Keberadaan Kerusakan: Menentukan apakah ada kerusakan pada struktur. Pada tahap ini, pengukuran getaran cukup untuk memastikan adanya kerusakan.
\item (Tingkat 2) Lokasi Kerusakan: Mengidentifikasi lokasi geometris kerusakan, baik kerusakan tunggal maupun ganda.
\item (Tingkat 3) Tipe Kerusakan: Mencirikan sifat kerusakan, yang dapat meliputi retakan, perubahan pada kondisi tumpuan, atau perubahan dalam sambungan struktur.
\item (Tingkat 4) Tingkat Keparahan: Mengukur secara kuantitatif seberapa parah kerusakan terjadi. Biasanya melalui eksperimen atau model terkalibrasi yang menggambarkan efek kerusakan, seperti penurunan kekakuan atau panjang retakan.
\item (Tingkat 5): Memprediksi sisa umur pakai struktur dengan mengandalkan pemantauan secara \textit{real-time} dan komprehensif serta model dengan fidelitas tinggi yang menggambarkan perkembangan kerusakan seiring waktu.
\end{enumerate}
Semakin tinggi tingkat identifikasi kerusakan, semakin besar pula kebutuhan akan sensor yang presisi, algoritma yang kompleks, serta parameter model yang akurat. Jika pada Tingkat 1 hanya diperlukan data yang terbatas untuk mendeteksi adanya kerusakan, maka Tingkat 5 membutuhkan akuisisi data secara \textit{real-time} dan canggih serta model prediktif yang memiliki fidelitas tinggi.
\par Tantangan utama terletak pada pengembangan sistem \acrshort{shm} yang mampu mengakomodasi berbagai tahapan identifikasi kerusakan secara efektif, baik dalam kondisi operasional normal maupun dalam situasi ekstrem seperti gempa bumi.
% Penelitian ini difokuskan pada lima tahapan identifikasi kerusakan, dengan tujuan untuk mengembangkan pendekatan yang lebih komprehensif terhadap diagnosis kerusakan dan peningkatan akurasi pelokasian (Tingkat 2), sekaligus mengoptimalkan strategi penempatan sensor dan perancangan algoritma guna mencapai efisiensi biaya yang lebih tinggi.
\par Dalam konteks pengembangan sistem \acrshort{shm} yang efektif, perlu memperhatikan elemen struktural yang rentan terhadap kerusakan namun sering kali terabaikan dalam pemantauan konvensional. % <- Transition sentence
Salah satu komponen struktural yang umum digunakan dalam penyambungan adalah sambungan baut (\textit{bolt joint}), yang dikenal karena kemudahan dalam perakitan dan penggunaannya. Namun, sambungan berulir ini rentan mengalami kelonggaran akibat beban kejut atau getaran terus-menerus \parencite{chen2017}. Kelonggaran baut yang tidak terdeteksi sejak dini dapat menyebabkan kerusakan serius pada struktur, sehingga identifikasi dini terhadap kerusakan sambungan baut menjadi krusial dalam bidang teknik sipil, mesin, dan kedirgantaraan. % <- Target
Pemantauan kondisi sambungan ini tidak hanya relevan dalam konteks deteksi dini (Tingkat 1), tetapi juga sangat penting untuk diagnosis kerusakan dan penentuan lokasi secara akurat (Tingkat 2), seiring dengan meningkatnya kebutuhan akan sistem \acrshort{shm} yang responsif dan adaptif terhadap dinamika kerusakan struktural. % <- closing sentences
\indent Deteksi kelonggaran baut telah dilakukan melalui berbagai metode. Kelompok pertama adalah inspeksi \textit{in-situ}, seperti inspeksi visual atau penggunaan alat mekanis seperti kunci torsi dan palu. Meskipun sederhana dan murah, metode ini sulit untuk mendeteksi kerusakan pada tahap awal \parencite{j.h.park2015}. Metode palu lebih efektif dibanding visual untuk mendeteksi awal kelonggaran, tetapi akurasinya dapat terganggu oleh kebisingan lingkungan, serta memakan waktu bila diaplikasikan pada struktur dengan banyak sambungan seperti jembatan \parencite{j.h.park2015,wang2013}.
\indent Kelompok kedua menggunakan teknik berbasis penglihatan komputer seperti kamera dan pencitraan digital, termasuk deteksi rotasi kepala baut menggunakan CNN dan Faster R-CNN \parencite{zhang2020,zhao2019}. Meskipun teknik ini dapat mendeteksi kerusakan secara visual tanpa dipengaruhi oleh kebisingan akustik, tantangan tetap ada dalam hal penempatan kamera dan beban komputasi tinggi dari model \gls{deep-learning}, terutama dalam kondisi ruang yang sangat seperti mesin kendaraan atau turbin.
\indent Kelompok ketiga dan yang menjadi fokus penelitian ini adalah teknik berbasis sensor, terutama pendekatan berbasis getaran (\textit{vibration-based}). Metode ini tidak hanya efektif dalam mengatasi keterbatasan teknik sebelumnya, tetapi juga mampu mendeteksi kelonggaran baut pada tahap awal secara baik dan akurat \parencite{nichols2004,razi2013}. Dalam penelitian ini, deteksi dilakukan melalui data akselerasi struktur yang diambil dari titik-titik sambungan dalam \textit{sistem grid} yang mewakili koneksi baut secara arah kolom.
\indent Penelitian oleh \textcite{abdeljaber2017} merupakan tonggak penting dalam sistem pemantauan kesehatan struktur (SHM), dengan menerapkan 30 model \acrlong{1d-cnn} pada 30 sensor akselerometer dalam struktur grid QUGS. Pendekatan ini menunjukkan bahwa metode pembelajaran mendalam sangat efektif dalam mendeteksi dan melokalisasi kerusakan dengan presisi tinggi. Namun, metode tersebut memerlukan sumber daya komputasi yang besar karena pemrosesan paralel data mentah berdimensi tinggi dari seluruh sensor \parencite{yang2020, liu2022}.
\indent Menanggapi tantangan ini, studi lanjutan seperti \parencite{shahid2022, doi:10.1007/s13349-023-00715-3} memperkenalkan pendekatan VMD-HT-CNN yang menggabungkan teknik ekstraksi fitur berbasis Variational Mode Decomposition (VMD) dan Hilbert Transform (HT) sebelum klasifikasi CNN. Metode ini secara signifikan meningkatkan efisiensi pelatihan dan akurasi deteksi meskipun dengan jumlah sensor yang lebih sedikit.
\indent Berdasarkan celah ini, penelitian ini mengadopsi strategi pengurangan jumlah sensor menjadi dua per jalur kolom (atas dan bawah), merepresentasikan sambungan vertikal seperti susunan baut, untuk menyederhanakan model tanpa kehilangan akurasi deteksi kerusakan. Data diubah melalui transformasi STFT sebelum diklasifikasikan menggunakan berbagai model pembelajaran mesin klasik. Dengan evaluasi antar berbagai pengklasifikasi dan validasi silang antar kolom, studi ini berkontribusi pada pengembangan sistem SHM yang efisien, hemat biaya, dan mudah diimplementasikan.
\section{Rumusan Masalah}
Untuk memandu arah penelitian ini, beberapa permasalahan utama yang akan dibahas adalah sebagai berikut:
\begin{enumerate}
\item Apakah sinyal getaran yang hanya diperoleh dari sensor pada bagian atas dan bawah suatu jalur kolom masih mampu merepresentasikan fitur-fitur penting yang diperlukan untuk mengklasifikasikan kerusakan struktur secara akurat?
\item Apakah penggabungan data dari beberapa jalur kolom dapat meningkatkan kemampuan generalisasi model, meskipun jumlah sensor pada tiap jalur dibatasi?
\item Apakah algoritma pemelajaran mesin klasik yang sederhana masih mampu menghasilkan model dengan kinerja yang cukup layak dibandingkan dengan model \textit{supervised} yang lebih kompleks ketika diterapkan pada skenario dengan input data sensor yang terbatas?
\end{enumerate}
% \section{Identifikasi Masalah}
% \begin{itemize}
% \item Kebanyakan kerangka kerja pada monitoring kesehatan struktur membutuhkan deretan sensor yang banyak, hal ini dibutuhkan biaya yang tinggi dan kurang praktikal untuk banyak pengaplikasian.
% \item Banyak model dengan performa tinggi bergantung pada teknik pemelajaran mendalam, sehingga dibutuhkan sumberdaya komputasi yang tinggi dan memungkinkan kurangnya kemudahan dan keterjangkauan untuk aplikasikan.
% \item Kurangnya kesederhanaan, pendeketan umum yang menyeimbangkan penggunaan sensor dengan keandalan dalam lokalisasi kerusakan.
% \end{itemize}
\section{Lingkup Penelitian}
Studi ini berfokus pada dataset yang tersedia secara publik didapat dari Queen's University Grandstand Simulator (QUGS), sebuah kerangka besi level laboratorium yang dipasang dengan tiga puluh titik sensor akselerometer dan \textit{white shaker noise}. Riset terdahulu telah dilakukan pengaplikasian pemelajaran mesin jaringan saraf terhadap seluruh sensor yang terpasang penuh pada setiap titik \textit{joint} untuk mencapai akurasi yang tinggi. Akan tetapi, pada praktiknya, instrumentasi penuh seperti ini terkadang kurang efektif dari segi biaya dan kurang layak dalam skala besar.
\section{Tujuan Penelitian}
\begin{enumerate}
\item Mengembangkan alur sistem (\textit{pipeline}) pemantauan kesehatan struktur (Structural Health Monitoring/SHM) yang disederhanakan dengan hanya menggunakan sepasang sensor di ujung-ujung struktur.
% \item Memperlakukan setiap grup kolom sensor sebagai elemen balok satu dimensi yang disederhanakan, dan mengevaluasi apakah karakteristik kerusakan tetap terjaga dalam energi getaran yang ditransmisikan antara kedua ujungnya.
% \item Menyusun setiap grup kolom sebagai satu dataset terpisah dan melakukan lima pengujian berbeda, di mana masing-masing grup kolom berperan sebagai data validasi secara bergantian.
% \item Menyertakan data dari setiap grup kolom ke dalam data pelatihan untuk membentuk satu model umum yang dapat digunakan untuk seluruh grup kolom.
\item Mengeksplorasi kemungkinan generalisasi satu model terhadap berbagai jalur kolom hanya dengan memanfaatkan data dari sensor pada kedua ujung kolom.
\end{enumerate}
% Dalam merespon hal tersebut, penelitian ini memperkenalkan pendekatan baru yang menekankan efisiensi pada penanganan data dan interpretasi fisik. Data pada sensor-sensor yang terpasang pada struktur grid ini dikelompokkan menjadi beberapa grup kolom, dan hanya menyisakan sensor awal dan sensor paling akhir dari setiap grup sensor sebagai input pengklasifikasian. Terdapat hipotesis bahwa energi getaran bergerak di sepanjang jalur kolom terjaga secara cukup baik antara ujung-ujung sensor untuk memungkinkan algoritma pemelajaran mesin, seperti Support-Vector Machine (SVM), Bagged Trees, Random Forest, Decision Tree, KNN, LDA, dan XGBoost, medeteksi dan mengklasifikasi secara akurat letak kerusakan.
\section{Manfaat Penelitian}
Penelitian ini memberikan beberapa manfaat yang diharapkan dapat berkontribusi dalam pengembangan sistem deteksi kerusakan struktur, antara lain:
\begin{enumerate}
\item Penelitian ini tidak berfokus pada pengembangan arsitektur model baru maupun penerapan \textit{transfer learning}, melainkan pada perancangan alur (\textit{pipeline}) klasifikasi yang sederhana dan mudah dipahami sebagai solusi tahap awal untuk pengembangan sistem monitor kesehatan struktur.
\item Dengan pemilihan titik sensor strategis yang terbatas (hanya di ujung atas dan bawah jalur kolom \textit{grid}) serta prapemrosesan berbasis transformasi STFT, penelitian ini menunjukkan bahwa efisiensi dapat dicapai tanpa mengorbankan akurasi secara signifikan.
\item Studi ini membuktikan bahwa algoritma pembelajaran mesin klasik seperti \gls{svm}, KNN, dan LDA masih mampu memberikan performa model yang kompetitif dalam klasifikasi kerusakan, apabila dipadukan dengan ekstraksi fitur yang tepat.
\item Hasil penelitian ini diharapkan dapat menjadi alternatif sistem SHM yang lebih terjangkau dan praktis untuk diterapkan pada struktur nyata, khususnya dalam kondisi keterbatasan sumber daya.
\item Rangkaian eksperimen dan pendekatan sistematis dalam penelitian ini dapat dijadikan tolok ukur atau \textit{baseline} untuk studi komparatif selanjutnya dan pengembangan model arsitektur yang lebih kompleks.
\end{enumerate}

View File

@@ -0,0 +1,31 @@
\chapter{Tinjauan Pustaka dan Landasan Teori}
\section{Tinjauan Pustaka}
% \input{chapters/id/02_literature_review/index}
Metode monitor kesehatan struktur (SHM) tradisional sering kali mengandalkan fitur yang dibuat secara manual dan pengklasifikasi (\textit{classifier}) yang diatur secara manual, yang menimbulkan tantangan dalam hal generalisasi, keandalan, dan efisiensi komputasi. Seperti yang disorot oleh \textcite{abdeljaber2017}, pendekatan-pendekatan ini umumnya memerlukan proses \textit{trial-and-error} dalam pemilihan fitur dan pengklasifikasi yang tidak hanya mengurangi ketangguhan metode tersebut di berbagai jenis struktur, tetapi juga menghambat penerapannya dalam aplikasi \textit{real-time} karena beban komputasi pada fase ekstraksi fitur.
\textcite{abdeljaber2017} memperkenalkan pendekatan deteksi kerusakan struktur berbasis CNN yang divalidasi melalui \textit{large-scale grandstand simulator} di Qatar University. Struktur tersebut dirancang untuk mereplikasi stadion modern, dilengkapi dengan 30 akselerometer, dan dikenai kerusakan terkontrol melalui pelonggaran baut sambungan antara balok dan gelagar. Data percepatan yang dikumpulkan di bawah eksitasi \textit{band-limited white noise} dan disampel pada 1024 Hz, kemudian dibagi menjadi bingkai berukuran 128 sampel untuk melatih 1-D CNN yang dilokalkan—satu untuk setiap sambungan (\textit{joint})—menciptakan sistem deteksi terdesentralisasi. Dalam dua fase (skenario) eksperimen, yang melibatkan pemantauan sebagian dan seluruh struktur, metode ini menunjukkan akurasi tinggi dalam pelokalisasian kerusakan, dengan kesalahan klasifikasi saat pelatihan hanya sebesar 0.54\%. Meskipun performa tetap andal bahkan dalam skenario kerusakan ganda, beberapa salah klasifikasi terjadi pada kasus kerusakan yang simetris atau berdekatan. Secara keseluruhan, metode yang diusulkan ini menawarkan solusi yang sangat efisien dan akurat untuk aplikasi SHM secara \textit{real-time}.
\textcite{eraliev2022} memperkenalkan teknik baru untuk mendeteksi dan mengidentifikasi tahap awal kelonggaran pada sambungan baut ganda menggunakan algoritma pembelajaran mesin. Studi ini difokuskan pada sebuah motor yang dikencangkan dengan empat baut dan dioperasikan dalam tiga kondisi putaran berbeda (800 rpm, 1000 rpm, dan 1200 rpm) guna mengumpulkan data getaran yang cukup untuk dianalisis. Studi ini menyoroti keterbatasan metode inspeksi tradisional, seperti inspeksi visual dan teknik pukulan palu, yang dinilai memakan waktu dan rentan terhadap gangguan kebisingan lingkungan \parencite{j.h.park2015, kong2018}.
Untuk meningkatkan akurasi deteksi, \textcite{eraliev2022} menggunakan transformasi Fourier waktu-singkat (STFT) sebagai metode ekstraksi fitur, yang menghasilkan 513 fitur frekuensidari sinyal getaran. Berbagai pengklasifikasi model pemelajaran mesin dilatih dan dievaluasi, dengan hasil menunjukkan performa yang memuaskan dalam mendeteksi baut longgar serta mengidentifikasi baut spesifik yang mulai kehilangan tegangan awal (preload). Studi ini juga menekankan pentingnya penempatan sensor, karena posisi sensor sangat memengaruhi akurasi dari pengklasifikasi yang digunakan \parencite{pham2020}. Temuan penelitian ini menunjukkan bahwa pengklasifikasi pada studi ini dapat digunakan untuk sistem pemantauan baut yang longgar secara daring (\textit{online monitoring}) pada pengaplikasian di masa depan, sehingga berkontribusi dalam pengembangan sistem pemantauan kesehatan struktur yang lebih baik.
STFT diidentifikasi sebagai metode peningkatan sinyal yang efektif, bersanding dengan \textit{wavelet transform} dan \textit{fractional fourier transform}. Keunggulan STFT terletak pada kemampuannya dalam menganalisis sinyal non-stasioner secara lokal, yang dapat meningkatkan kualitas fitur dalam mengenali pola, termasuk dalam tugas-tugas klasifikasi berbasis respon getaran struktur \parencite{zhang2023}.
Lebih lanjut, pendekatan yang dikembangkan oleh \textcite{garrido2016} menunjukkan potensi untuk menjembatani efektivitas fitur domain waktu-frekuensi dengan efisiensi pemrosesan model \textit{end-to-end}. Model ini mengintegrasikan proses STFT langsung ke dalam arsitektur jaringan \textit{feedforward}, memungkinkan sistem untuk tetap menggunakan representasi waktu-frekuensi namun tanpa biaya komputasi berat dari transformasi eksplisit di luar jaringan. Dengan demikian, pendekatan ini menawarkan jalan tengah yang menjanjikan antara kompleksitas 1-D CNN berbasis \textit{real-time raw signal} dan keunggulan struktural dari representasi domain frekuensi. Dalam konteks penelitian ini, meskipun transformasi dilakukan secara eksplisit, gagasan ini mendukung hipotesis bahwa representasi STFT dapat menjadi alternatif yang efisien dan kompetitif dibanding pemrosesan sinyal mentah dalam skenario pembelajaran mesin dengan sensor terbatas.
% \indent Metode berbasis getaran merupakan salah satu teknik paling umum dalam sistem pemantauan kesehatan struktur (SHM) karena kemampuannya dalam mendeteksi perubahan kondisi struktur secara non-destruktif. Pendekatan ini bergantung pada prinsip bahwa kerusakan pada suatu struktur, seperti kelonggaran sambungan atau penurunan kekakuan elemen, akan mengubah karakteristik dinamikanya, seperti frekuensi alami, bentuk mode, dan respons getaran terhadap eksitasi tertentu.
% \indent Salah satu jenis kerusakan struktural yang umum dijumpai dalam sambungan mekanis adalah baut yang longgar akibat beban dinamis berulang, seperti getaran atau kejutan. Kondisi ini dapat menyebabkan penurunan integritas struktur dan berujung pada kegagalan sistem jika tidak terdeteksi sejak dini. Oleh karena itu, deteksi baut yang longgar secara dini telah menjadi perhatian utama dalam bidang teknik sipil, mesin, maupun dirgantara [1, 11].
\indent Teknik deteksi berbasis getaran terbukti efektif dalam mengidentifikasi tanda-tanda awal anomali pada sambungan. Hal ini dilakukan dengan menganalisis perubahan spektrum frekuensi atau energi getaran antar kondisi sehat dan rusak. Dalam praktiknya, data getaran biasanya dikumpulkan melalui akselerometer yang dipasang pada titik-titik tertentu dalam struktur. Perubahan karakteristik getaran, seperti penurunan amplitudo, pergeseran frekuensi dominan, atau pola spektral lainnya, menjadi indikator keberadaan dan lokasi kerusakan. Misalnya, studi oleh \textcite{zhao2019, eraliev2022} menunjukkan bahwa perubahan rotasi kepala baut akibat kelonggaran dapat dikaitkan dengan pola getaran tertentu. Sementara itu, pendekatan yang lebih umum dalam domain teknik sipil adalah memanfaatkan sinyal akselerasi dari sambungan kolom atau balok sebagai masukan untuk sistem klasifikasi kerusakan berbasis pembelajaran mesin.
\indent Kelebihan utama dari pendekatan berbasis getaran dibanding metode visual atau inspeksi manual adalah kemampuannya dalam mendeteksi kerusakan mikro secara lebih dini, bahkan sebelum tampak secara fisik. Namun, tantangan tetap ada, terutama dalam penempatan sensor yang optimal, pemrosesan sinyal, dan interpretasi pola dinamik yang kompleks dalam struktur grid. Oleh karena itu, kombinasi antara teknik transformasi sinyal seperti Short-Time Fourier Transform (STFT) dan algoritma pembelajaran mesin menjadi arah baru yang menjanjikan dalam riset SHM masa kini.
\section{Dasar Teori}
\input{chapters/id/02_literature_review/theoritical_foundation/stft}
\input{chapters/id/02_literature_review/theoritical_foundation/role_windowing}
\input{chapters/id/02_literature_review/theoritical_foundation/hann}
\input{chapters/id/02_literature_review/theoritical_foundation/machine_learning}
Dasar teori ini memberikan kerangka metodologi untuk mengimplementasi dan mengevaluasi usulan sistem lokalisasi kerusakan pada penelitian ini. Kokmbinasi dari analisis waktu-frekuensi menggunakan STFT dan klasifikasi pemelajaran mesin klasik memungkinkan ketercapaian monitor kesehatan struktur yang efisien dan mudah diterapkan.

View File

@@ -0,0 +1,3 @@
Metode monitor kesehatan struktur (SHM) tradisional sering kali mengandalkan fitur yang dibuat secara manual dan pengklasifikasi (\textit{classifier}) yang diatur secara manual, yang menimbulkan tantangan dalam hal generalisasi, keandalan, dan efisiensi komputasi. Seperti yang disorot oleh \textcite{abdeljaber2017}, pendekatan-pendekatan ini umumnya memerlukan proses \textit{trial-and-error} dalam pemilihan fitur dan pengklasifikasi yang tidak hanya mengurangi ketangguhan metode tersebut di berbagai jenis struktur, tetapi juga menghambat penerapannya dalam pengaplikasian secara \textit{real-time} karena beban komputasi pada fase ekstraksi fitur.
\textcite{abdeljaber2017} memperkenalkan pendekatan deteksi kerusakan struktur berbasis CNN yang divalidasi melalui \textit{large-scale grandstand simulator} di Qatar University. Struktur tersebut dirancang untuk mereplikasi stadion modern, dilengkapi dengan 30 akselerometer, dan dikenai kerusakan terkontrol melalui pelonggaran baut sambungan antara balok dan gelagar. Data percepatan yang dikumpulkan di bawah eksitasi \textit{band-limited white noise} dan disampel pada 1024 Hz, kemudian dibagi menjadi bingkai berukuran 128 sampel untuk melatih 1-D CNN yang dilokalkan—satu untuk setiap sambungan (\textit{joint})—menciptakan sistem deteksi terdesentralisasi. Dalam dua fase (skenario) eksperimen, yang melibatkan pemantauan sebagian dan seluruh struktur, metode ini menunjukkan akurasi tinggi dalam pelokalisasian kerusakan, dengan kesalahan klasifikasi saat pelatihan hanya sebesar 0.54\%. Meskipun performa tetap andal bahkan dalam skenario kerusakan ganda, beberapa salah klasifikasi terjadi pada kasus kerusakan yang simetris atau berdekatan. Secara keseluruhan, metode yang diusulkan ini menawarkan solusi yang sangat efisien dan akurat untuk aplikasi SHM secara \textit{real-time}.

View File

@@ -0,0 +1,13 @@
Metode monitor kesehatan struktur (SHM) tradisional sering kali mengandalkan fitur yang dibuat secara manual dan pengklasifikasi (\textit{classifier}) yang diatur secara manual, yang menimbulkan tantangan dalam hal generalisasi, keandalan, dan efisiensi komputasi. Seperti yang disorot oleh \textcite{abdeljaber2017}, pendekatan-pendekatan ini umumnya memerlukan proses \textit{trial-and-error} dalam pemilihan fitur dan pengklasifikasi yang tidak hanya mengurangi ketangguhan metode tersebut di berbagai jenis struktur, tetapi juga menghambat penerapannya dalam pengaplikasian secara \textit{real-time} karena beban komputasi pada fase ekstraksi fitur.
\textcite{abdeljaber2017} memperkenalkan pendekatan deteksi kerusakan struktur berbasis CNN yang divalidasi melalui \textit{large-scale grandstand simulator} di Qatar University. Struktur tersebut dirancang untuk mereplikasi stadion modern, dilengkapi dengan 30 akselerometer, dan dikenai kerusakan terkontrol melalui pelonggaran baut sambungan antara balok dan gelagar. Data percepatan yang dikumpulkan di bawah eksitasi \textit{band-limited white noise} dan disampel pada 1024 Hz, kemudian dibagi menjadi bingkai berukuran 128 sampel untuk melatih 1-D CNN yang dilokalkan—satu untuk setiap sambungan (\textit{joint})—menciptakan sistem deteksi terdesentralisasi. Dalam dua fase (skenario) eksperimen, yang melibatkan pemantauan sebagian dan seluruh struktur, metode ini menunjukkan akurasi tinggi dalam pelokalisasian kerusakan, dengan kesalahan klasifikasi saat pelatihan hanya sebesar 0.54\%. Meskipun performa tetap andal bahkan dalam skenario kerusakan ganda, beberapa salah klasifikasi terjadi pada kasus kerusakan yang simetris atau berdekatan. Secara keseluruhan, metode yang diusulkan ini menawarkan solusi yang sangat efisien dan akurat untuk aplikasi SHM secara \textit{real-time}.
\indent Metode berbasis getaran merupakan salah satu teknik paling umum dalam sistem pemantauan kesehatan struktur (SHM) karena kemampuannya dalam mendeteksi perubahan kondisi struktur secara non-destruktif. Pendekatan ini bergantung pada prinsip bahwa kerusakan pada suatu struktur, seperti kelonggaran sambungan atau penurunan kekakuan elemen, akan mengubah karakteristik dinamikanya, seperti frekuensi alami, bentuk mode, dan respons getaran terhadap eksitasi tertentu.
\indent Salah satu jenis kerusakan struktural yang umum dijumpai dalam sambungan mekanis adalah kelonggaran baut akibat beban dinamis berulang, seperti getaran atau kejutan. Kondisi ini dapat menyebabkan penurunan integritas struktur dan berujung pada kegagalan sistem jika tidak terdeteksi sejak dini. Oleh karena itu, deteksi kelonggaran baut secara dini telah menjadi perhatian utama dalam bidang teknik sipil, mesin, maupun dirgantara [1, 11].
\indent Teknik deteksi berbasis getaran terbukti efektif dalam mengidentifikasi tanda-tanda awal kelonggaran sambungan. Hal ini dilakukan dengan menganalisis perubahan spektrum frekuensi atau energi getaran antar kondisi sehat dan rusak. Dalam praktiknya, data getaran biasanya dikumpulkan melalui akselerometer yang dipasang pada titik-titik tertentu dalam struktur. Perubahan karakteristik getaran, seperti penurunan amplitudo, pergeseran frekuensi dominan, atau pola spektral lainnya, menjadi indikator keberadaan dan lokasi kerusakan.
\indent Sejumlah penelitian telah menerapkan teknik ini dalam konteks struktur kompleks seperti sambungan multi-baut atau grid struktural. Misalnya, studi oleh Zhao et al. [10] menunjukkan bahwa perubahan rotasi kepala baut akibat kelonggaran dapat dikaitkan dengan pola getaran tertentu. Sementara itu, pendekatan yang lebih umum dalam domain teknik sipil adalah memanfaatkan sinyal akselerasi dari sambungan kolom atau balok sebagai masukan untuk sistem klasifikasi kerusakan berbasis pembelajaran mesin [12].
\indent Kelebihan utama dari pendekatan berbasis getaran dibanding metode visual atau inspeksi manual adalah kemampuannya dalam mendeteksi kerusakan mikro secara lebih dini, bahkan sebelum tampak secara fisik. Namun, tantangan tetap ada, terutama dalam penempatan sensor yang optimal, pemrosesan sinyal, dan interpretasi pola dinamik yang kompleks dalam struktur grid. Oleh karena itu, kombinasi antara teknik transformasi sinyal seperti Short-Time Fourier Transform (STFT) dan algoritma pembelajaran mesin menjadi arah baru yang menjanjikan dalam riset SHM masa kini.

View File

@@ -0,0 +1,20 @@
\subsubsection{Hann window}
Salah satu fungsi \textit{windowing} yang paling umum digunakan dalam STFT adalah \textit{Hann window}. Jendela ni adalah jenis jendela kosinus yang memberikan hasil yang baik antara resolusi frekuensi dan kebocoran spektral. \textit{Hann windowing} diskret dengan panjang $N$ didefinisikan sebagai:
\begin{equation}
w(n) = 0{.}5 \left(1 - \cos\left( \frac{2\pi n}{N - 1} \right) \right), \quad 0 \leq n \leq N - 1
\end{equation}
Fungsi ini secara halus meruncingkan sinyal menjadi nol di kedua ujungnya, sehingga mengurangi \textit{side lobe} dalam domain frekuensi sambil mempertahankan lebar \textit{lobe} utama yang relatif sempit. Dibandingkan dengan jendela persegi (rectangular window) yang memiliki tepi tajam, jendela Hann mengurangi fenomena Gibbs dan sangat cocok untuk aplikasi yang melibatkan estimasi spektral.
% \subsubsection*{Alasan Penggunaan dalam STFT}
% Jendela Hann sangat efektif digunakan dalam STFT karena keseimbangannya antara pelokalan waktu dan frekuensi:
% \begin{itemize}
% \item \textbf{Lebar lobe utama}: Menentukan resolusi frekuensi. Jendela Hann memiliki lobe utama yang sedikit lebih lebar dibandingkan beberapa alternatif, yang berarti resolusinya sedikit berkurang namun kebocoran spektralnya lebih baik ditekan.
% \item \textbf{Redaman side lobe}: Side lobe pertama sekitar -31 dB, yang secara signifikan mengurangi kebocoran dibandingkan jendela persegi.
% \item \textbf{Kelembutan dalam domain waktu}: Turunan pertama yang kontinu mengurangi transisi mendadak pada tepi segmen sinyal yang dijendela.
% \end{itemize}
% Hal ini membuat jendela Hann cocok untuk menganalisis sinyal dengan konten frekuensi yang berubah secara halus, seperti sinyal getaran, suara, atau sinyal biomedis.

View File

@@ -0,0 +1,45 @@
\subsection{Algoritma Klasifikasi}
Penelitian ini mengevaluasi lima algoritma pemelajaran mesin klasik untuk melakukan tugas pengklasifikasian terhadap lokalisasi kerusakan. Setiap algoritma memiliki keunggulan dan limitasi masing-masing, dan performa untuk setiap algoritma dijadikan tolok ukur untuk mengidentifikasi manakah algoritma yang paling sesuai untuk setiap \textit{dataset} yang diberikan.
\subsubsection{Support Vector Machine (SVM)}
Mesin vektor pendukung (SVM) adalah sebuah algoritma pemelajaran mesin terarah yang mencari \textit{hyperplane} optimal dengan cara memisahkan data ke dalam kelas-kelas dengan margin maksimum. SVM bekerja dengan baik pada ruang dimensi tinggi dan cukup kokoh terhadap \textit{overfitting}, terutama pada kasus yang membutuhkan batasan margin secara jelas \parencite{cortes1995}.
SVM sesuai untuk klasifikasi sinyal getaran karena kemampuannya untuk mengatasi keputusan batasan-batasan non-linier apabila dilengkapi dengan fungsi kernel, seperti fungsi kernel berbasis radial (RBF).
\subsubsection{K-Nearest Neighbors (KNN)}
KNN merupakan sebuah algoritma pemelajaran non-parametrik, berbasis contoh. Algoritma ini mengklasifikasi titik data yang berbasis pada pungutan suara terbanyak dari tetangga terdekat $k$ pada ruang fitur. Meskipun dinilai sederhana, KNN dapat dinilai efektif ketika datanya terdistribusi dengan baik dan batasan-batasan pada kelasnya merata.
Performa algoritma ini sensitif pada pemilihan $k$ dan jarak metriknya. Untuk data dengan dimensi tinggi seperti fitur STFT, mungkin diperlukan optimalisasi atau penskalaan dimensi.
\subsubsection{Decision Tree (DT)}
Decision Tree adalah algoritma pemelajaran terarah (\textit{supervised learning}) berbasis struktur pohon, di mana setiap \textit{node} internal mewakili suatu keputusan berdasarkan atribut tertentu, setiap cabang mewakili hasil dari keputusan tersebut, dan setiap daun (leaf node) mewakili label kelas. Algoritma ini secara rekursif membagi data ke dalam subset berdasarkan fitur yang memberikan informasi paling tinggi, seperti diukur dengan Gini index atau entropi (information gain).
Kelebihan dari Decision Tree adalah interpretabilitasnya yang tinggi dan kemampuannya menangani data numerik maupun kategorikal. Namun, pohon keputusan rentan terhadap \textit{overfitting}, terutama jika kedalaman pohon tidak dikontrol.
\subsubsection{Random Forest (RF)}
Random Forest adalah metode ensemble yang terdiri dari banyak Decision Tree yang dilatih pada subset data dan subset fitur yang diacak. Setiap pohon dalam hutan memberikan prediksi, dan hasil akhir ditentukan melalui agregasi (misalnya, voting mayoritas untuk klasifikasi).
Dengan menggabungkan banyak pohon, Random Forest mengurangi varian model dan meningkatkan generalisasi. Teknik ini efektif untuk dataset yang kompleks dan sangat cocok untuk menghindari \textit{overfitting} yang umum terjadi pada satu pohon keputusan tunggal.
\subsubsection{Bagged Trees (BT)}
\textit{Bagged Trees} atau \textit{Bootstrap Aggregated Trees} adalah pendekatan \textit{ensemble} yang mirip dengan Random Forest, namun perbedaannya terletak pada pemilihan fitur. Dalam \textit{Bagged Trees}, pohon-pohon dibangun dari sampel acak \textit{bootstrap} dari dataset pelatihan, tetapi tanpa pengacakan subset fitur seperti pada Random Forest.
\subsubsection{XGBoost (Extreme Gradient Boosting)}
XGBoost adalah algoritma pemelajaran mesin berbasis \textit{gradient boosting} yang dirancang untuk efisiensi dan performa tinggi. Algoritma ini bekerja dengan membangun model secara bertahap, di mana setiap pohon selanjutnya mencoba memperbaiki kesalahan dari pohon sebelumnya dengan mengoptimasi fungsi kerugian (\textit{loss function}) menggunakan metode gradien.
XGBoost menggabungkan beberapa teknik seperti regularisasi $L1$ dan $L2$, pemangkasan pohon (\textit{pruning}), dan pemrosesan paralel, sehingga menghindari terjadinya \textit{overfitting} dan unggul dalam akurasi prediksi dibanding metode pohon lainnya. Algoritma ini sangat populer dalam kompetisi data karena kemampuannya menangani data besar, fitur multivariat, dan klasifikasi multi-kelas secara efisien.
\subsubsection{Linear Discriminant Analysis (LDA)}
Linear Discriminant Analysis (LDA) adalah teknik klasifikasi dan reduksi dimensi yang mengasumsikan bahwa data berasal dari distribusi normal multivariat dan memiliki kovarians yang seragam untuk setiap kelas. LDA bertujuan untuk memproyeksikan data ke ruang berdimensi lebih rendah yang memaksimalkan pemisahan antar kelas (rasio varians antar kelas terhadap varians dalam kelas).
LDA sangat cocok ketika distribusi data mendekati normal dan jumlah fitur tidak terlalu besar dibanding jumlah sampel. Selain sebagai klasifikator, LDA juga sering digunakan sebagai teknik prapemrosesan untuk ekstraksi fitur sebelum digunakan dalam algoritma lain.
\bigskip

View File

@@ -0,0 +1,2 @@
\subsubsection{Fungsi \textit{Windowing}}
Fungsi jendela $w(n)$ berfungsi untuk melokalisasi sinyal dalam domain waktu, dengan meruncingkan sinyal di kedua ujungnya guna meminimalkan diskontinuitas. Hal ini sangat penting untuk mengurangi kebocoran spektral—sebuah fenomena di mana energi sinyal menyebar ke bin frekuensi di sekitarnya akibat pemotongan sinyal secara tiba-tiba. Pemilihan jenis jendela sangat memengaruhi resolusi dan akurasi representasi waktu-frekuensi.

View File

@@ -0,0 +1,13 @@
\subsection{Short-Time Fourier Transform (STFT)}
Short-Time Fourier Transform (STFT) adalah teknik fundamental yang digunakan untuk menganalisis sinyal non-stasioner, seperti yang diperoleh dari struktur dalam keadaan menerima beban dinamik atau eksitasi derau putih. Meskipun tradisional transformasi fourier memberikan informasi domain frekuensi, teknik ini tidak memiliki resolusi waktu. STFT mengatasi limitasi tersebut dengan menerapkan transformasi fourier segment-segment sinyal pendek yang tumpang tindih, dengan demikian diperoleh representasi waktu-frekuensi.
Secara matematis, STFT dari sinyal $x(t)$ diberikan sebagai berikut:
\begin{equation}
X(m, \omega) = \sum_{n=-\infty}^{\infty} x[n] \cdot w[n - m] \cdot e^{-j \omega n}
\end{equation}
dengan $w(\tau - t)$ adalah sebuah fungsi \textit{windowing} berpusat pada waktu $t$ dan $\omega$ adalah frekuensi angular.
Pada studi ini, STFT digunakan untuk mengekstrak domain waktu-frekuensi dari sinyal getaran yang diperoleh dari dari respon struktur terhadap getaran yang diberikan oleh mesin \textit{shaker}. Fitur-fitur ini kemudian digunakan sebagai input pada klasifikasi pemelajaran mesin. Proces ini merekap frekuensi lokal setiap waktu, yang dinilai krusial pada pengidentifikasian perubahan struktur akibat kerusakan.

View File

@@ -0,0 +1,62 @@
\chapter{Metode Penelitian}
\section{Benda Uji}
\input{chapters/id/03_methodology/materials}
\section{Alat}
\input{chapters/id/03_methodology/tools}
\clearpage
\section{Tahapan Penelitian}
\input{chapters/id/03_methodology/steps/index}
\section{Akuisisi Data}
\input{chapters/id/03_methodology/steps/data_acquisition}
\section{Ekstraksi Fitur}
\input{chapters/id/03_methodology/steps/feature_extraction}
\section{Analisis Data}
Sebelum pelatihan model dan optimasi \textit{hyperparameter}, dilakukan analisis eksplorasi pada data untuk memahami karakteristik dan struktur fitur-fitur yang telah diproses. Pada langkah ini, reduksi dimensi dengan \gls{pca} digunakan untuk mengevaluasi seberapa besar varian yang dapat dijelaskan oleh setiap komponen utama menggunakan diagram \textit{scree}. Kemudian visualisasi data dilakukan dengan teknik reduksi dimensi non-linear \gls{tsne} \parencite{JMLR:v9:vandermaaten08a} dan \gls{pacmap} \parencite{JMLR:v22:20-1061} untuk mengamati ruang fitur (ruang berdimensi tinggi) pada ruang dua dimensi.
Visualisasi non-linear ini bertujuan untuk menilai seberapa baik fitur-fitur getaran yang diekstraksi dapat merepresentasikan kondisi struktur yang berbeda dan mengidentifikasi rentang parameter yang sesuai untuk optimasi model selanjutnya. Pemahaman ini penting dalam merancang strategi pencarian \textit{grid} yang efisien, sehingga dapat menyeimbangkan kompleksitas model dengan interpretabilitas, terutama dalam menentukan jumlah komponen utama \gls{pca} yang optimal untuk dipertahankan dalam pipeline klasifikasi.
\section{Pengembangan Model}
Model klasifikasi \gls{svm} dengan kernel \gls{rbf} digunakan untuk mengklasifikasikan lokasi kerusakan struktur. Model ini dipilih karena kemampuannya dalam menangani data non-linear dan efektivitasnya dalam berbagai aplikasi klasifikasi dengan bantuan kernel \gls{rbf} yang memungkinkan pemetaan data ke ruang fitur berdimensi lebih tinggi, sehingga memudahkan pemisahan kelas yang kompleks.
\section{Optimasi Hyperparameter}
Model \gls{svm} memiliki beberapa \textit{hyperparameter} penting yang perlu dioptimalkan untuk mencapai kinerja terbaik, yaitu parameter regulasi $C$ dan parameter kernel $\gamma$. Parameter $C$ mengontrol keseimbangan antara memaksimalkan margin dan meminimalkan kesalahan klasifikasi pada data pelatihan, sedangkan parameter $\gamma$ menentukan jangkauan pengaruh dari setiap titik pelatihan, dengan nilai kecil menghasilkan pengaruh yang luas dan nilai besar menghasilkan pengaruh yang sempit.
Dalam penelitian ini, optimasi \textit{hyperparameter} dilakukan melalui pencarian \textit{grid} dengan dua tahap: \textit{coarse grid-search} dan \textit{fine grid-search}. Nilai $C$ dan $\gamma$ yang digunakan mengikuti rentang logaritma basis 2 yang direkomendasikan oleh \textcite{Hsu2009APG, CC01a} dan diadopsi oleh beberapa penelitian populer sebelumnya \textcite{hsu2002, JMLR:v18:16-174} dengan penyesuaian interval untuk mengurangi komputasi yang dibutuhkan yang semula $C \in \{ 2^{-5}, 2^{-3}, \dots, 2^{15} \}$ dan $\gamma \in \{ 2^{-15}, 2^{-13}, \dots, 2^{3} \}$ menjadi $C \in \{ 2^{-5}, 2^{0}, 2^{5}, 2^{10}, 2^{15} \}$ dan $\gamma \in \{ 2^{-15}, 2^{-10}, 2^{-5}, 2^{0}, 2^{5} \}$.
% Before using another Machine Learning algorithm, it's beneficial to apply a dimensionality reduction technique to your training data. This can lead to faster processing, reduced storage requirements, and potentially improved performance.
Reduksi dimensi ditambahkan sebagai parameter ketiga dalam pencarian \textit{grid} untuk menentukan jumlah komponen utama \gls{pca} guna mengoptimasi waktu komputasi, performa \textit{inference}, kompleksitas model, dan ukuran model \parencite{geron2019}. Nilai-nilai komponen yang diuji adalah $n_{components} \in \{512, 256, 128, 64, 32, 16, 8, 4, 2\}$. Rentang nilai tetap ini dipilih dibandingkan rentang \textit{fractional threshold} $(0 < x < 1)$ variansi kumulatif untuk memastikan konsistensi, meningkatkan reprodusibilitas, dan memudahkan interpretasi jumlah komponen utama yang dipilih di setiap iterasi pencarian \textit{grid}.
Kemudian, \textit{cross-validation} dengan skema \textit{stratified k-fold} digunakan untuk menilai kinerja model pada setiap kombinasi \textit{hyperparameter}. Skema ini memastikan bahwa setiap lipatan memiliki proporsi kelas yang seimbang, sehingga mengurangi bias dalam penilaian model \parencite{Kohavi1995ASO}. Nilai $k$ yang digunakan pada penelitian ini adalah 5 yang berarti data pelatihan dibagi menjadi 5 bagian: 4 bagian digunakan untuk pelatihan dan 1 bagian untuk validasi secara bergantian. Proses ini diulang untuk seluruh kombinasi \textit{hyperparameter} yang berjumlah 324 kombinasi, sehingga total pelatihan model yang dilakukan adalah 675 kali.
% table showing the grid search parameters
Tabel \ref{tab:grid_search_parameters} merangkum parameter-parameter yang digunakan dalam pencarian \textit{grid}.
\begin{table}[H]
\centering
\caption{Parameter-parameter dalam pencarian \textit{grid} untuk optimasi \textit{hyperparameter} model \gls{svm}.}
\label{tab:grid_search_parameters}
\begin{tabular}{lll}
\toprule
Parameter & Nilai yang Diuji & Jumlah Nilai \\
\midrule
% kernel
kernel & \gls{rbf} & 1 \\
% regularization parameter
$C$ & $\left\{ 2^{\,x} \,\middle|\, x \in \{-5, 0, \dots, 15\} \right\}$ & 5 \\
$\gamma$ & $\left\{ 2^{\,x} \,\middle|\, x \in \{-15, -10, \dots, 5\} \right\}$ & 5 \\
$n_{components}$ & $\{512, 256, 128, 64, 32, 16, 8, 4, 2\}$ & 9 \\
\midrule
Total Kombinasi & & 135 \\
\bottomrule
\end{tabular}
\end{table}
\section{Evaluasi Model}

View File

@@ -0,0 +1,39 @@
Penelitian ini menggunakan data sekunder dari \textcite{abdeljaber2017}, yang tersedia secara publik dan diperoleh melalui eksperimen menggunakan \textit{Queen's University Grandstand Simulator}. Adapun rincian data yang digunakan adalah sebagai berikut:
\begin{itemize}
\item Dataset terdiri atas rekaman respons getaran dari struktur rangka baja berukuran $6 \times 5$ yang dilengkapi dengan 30 akselerometer.
\item Setiap skenario dalam dataset mencakup satu kasus struktur tanpa kerusakan (healthy) dan 30 kasus kerusakan tunggal pada masing-masing sambungan (\textit{single-joint damage}).
\item Sinyal getaran direkam dengan frekuensi pengambilan sampel sebesar 1024 Hz selama durasi 256 detik untuk tiap skenario.
\item Kerusakan struktur disimulasikan dengan cara mengendurkan baut pada sambungan-sambungan tertentu.
\end{itemize}
Struktur dataset yang digunakan ditampilkan pada Gambar~\ref{fig:specimen-photo}.
% \begin{figure}[!ht]
% \centering
% \includegraphics[width=0.5\textwidth]{chapters/img/original_data.png}
% \caption{Overview of the original data used from Abdeljaber et al. (2017)}
% \label{fig:original-data}
% \end{figure}
\begin{figure}[ht]
\centering
\includegraphics[width=0.75\linewidth]{chapters/img/specimen.jpg}
\caption{Bentuk benda uji struktur baja dan penempatan akselerometer \textcite{abdeljaber2017}}
\label{fig:specimen-photo}
\end{figure}
\begin{figure}[ht]
\centering
\begin{minipage}[b]{0.45\linewidth}
\centering
\includegraphics[width=\linewidth]{chapters/img/i3-a-output.jpg}
\end{minipage}
\hfill
\begin{minipage}[b]{0.45\linewidth}
\centering
\includegraphics[width=\linewidth]{chapters/img/i3-b-output.jpg}
\end{minipage}
\caption{(kiri) posisi akselerometer dan skenario baut yang dikencangkan (damaged). (kanan) posisi akselerometer dan skenario baut yang dikendurkan (undamaged) \textcite{abdeljaber2017}}
\label{fig:skenario-kerusakan}
\end{figure}

View File

@@ -0,0 +1,64 @@
Dataset yang digunakan dalam penelitian ini bersumber dari basis data getaran yang dipublikasi oleh \textcite{abdeljaber2017}.
Dataset terdiri dari dua folder:
\begin{itemize}
\item \texttt{Dataset A} digunakan untuk pelatihan (training)
\item \texttt{Dataset B} digunakan untuk pengujian (testing)
\end{itemize}
Setiap dataset berisi 31 berkas yang merepresentasikan 31 kasus:
\begin{itemize}
\item Berkas pertama: struktur tanpa kerusakan ($\mathbf{U}$)
\item Berkas kedua hingga ke-31: kerusakan pada sambungan 130 ($\mathbf{D}^{(n)} , n = 1, \dots, 30$)
\end{itemize}
Sepuluh baris pertama dari setiap berkas berisi metadata yang menjelaskan konfigurasi pengujian, laju sampling, dan informasi kanal. Oleh karena itu, data deret waktu percepatan dimulai dari baris ke-11 yang berisi 31 kolom:
\begin{itemize}
\item \textbf{Kolom 1:} Waktu dalam detik
\item \textbf{Kolom 231:} Magnitudo percepatan dari \textit{joint} 1 hingga 30
\end{itemize}
Setiap sinyal di-\textit{sampling} pada frekuensi $f_s = 1024$ Hz dan direkam selama $t = 256$ detik, sehingga menghasilkan:
\begin{align}
\gls{not:signal} &= \gls{not:sampling_freq} \cdot \gls{not:time_length} \nonumber \\
&= 1024 \cdot 256 \nonumber \\
&= 262144 \quad \text{sampel per kanal} \label{eq:sample}
\end{align}
Dengan demikian, setiap berkas dapat direpresentasikan sebagai matriks:
\begin{equation}
\mathbf{D}^{(n)} \in \mathbb{R}^{262144 \times 30}, \quad n = 1, \dots, 30
\end{equation}
di mana $n$ mengacu pada indeks kasus (130 = kerusakan pada \textit{joint} ke-$n$) berisi rekaman getaran untuk seluruh tiga puluh \textit{joint}, dan berkas tanpa kerusakan (\textit{undamaged}) pada seluruh \textit{joint} direpresentasikan dengan matriks:
\begin{equation}
\mathbf{U} \in \mathbb{R}^{262144 \times 30}
\end{equation}
Kemudian \textit{dataset} A dapat direpresentasikan sebagai matriks:
\begin{equation}
\gls{not:dataset_A}
=
\Bigl\{
\mathbf{U} \in \mathbb{R}^{262144 \times 30}
\Bigr\}
\;\cup\;
\Bigl\{
\mathbf{D}^{(n)} \in \mathbb{R}^{262144 \times 30}
\;\bigm|\;
n = 1, \dots, 30
\Bigr\}.
\end{equation}
\begin{equation}
\gls{not:dataset_B}
=
\Bigl\{
\mathbf{U} \in \mathbb{R}^{262144 \times 30}
\Bigr\}
\;\cup\;
\Bigl\{
\mathbf{D}^{(n)} \in \mathbb{R}^{262144 \times 30}
\;\bigm|\;
n = 1, \dots, 30
\Bigr\}.
\end{equation}

View File

@@ -0,0 +1,402 @@
Sebelum melakukan ekstraksi fitur menggunakan \gls{stft}, persiapan data dilakukan agar tujuan penelitian dapat tercapai.
\subsection{Grid, Kode \textit{Joint}, dan Nama File}
Setiap berkas pada \textit{dataset} merekam respons getaran dari seluruh tiga puluh \textit{joint} yang dipasangi sensor akselerometer.
Berkas tanpa kerusakan direpresentasikan dengan matriks $\mathbf{U} \in \mathbb{R}^{262144 \times 30}$, sedangkan berkas dengan kerusakan pada \textit{joint} ke-$n$ dinotasikan sebagai $\mathbf{D}^{(n)} \in \mathbb{R}^{262144 \times 30}$ untuk $n = 1, \dots, 30$.
Setiap kolom pada matriks $\mathbf{U}$ maupun $\mathbf{D}^{(n)}$ merepresentasikan sinyal percepatan dari satu sensor (satu \textit{joint}), sehingga kolom ke-$j$ dapat ditulis sebagai vektor:
\begin{equation}
\mathbf{a}_{j}^{(n)} =
\begin{bmatrix}
a_{1}^{(n,j)} \\[2pt]
a_{2}^{(n,j)} \\[2pt]
\vdots \\[2pt]
a_{262144}^{(n,j)}
\end{bmatrix}
\in \mathbb{R}^{262144},
\quad
j = 1, \dots, 30,
\quad
n = 0, \dots, 30.
\end{equation}
Vektor $\mathbf{a}_{j}^{(n)}$ menunjukkan deret waktu percepatan yang diukur oleh sensor pada \textit{joint} ke-$j$ untuk kasus ke-$n$.
Dengan demikian, satu berkas $\mathbf{D}^{(n)}$ dapat ditulis sebagai himpunan dari seluruh vektor kolomnya:
\begin{equation}
\mathbf{D}^{(n)} = \bigl\{\,\mathbf{a}_{1}^{(n)}, \mathbf{a}_{2}^{(n)}, \dots, \mathbf{a}_{30}^{(n)}\,\bigr\}.
\end{equation}
Untuk kasus tanpa kerusakan, $\mathbf{U}$ dapat dinotasikan secara serupa dengan $n=0$ secara tunggal:
\begin{equation}
\mathbf{U} = \bigl\{\,\mathbf{a}_{1}^{(0)}, \mathbf{a}_{2}^{(0)}, \dots, \mathbf{a}_{30}^{(0)}\,\bigr\}.
\end{equation}
Pada setiap kasus kerusakan, \textit{joint} yang rusak berkorespondensi langsung dengan indeks berkas, yaitu:
\begin{equation}
\text{Kerusakan pada } \mathbf{D}^{(n)} \text{ terjadi di } \mathbf{a}_{n}^{(n)},
\quad n = 1, \dots, 30.
\end{equation}
% Secara ringkas, \textit{dataset} dapat dinyatakan sebagai himpunan seluruh sinyal akselerometer:
% \begin{equation}
% \mathcal{A}
% =
% \Bigl\{
% \mathbf{a}_{j}^{(n)} \in \mathbb{R}^{262144}
% \;\bigm|\;
% j = 1,\dots,30; \;
% n = 0,\dots,30
% \Bigr\}.
% \end{equation}
% Hubungan antara \textit{joint} ($j$), indeks berkas ($n$), dan kondisi kerusakan inilah yang menjadi dasar pembentukan \textit{grid} sensor serta penentuan label kelas kerusakan pada bagian selanjutnya (\autoref{sec:pemetaan-sensor}).
\subsection{Kelas Kerusakan}
\label{sec:kelas-kerusakan}
Enam kelas pertama ($d_1$$d_6$) merepresentasikan kondisi struktur dengan kerusakan pada lima \textit{joint} berturut-turut.
Setiap kelas $d_i$ berisi lima sinyal percepatan satu dimensi $\mathbf{a}_{n}^{(n)} \in \mathbb{R}^{262144}$,
masing-masing berasal dari berkas $\mathbf{D}^{(n)}$ yang merekam kondisi kerusakan pada \textit{joint} ke-$n$.
Secara umum, setiap kelas $d_i$ ($i = 1, \dots, 6$) terdiri atas lima sinyal percepatan
$\mathbf{a}_{n}^{(n)} \in \mathbb{R}^{262144}$ yang diambil dari lima berkas berturut-turut
pada rentang indeks $n = 5(i-1)+1$ hingga $5i$:
\begin{equation}\label{eq:d_i}
d_i = \bigl\{\,\mathbf{a}_{n}^{(n)}\,\bigr\}_{n = 5(i-1)+1}^{5i}\ ,
\quad i = 1, \dots, 6.
\end{equation}
Masing-masing $\mathbf{a}_{n}^{(n)}$ merupakan vektor berukuran $262144 \times 1$ yang memuat deret waktu percepatan dari
sensor akselerometer pada \textit{joint} ke-$n$ di berkas $\mathbf{D}^{(n)}$.
Sebagai contoh konkret:
\begin{align*}
d_1 &= \{\mathbf{a}_{1}^{(1)},\,\mathbf{a}_{2}^{(2)},\,\mathbf{a}_{3}^{(3)},\,\mathbf{a}_{4}^{(4)},\,\mathbf{a}_{5}^{(5)}\},\\
d_2 &= \{\mathbf{a}_{6}^{(6)},\,\mathbf{a}_{7}^{(7)},\,\mathbf{a}_{8}^{(8)},\,\mathbf{a}_{9}^{(9)},\,\mathbf{a}_{10}^{(10)}\},\\
&\;\;\vdots\\
d_6 &= \{\mathbf{a}_{26}^{(26)},\,\mathbf{a}_{27}^{(27)},\,\mathbf{a}_{28}^{(28)},\,\mathbf{a}_{29}^{(29)},\,\mathbf{a}_{30}^{(30)}\}.
\end{align*}
Dengan demikian, setiap kelas $d_i$ ($i \geq 1$) beranggotakan lima sinyal percepatan dari lima \textit{joint} yang berbeda,
masing-masing mencerminkan satu skenario kerusakan pada posisi yang berurutan di sepanjang struktur.
\subsection{Simulasi dengan Desain Sensor Terbatas}
Setiap posisi kolom pada struktur dipasangi dua sensor akselerometer,
yaitu satu di bagian atas dan satu di bagian bawah.
Hubungan antara indeks sensor atas dan bawah ditentukan berdasarkan
indeks \textit{joint} $n$ menggunakan operasi \textit{modulo} sebagai berikut:
\begin{equation}
r = ((n - 1) \bmod 5) + 1.
\end{equation}
Nilai $r$ menentukan posisi kolom (15), sehingga pasangan sensor
atasbawah dapat direpresentasikan dengan:
\begin{equation}
\bigl(
\mathbf{a}_{r}^{(n)},\;
\mathbf{a}_{r+25}^{(n)}
\bigr),
\quad r = ((n - 1) \bmod 5) + 1.
\end{equation}
Sebagai contoh, untuk $n=1$ hingga $5$ diperoleh pasangan
$(\mathbf{a}_{1}^{(1)}, \mathbf{a}_{26}^{(1)}), \dots, (\mathbf{a}_{5}^{(5)}, \mathbf{a}_{30}^{(5)})$;
sedangkan untuk $n=6$ hingga $10$ pasangan tersebut berulang
$(\mathbf{a}_{1}^{(6)}, \mathbf{a}_{26}^{(6)}), \dots, (\mathbf{a}_{5}^{(10)}, \mathbf{a}_{30}^{(10)})$, dan seterusnya.
Dengan demikian, definisi~\ref{eq:d_i} dapat dimodifikasi untuk memasukkan
hanya pasangan sensor atasbawah pada setiap kelas $d_i$ menjadi:
\begin{equation}
d_i =
\bigl\{
(\mathbf{a}_{r}^{(n)},\, \mathbf{a}_{r+25}^{(n)})
\bigr\}^{5i}_{n = 5(i-1)+1}, \quad i = 1, \dots, 6.
\end{equation}
Secara eksplisit:
\begin{align*}
d_1 &= \{(\mathbf{a}_{1}^{(1)}, \mathbf{a}_{26}^{(1)}),\,
(\mathbf{a}_{2}^{(2)}, \mathbf{a}_{27}^{(2)}),\,
(\mathbf{a}_{3}^{(3)}, \mathbf{a}_{28}^{(3)}),\,
(\mathbf{a}_{4}^{(4)}, \mathbf{a}_{29}^{(4)}),\,
(\mathbf{a}_{5}^{(5)}, \mathbf{a}_{30}^{(5)})\},\\
d_2 &= \{(\mathbf{a}_{1}^{(6)}, \mathbf{a}_{26}^{(6)}),\,
(\mathbf{a}_{2}^{(7)}, \mathbf{a}_{27}^{(7)}),\,\dots,\,
(\mathbf{a}_{5}^{(10)}, \mathbf{a}_{30}^{(10)})\},\\
&\;\;\vdots\\
d_6 &= \{(\mathbf{a}_{1}^{(26)}, \mathbf{a}_{26}^{(26)}),\,
(\mathbf{a}_{2}^{(27)}, \mathbf{a}_{27}^{(27)}),\,\dots,\,
(\mathbf{a}_{5}^{(30)}, \mathbf{a}_{30}^{(30)})\}.
\end{align*}
\subsection{Konstruksi Kelas Tanpa Kerusakan}
\label{sec:konstruksi-d0}
Untuk membentuk kelas tanpa kerusakan ($d_0$), pada setiap berkas kerusakan $\mathbf{D}^{(n)}$
ditentukan indeks kolom yang rusak
\begin{equation}
r_n = ((n - 1) \bmod 5) + 1, \qquad n=1,\dots,30.
\end{equation}
Selanjutnya, himpunan indeks kolom komplemen (sehat) didefinisikan sebagai
\begin{equation}
\mathcal{R}_c(n) = \{1,2,3,4,5\}\setminus\{r_n\}.
\end{equation}
Empat \textit{pasangan komplemen sehat} pada berkas $\mathbf{D}^{(n)}$ kemudian dibentuk sebagai
\begin{equation}
\mathcal{C}(n) =
\Bigl\{
\bigl(\mathbf{a}_{r}^{(n)},\,\mathbf{a}_{r+25}^{(n)}\bigr)
\;\Bigm|\;
r \in \mathcal{R}_c(n)
\Bigr\}, \qquad \left|\mathcal{C}(n)\right| = 4.
\end{equation}
Akhirnya, kelas tanpa kerusakan dihimpun dari seluruh berkas kerusakan:
\begin{align}
d_0 &= \bigcup_{n=1}^{30}\mathcal{C}(n) \\
&= \bigcup_{n=1}^{30}
\Bigl\{
\bigl(
\mathbf{a}_{r}^{(n)},\,\mathbf{a}_{r+25}^{(n)}
\bigr)
\;\Bigm|\;
r \in \mathcal{R}_c(n)
\Bigr\}. \\
&= \bigcup_{n=1}^{30}
\Bigl\{
\bigl(
\mathbf{a}_{r}^{(n)},\,\mathbf{a}_{r+25}^{(n)}
\bigr)
\;\Bigm|\;
r \in \{1,\dots,5\}\setminus\{r_n\}
\Bigr\}.
\end{align}
Setiap elemen $d_0$ merupakan pasangan sinyal satu dimensi berukuran
$\mathbb{R}^{262144}\times\mathbb{R}^{262144}$, dan secara keseluruhan
$|d_0| = 30 \times 4 = 120$ pasangan.
Kemudian, selain pasangan komplemen sehat dari seluruh berkas kerusakan,
kelas tanpa kerusakan juga mencakup kelima pasangan sensor atasbawah
yang berasal dari berkas \(\mathbf{U}\):
\begin{equation}
\mathcal{C}_{\mathbf{U}} \;=\;
\Bigl\{
\bigl(\mathbf{a}_{r}^{(0)},\,\mathbf{a}_{r+25}^{(0)}\bigr)
\;\Bigm|\;
r \in \{1,2,3,4,5\}
\Bigr\}.
\end{equation}
Dengan demikian, definisi akhir kelas tanpa kerusakan adalah
\begin{equation}
d_0
\;=\;
\Bigl(\,\bigcup_{n=1}^{30}\mathcal{C}(n)\Bigr)
\;\cup\;
\mathcal{C}_{\mathbf{U}}.
\end{equation}
Karena setiap \(\mathcal{C}(n)\) berisi empat pasangan (kolom komplemen
terhadap kolom rusak pada berkas \(\mathbf{D}^{(n)}\)) dan
\(\mathcal{C}_{\mathbf{U}}\) berisi lima pasangan dari \(\mathbf{U}\),
maka kardinalitasnya adalah
\begin{equation}
\bigl|d_0\bigr|
\;=\;
\underbrace{30 \times 4}_{\text{komplemen dari } \mathbf{D}^{(n)}}
\;+\;
\underbrace{5}_{\text{pasangan dari } \mathbf{U}}
\;=\; 125.
\end{equation}
\subsection{Ekstraksi Fitur dengan STFT}
\label{sec:stft-feature}
Setiap elemen pada himpunan $d_i$ ($i=0,\dots,6$) direpresentasikan sebagai pasangan sinyal percepatan
\((\mathbf{a}_{r}^{(n)}, \mathbf{a}_{r+25}^{(n)})\),
masing-masing berukuran $\mathbb{R}^{262144}$.
Transformasi Fourier Waktu-Pendek (\textit{Short-Time Fourier Transform}, STFT) diterapkan
pada kedua sinyal dalam setiap pasangan untuk memperoleh representasi domain-frekuensiwaktu
yang selanjutnya digunakan sebagai fitur model.
Kemudian, didefinisikan operator STFT \(\mathcal{S}\) untuk memetakan sinyal domain waktu mentah dengan panjang \(L=262144\) sampel menjadi sebuah spektrogram berukuran \(513\times513\). Kemudian digunakan \textit{Hanning window} dengan panjang \(N_{w}=1024\) dan hop size \(N_{h}=512\). Bentuk kompleks dari STFT adalah:
\begin{equation*}
\begin{aligned}
\text{(1) Window function:}\quad
w[n] &= \frac12\Bigl(1 - \cos\frac{2\pi n}{N_w - 1}\Bigr),
\quad n=0,\ldots,N_w-1; \\[1ex]
\text{(2) STFT:}\quad
S_k(p,t)
&= \sum_{n=0}^{N_w-1}
x_k\bigl[t\,N_h + n\bigr]
\;w[n]\;
e^{-j2\pi p n / N_w},\\
&\quad
p = 0,\ldots,512,\quad t = 0,\ldots,512.
\end{aligned}
\end{equation*}
Dengan demikian operatornya adalah
\begin{equation*}
\mathcal{S}:\; \mathbf{a}\in\mathbb{R}^{262144}
\;\longmapsto\;
\mathbf{\widetilde{a}}\in\mathbb{R}^{513\times513}.
\end{equation*}
Operator STFT diterapkan pada seluruh komponen sensor atas dan bawah
dari setiap pasangan \((\mathbf{a}_{r}^{(n)}, \mathbf{a}_{r+25}^{(n)})\)
yang terdapat pada himpunan $d_i$, untuk seluruh $i = 0, \dots, 6$:
\begin{equation}
\begin{aligned}
\mathcal{D}_A &= \bigl\{
\mathcal{S}\{\mathbf{a}_{r}^{(n)}\}
\;\bigm|\;
(\mathbf{a}_{r}^{(n)}, \mathbf{a}_{r+25}^{(n)}) \in d_i,\;
i = 0, \dots, 6
\bigr\}. \\
\mathcal{D}_B &= \bigl\{
\mathcal{S}\{\mathbf{a}_{r+25}^{(n)}\}
\;\bigm|\;
(\mathbf{a}_{r}^{(n)}, \mathbf{a}_{r+25}^{(n)}) \in d_i,\;
i = 0, \dots, 6
\bigr\}.
\end{aligned}
\end{equation}
Kedua himpunan \(\mathcal{D}_A\) dan \(\mathcal{D}_B\)
masing-masing menjadi \textit{model data} untuk dua kanal sensor
(atas dan bawah) yang digunakan pada tahap pemodelan berikutnya.
Untuk setiap pasangan \((\mathbf{a}_{r}^{(n)},\mathbf{a}_{r+25}^{(n)})\) hasil STFT adalah
\(\widetilde{\mathbf{a}}_{r}^{(n)}=\mathcal{S}\{\mathbf{a}_{r}^{(n)}\}\in\mathbb{R}^{513\times513}\),
dengan indeks waktu \(t=0,\dots,512\) dan frekuensi \(p=0,\dots,512\).
Setiap baris \(\widetilde{\mathbf{a}}_{r}^{(n)}[t]\) adalah vektor frekuensi berdimensi \(513\).
Untuk kelas kerusakan \(d_i\) ($i\ge1$) seluruh \(513\) \textit{frame} dari kelima pasangan diambil, sehingga setiap $d_i$ menghasilkan
\begin{equation}\label{eq:concat_stft_di}
\operatorname{concat}_{\text{time}}\bigl(\{\widetilde{\mathbf{a}}_{r}^{(n)}\}_{n=5(i-1)+1}^{5i}\bigr)\in\mathbb{R}^{5\cdot513\times513}=\mathbb{R}^{2565\times513}.
\end{equation}
Agar dimensi pada kelas tanpa kerusakan \(d_0\) sama dengan dimensi kelas kerusakan lain (lihat~\ref{eq:concat_stft_di}), hanya beberapa \textit{frame} dari masing-masing pasangan di \(d_0\). Dengan \(|d_0|=125\) pasangan, diperlukan pembagian:
\begin{align}
\frac{2565}{125} &= 20.52
\begin{cases}
20 \, \text{or} \\
21
\end{cases}\\
20x + 21y &= 2565,\qquad x+y=125,
\end{align}
yang memberikan \(x=60\) pasangan mengambil 20 \textit{frame} dan \(y=65\) pasangan mengambil 21 \textit{frame}.
Setelah mengurutkan pasangan \(d_0\) secara deterministik (mis. leksikografis menurut \((n,r)\)), kita ambil
\begin{itemize}
\item untuk pasangan ke-$1$ sampai ke-$60$: frame $t=0,\dots,19$ (20 baris),
\item untuk pasangan ke-$61$ sampai ke-$125$: frame $t=0,\dots,20$ (21 baris).
\end{itemize}
Maka setelah konkatenasi menurut urutan tersebut diperoleh
\(\operatorname{concat}_{\text{time}}(\mathcal{F}_{d_0})\in\mathbb{R}^{2565\times513}\),
menghasilkan dimensi yang sama dengan kelas \(d_i\).
% Pengambilan magnitudo menghasilkan matriks spektrogram pada bilah frekuensi $p$ dan \textit{frame} waktu $t$ untuk \textit{node} $k$
% \begin{equation*}
% \widetilde n_{k}^{F_{k}}(p,t) \;=\; \bigl|S_{k}(p,t)\bigr|
% \;\in\;\mathbb{R}^{513\times513}.
% \end{equation*}
% Sensor-sensor ujung bagian bawah dilabeli sebagai Sensor A dan Sensor-sensor ujung bagian atas dilabeli sebagai Sensor B. Semua enam kasus kerusakan dikumpulkan menjadi satu menghasilkan dua himpunan spektrogram, masing-masing berisi enam (kasus kerusakan):
% \begin{equation*}
% \text{Sensor A}
% =
% \bigl\{\,
% \widetilde n_{0}^{F_{0}},\,
% \widetilde n_{5}^{F_{5}},\,
% \dots,\,
% \widetilde n_{25}^{F_{25}}
% \bigr\},
% \quad
% \text{Sensor B}
% =
% \bigl\{\,
% \widetilde n_{4}^{F_{4}},\,
% \widetilde n_{9}^{F_{9}},\,
% \dots,\,
% \widetilde n_{29}^{F_{29}}
% \bigr\}.
% \end{equation*}
\subsection{Pemberian Label Data}
Seluruh vektor fitur hasil STFT pada setiap kelas $d_i$
dikonkat menjadi satu matriks fitur $\mathcal{D}\in\mathbb{R}^{17955\times513}$.
Selanjutnya, setiap baris pada $\mathcal{D}$ diberi label kelas $y_i$
sesuai asalnya:
\[
y_i =
\begin{cases}
0, & \text{jika berasal dari } d_0,\\
1, & \text{jika berasal dari } d_1,\\
\vdots\\
6, & \text{jika berasal dari } d_6.
\end{cases}
\]
Sehingga dataset berlabel dapat dituliskan sebagai:
\begin{align}
\mathcal{D}_{A,\text{labeled}}
&= \bigl\{\,(\mathbf{x}_k, y_k)\;\bigm|\;
\mathbf{x}_k \in \mathbb{R}^{513},~
y_k \in \{0,\dots,6\}
\bigr\} \\
\mathcal{D}_{B,\text{labeled}}
&= \bigl\{\,(\mathbf{x}_k, y_k)\;\bigm|\;
\mathbf{x}_k \in \mathbb{R}^{513},~
y_k \in \{0,\dots,6\}
\bigr\},
\end{align}
dengan representasi dalam bentuk \textit{dataframe} berdimensi
$\mathbb{R}^{17955\times514}$ (513 kolom fitur dan 1 kolom label).
% \subsection{Perakitan Baris dan Pelabelan}
% Setiap spektrogram berukuran \(513\times513\) diartikan sebagai 513 vektor fitur berdimensi 513. Kemudian diberikan indeks pengulangan dalam satu kasus kerusakan dengan \(r\in\{0,\dots,4\}\) dan potongan waktu dengan \(t\in\{0,\dots,512\}\). Misalkan
% \begin{equation*}
% \mathbf{x}_{i,s,r,t}\in\mathbb{R}^{513}
% \end{equation*}
% menunjukkan baris (atau kolom) ke-\(t\) dari spektrogram ke-\(r\) untuk kasus kerusakan \(i\) dan sensor \(s\). Label skalar untuk kasus kerusakan tersebut adalah
% \begin{equation*}
% y_{i} = i,\quad i=0,\dots,5.
% \end{equation*}
% Kemudian didefinisikan fungsi \textit{slicing} sebagai
% \begin{equation*}
% \Lambda(i,s,r,t)
% \;=\;
% \bigl[\,
% \mathbf{x}_{i,s,r,t},
% \;y_{i}
% \bigr]
% \;\in\;\mathbb{R}^{513+1}.
% \end{equation*}
% \subsection{Bentuk Akhir Data untuk Pelatihan}
% Seluruh baris dari enam kasus kerusakan, lima pengulangan, dan 513 potongan waktu dikumpulkan menghasilkan \textit{dataset} untuk satu sisi sensor:
% \begin{equation*}
% \mathcal{D}^{(s)}
% =
% \bigl\{
% \Lambda(i,s,r,t)
% \;\big|\;
% i=0,\dots,5,\;
% r=0,\dots,4,\;
% t=0,\dots,512
% \bigr\}.
% \end{equation*}
% Karena terdapat total \(6\times5\times513=15{,}390\) baris dan setiap baris memiliki \(513\) fitur ditambah satu kolom label, maka bentuk akhir dari data untuk satu sisi sensor yang siap digunakan untuk pelatihan adalah
% \begin{equation*}
% |\mathcal{D}^{(s)}| = 15\,390 \times 514.
% \end{equation*}

View File

@@ -0,0 +1,29 @@
Alur keseluruhan penelitian ini dilakukan melalui tahapan-tahapan sebagai berikut:
\begin{figure}[H]
\centering
\includegraphics[width=0.3\linewidth]{chapters/img/flow.png}
\caption{Diagram alir tahapan penelitian}
\label{fig:flowchart}
\end{figure}
\begin{enumerate}
\item Akuisisi data: mengunduh dataset dari \textcite{abdeljaber2017} yang berisi sinyal percepatan untuk 31 kondisi struktur (1 kondisi sehat dan 30 kondisi kerusakan tunggal).
% \item Seleksi Sensor: Memilih sinyal dari sejumlah sensor terbatas pada garis vertikal tertentu (misalnya, node 1 dan 26) untuk mensimulasikan konfigurasi sensor yang direduksi.
\item Ekstraksi fitur: melakukan normalisasi dan mengubah sinyal domain waktu mentah menjadi domain waktu-frekuensi menggunakan metode \gls{stft}.
\item \textit{Pre-processing} fitur: \textit{feature scaling} digunakan untuk menormalisasi data pada setiap fitur agar semua nilai berada dalam skala yang sama.
\item Reduksi dimensi: \gls{pca} digunakan untuk mengurangi kompleksitas komputasi dan menghilangkan fitur yang kurang informatif.
\item Pengembangan model: algoritma \acrshort{svm} digunakan untuk mengklasifikasikan lokasi kerusakan struktur.
\item Optimasi \textit{hyperparameter}: pencarian \textit{grid} dilakukan dengan \textit{coarse} dan \textit{fine grid-search} dan validasi silang \textit{stratified K-Fold} untuk setiap model guna meningkatkan kinerja klasifikasi.
\item Evaluasi: mengevaluasi kinerja model menggunakan metrik akurasi, presisi, dan \gls{cm} pada berbagai skenario pengujian. Evaluasi dilakukan dengan dua skema: (i) validasi silang K-Fold terstratifikasi pada setiap himpunan data, dan (ii) validasi silang antar-dataset (latih pada Dataset A, uji pada Dataset B, dan sebaliknya) untuk menilai kemampuan generalisasi lintas sumber data.
\end{enumerate}
% \section{Prapemrosesan Data dan Ekstraksi Fitur}

View File

@@ -0,0 +1,24 @@
We now introduce a simple “dataaugmentation” logic across repeated tests as:
\[
\mathbf{c}_{j}^{(i)}
\;=\;
\Bigl[S_{0+j}^{(i)},\,S_{5+j}^{(i)},\,S_{10+j}^{(i)},\,S_{15+j}^{(i)},\,S_{20+j}^{(i)},\,S_{25+j}^{(i)}\Bigr]^{T}
\;\in\mathbb{R}^{6}\!,
\]
where \(S_{k}^{(i)}\) is the \(k\)th sensors timefrequency feature vector (after STFT+logscaling) from the \(i\)-th replicate of scenario \(j\).
For each fixed scenario \(j\), collect the five replicates into the set
\[
\mathcal{D}^{(j)}
=\bigl\{\mathbf{c}_{j}^{(1)},\,\mathbf{c}_{j}^{(2)},\,\mathbf{c}_{j}^{(3)},\,\mathbf{c}_{j}^{(4)},\,\mathbf{c}_{j}^{(5)}\bigr\},
\]
so \(|\mathcal{D}^{(j)}|=5\). Across all six scenarios, the total augmented dataset is
\[
\mathcal{D}
=\bigcup_{j=0}^{5}\mathcal{D}^{(j)}
=\bigl\{\mathbf{c}_{j}^{(i)}: j=0,\dots,5,\;i=1,\dots,5\bigr\},
\]
with \(\lvert\mathcal{D}\rvert = 6 \times 5 = 30\) samples.
Each \(\mathbf{c}_{j}^{(i)}\) hence represents one ``columnbased damage sample,
and the collection \(\mathcal{D}\) serves as the input set for subsequent classification.

View File

@@ -0,0 +1,9 @@
Let $\mathcal{G}$ represent the $6 \times 5$ structural grid, where each node is denoted with row and column as $N_{r,c}$ with $r \in \{1,2,...,6\}$ and $c \in \{1,2,...,5\}$.\\
\begin{figure}[ht]
\centering
% \includegraphics[width=\textwidth]{}
\input{chapters/img/specimen}
\caption{Diagram joint and sensors placement}
\label{fig:specimen}
\end{figure}

View File

@@ -0,0 +1,66 @@
\subsection{Signal Normalization}
Each raw acceleration time series
\(\mathbf{a}_{k}(n)\), \(n = 0,1,\dots,N-1\) with \(N=262144\) samples (collected at \(f_s=1024\)Hz over 256s) :contentReference[oaicite:0]{index=0} is first standardized to zero mean and unit variance:
\[
\tilde a_{k}(n)
=\frac{a_{k}(n)-\mu_{k}}{\sigma_{k}},
\quad
\mu_{k}=\frac{1}{N}\sum_{n=0}^{N-1}a_{k}(n),
\quad
\sigma_{k}=\sqrt{\frac{1}{N}\sum_{n=0}^{N-1}\bigl(a_{k}(n)-\mu_{k}\bigr)^{2}}.
\]
\subsection{Framing and Windowing}
The normalized signal \(\tilde a_{k}(n)\) is chopped into overlapping frames of length \(W\) samples with hop size \(H\). The \(p\)-th frame is
\[
x_{k,p}[m]
=\tilde a_{k}(pH + m)\,w[m],
\quad
m=0,1,\dots,W-1,
\]
where \(w[m]\) is a chosen window function (e.g., Hamming).
\subsection{Short-Time Fourier Transform (STFT)}
For each frame \(x_{k,p}[m]\), compute its STFT:
\[
S_{k}(f,p)
=\sum_{m=0}^{W-1}x_{k,p}[m]\;e^{-j2\pi\,f\,m/W},
\]
where \(f=0,1,\dots,W-1\) indexes frequency bins :contentReference[oaicite:1]{index=1}.
\subsection{Spectrogram and Log-Magnitude}
Form the magnitude spectrogram
\[
M_{k}(f,p)
=\bigl|S_{k}(f,p)\bigr|,
\]
and apply log scaling for numerical stability:
\[
L_{k}(f,p)
=\log\bigl(1 + M_{k}(f,p)^{2}\bigr).
\]
This yields a timefrequency representation
\(\mathbf{L}_{k}\in\mathbb{R}^{F\times P}\), with \(F\) frequency bins and \(P\) frames.
\subsection{Feature Matrix Assembly}
For each column \(j\in\{1,\dots,5\}\), select only the two endpoint sensors:
\[
\mathbf{L}_{\text{bot},j} = \mathbf{L}_{(j)},\quad
\mathbf{L}_{\text{top},j} = \mathbf{L}_{(25+j)},
\]
and stack them:
\[
\mathbf{F}_{j}
=
\begin{bmatrix}
\mathbf{L}_{\text{bot},j} \\[6pt]
\mathbf{L}_{\text{top},j}
\end{bmatrix}
\;\in\mathbb{R}^{2F\times P}.
\]
Finally, flatten into a feature vector:
\[
\mathbf{f}_{j}
=\operatorname{vec}\bigl(\mathbf{F}_{j}\bigr)
\;\in\mathbb{R}^{2FP}.
\]

View File

@@ -0,0 +1,20 @@
For the vertical column approach with limited sensors
% we
are defined as column vector $\mathbf{c}_j$:
\begin{equation}
\mathbf{c}_j^{(i,d)} = [S_{0+j}^{(i+d)}, S_{5+j}^{(i+d)}, S_{10+j}^{(i+d)}, S_{15+j}^{(i+d)}, S_{20+j}^{(i+d)}, S_{25+j}^{(i+d)}]^T
\end{equation}
\begin{equation}
\mathbf{D}^{(i)} = [\mathbf{c}_0^{(i,i+1)}, \mathbf{c}_1^{(i,i+6)}, \mathbf{c}_2^{(i,i+11)}, \mathbf{c}_3^{(i,i+16)}, \mathbf{c}_4^{(i,i+21)}]^T
\end{equation}
where $j \in \{0, 1,2,3,4\}$ represents the column index.
For the limited sensor case focusing on endpoints only, we use:
\begin{equation}
\mathbf{c}^{\text{limited}}_j = [S_{0+(j-1)}, S_{25+(j-1)}]^T
\end{equation}
representing only the lower sensor (sensor A) and upper sensor (sensor B) of column $j$.

View File

@@ -0,0 +1,23 @@
Untuk setiap sensor $S_k$ dengan $k \in \{0,1,2,...,29\}$ diletakkan pada \textit{node} $N_{k}$, deret deret akselerasi waktu didefinisikan sebagai:
\begin{equation}
\mathbf{a}_{k}(t) = [a_{k}(t_1), a_{k}(t_2), \ldots, a_{k}(t_{262144})]
\end{equation}
% where $N = 262144$ samples at a sampling frequency of 1024 Hz over 256 seconds.
% $k \in \{i,(i+1),...,(i+(r\times j))\}$
Satu dataset utuh untuk setiap skenario ($A|B$) dapat direpresentasikan sebagai matrix $\mathbf{X}_d \in \mathbb{R}^{30 \times 262144}$:
\begin{equation}
\mathbf{{X}_d}^\intercal =
\begin{bmatrix}
\mathbf{a}_{0}(t) \\
\mathbf{a}_{1}(t) \\
\mathbf{a}_{2}(t) \\
\vdots \\
\mathbf{a}_{29}(t)
\end{bmatrix}
\end{equation}
di mana $d \in \{0, 1, 2, \ldots, 30\}$ merepresentasikan skenario kerusakan, dengan $d=0$ mengindikasikan tanpa kasus kerusakan.

View File

@@ -0,0 +1,54 @@
\subsection{Alat Perangkat Keras}
Data getaran struktur yang digunakan dalam penelitian ini diperoleh dari penelitian oleh \textcite{abdeljaber2017}, yang dilakukan menggunakan simulator struktur baja Grandstand di Queens University. Dalam eksperimen tersebut, struktur baja dipasang dengan akselerometer pada setiap sambungan-sambungan (\textit{joints}). Rangkaian perangkat keras yang digunakan untuk pengambilan data meliputi:
\begin{itemize}
\item \textbf{27 akselerometer PCB model 393B04} (Gambar~\ref{fig:accel393}) untuk merekam respons percepatan pada sebagian besar titik pengukuran.
\item \textbf{3 akselerometer B\&K model 8344} (Gambar~\ref{fig:accel393}) digunakan pada beberapa lokasi untuk validasi tambahan.
\item \textbf{Mounting magnetic PCB model 080A121} digunakan untuk menempelkan akselerometer secara aman pada struktur baja.
\item \textbf{Modal shaker (Model 2100E11)} digunakan untuk memberikan eksitasi getaran terkontrol pada struktur (Gambar~\ref{fig:shaker}). Sinyal input untuk shaker dihasilkan melalui \textbf{penguat daya SmartAmp 2100E21-400}.
\item \textbf{Dua perangkat akuisisi data 16-kanal (DT9857E-16)} digunakan secara simultan: satu untuk menghasilkan sinyal input ke shaker dan satu lagi untuk merekam data keluaran dari akselerometer (Gambar~\ref{fig:datalogger}).
\end{itemize}
Seluruh perangkat ini memungkinkan pengambilan data getaran dengan fidelitas tinggi, dengan laju pengambilan sampel sebesar 1024 Hz per kanal selama 256 detik untuk setiap skenario pengujian.
Adapun sumberdaya komputasi yang digunakan untuk pemrosesan semua data dan pemodelan pada skripsi ini, yaitu:
\begin{itemize}
\item \textbf{\textit{Processor}:} Intel Core i7 11th-gen @ 2.8 GHz
\item \textbf{RAM:} 2$\times$8 GB LPDDR4X
% \item \textbf{GPU:} Intel iris Xe Graphics (16 GB VRAM \textit{shared})
\item \textbf{Sistem Operasi:} Windows 10 64-bit
\end{itemize}
\begin{figure}[H]
\centering
\includegraphics[width=\textwidth]{chapters/img/accel393.png}
\caption{Akselerometer yang digunakan: (a) PCB 393B04, (b) B\&K 8344}
\label{fig:accel393}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.4\textwidth]{chapters/img/shaker.png}
\caption{Modal shaker (TMS 2100E11) yang dipasang pada struktur uji}
\label{fig:shaker}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.7\textwidth]{chapters/img/datalogger.jpg}
\caption{Perangkat akuisisi data (DT9857E-16) dan penguat daya SmartAmp 2100E21-400}
\label{fig:datalogger}
\end{figure}
\subsection{Alat Perangkat Lunak}
Berikut merupakan perangkat lunak yang digunakan selama proses penelitian ini:
\begin{itemize}
\item \textbf{Python 3.11} digunakan untuk proses pra-pemrosesan data, pemodelan, dan evaluasi.
\item \textbf{NumPy 1.22.4} digunakan untuk perhitungan deret numerik.
\item \textbf{Pandas 1.5.1} digunakan untuk memanipulasi struktur data.
\item \textbf{Pandas 1.7.3} digunakan untuk memproses sinyal.
\item \textbf{Matplotlib 3.7.1} digunakan untuk menghasilkan plot data.
\item \textbf{Scikit-Learn 1.5.1} digunakan untuk membangun dan melatih model dengan algoritma pemelajaran mesin klasik.
\item \textbf{Jupyter Notebook} digunakan untuk pelatihan model dan percobaan eksperimental secara interaktif.
\end{itemize}

View File

@@ -0,0 +1,666 @@
\chapter{Hasil Penelitian dan Pembahasan}
Bab ini menyajikan hasil dari proses ekstraksi fitur, analisis eksplorasi data,
pengembangan model klasifikasi, serta evaluasi kinerja model.
Hasil yang diperoleh selanjutnya dianalisis untuk menilai kemampuan model dengan fitur yang telah diekstraksi
dalam mendeteksi dan mengklasifikasikan lokasi kerusakan struktur \textit{grid}.
% \section{Pendahuluan Singkat}
% Bab ini menyajikan hasil evaluasi model untuk prediksi lokasi kerusakan berbasis fitur domain waktu dan frekuensi yang diekstrak dari STFT. Tujuan utama evaluasi adalah menguji apakah kombinasi fitur waktu--frekuensi dapat meningkatkan kinerja klasifikasi dibandingkan masing-masing domain secara terpisah, serta menilai kelayakan pendekatan sensor terbatas untuk penerapan di lapangan.
% Secara ringkas, kami menampilkan: (i) performa utama pada data uji, (ii) analisis per-kelas dan pola kesalahan, (iii) studi ablation dan sensitivitas mencakup fitur, parameter STFT, serta jumlah/posisi sensor, dan (iv) uji robustness serta implikasi implementasi. Detail metodologi eksperimen telah diuraikan pada Bab Metodologi; bagian ini berfokus pada temuan empiris dan interpretasinya.
\section{Hasil Ekstraksi Fitur STFT}
Bagian ini menyajikan contoh hasil transformasi STFT yang diterapkan
pada sinyal percepatan dari sensor atas dan bawah.
Analisis dilakukan untuk memastikan konsistensi pola spektral
dan kesetaraan ukuran data antar kelas sebelum proses pelatihan model.
Gambar~\ref{fig:stft-undamaged} memperlihatkan hasil STFT gabungan (\textit{aggregated}) untuk seluruh titik join tanpa kerusakan (kelas 0).
\begin{figure}[htbp]
\centering
\begin{minipage}{0.48\textwidth}
\centering
\includesvg[width=\textwidth, pretex=\tiny]{chapters/img/sensor1/stft-undamaged-1}
% \caption{Caption for the first image.}
% \label{fig:image1}
\end{minipage}\hfill
\begin{minipage}{0.48\textwidth}
\centering
\includesvg[width=\textwidth, pretex=\tiny]{chapters/img/sensor2/stft-undamaged-2}
% \caption{Caption for the second image.}
% \label{fig:image2}
\end{minipage}
\caption{STFT tanpa kerusakan (undamaged). Sensor A (kiri) dan Sensor B (kanan)}
\label{fig:stft-undamaged}
\end{figure}
Gambar~\ref{fig:stft-damaged-multiple-a} dan Gambar~\ref{fig:stft-damaged-multiple-b} memperlihatkan hasil STFT gabungan (\textit{aggregated}) untuk seluruh titik join dengan kerusakan (kelas 1--6). Setiap 513 segmen waktu merepresentasikan kolom sensor yang ditinjau.
\begin{figure}[htbp]
\centering
\includesvg[width=\textwidth, pretex=\tiny, inkscapelatex=true]{chapters/img/sensor1/stft-damaged-multiple-1.svg}
\caption{STFT sensor A dengan kerusakan (damaged $d_1$\textemdash $d_6$).}
\label{fig:stft-damaged-multiple-a}
\end{figure}
\begin{figure}[htbp]
\centering
\includesvg[width=1\textwidth, pretex=\tiny, inkscapelatex=true]{chapters/img/sensor2/stft-damaged-multiple-2.svg}
\caption{STFT sensor B dengan kerusakan (damaged $d_1$\textemdash $d_6$).}
\label{fig:stft-damaged-multiple-b}
\end{figure}
\section{Analisis Eksplorasi Data}
\label{sec:eda}
Sebelum tahap pelatihan model dilakukan, diperlukan analisis eksplorasi
untuk memahami distribusi dan karakteristik data fitur hasil ekstraksi
STFT pada himpunan $\mathcal{D}_A$ dan $\mathcal{D}_B$.
Analisis ini bertujuan untuk menilai sejauh mana fitur yang diperoleh
mampu merepresentasikan perbedaan kondisi struktur
serta menentukan parameter reduksi dimensi yang sesuai
pada tahap pemodelan berikutnya.
\subsection{Analisis Komponen Utama (PCA)}
Transformasi \gls{pca} diterapkan terhadap data fitur berdimensi
$513$ untuk mengevaluasi proporsi variansi yang dapat dijelaskan
oleh setiap komponen utama.
Dengan menghitung \textit{explained variance ratio}, diperoleh
diagram \textit{scree} seperti pada Gambar~\ref{fig:scree_plot},
yang menunjukkan kontribusi masing-masing komponen terhadap
total variansi data.
\begin{figure}[H]
\centering
\includegraphics[width=.75\textwidth]{chapters/img/sensor1/scree_plot.png}
\caption{Diagram \textit{scree} hasil analisis PCA pada dataset $\mathcal{D}_A$ dan $\mathcal{D}_B$.}
\label{fig:scree_plot}
\end{figure}
Dari Gambar~\ref{fig:scree_plot} terlihat bahwa \textit{explained ratio cumulative} 0.95 dicapai pada sekitar 300 komponen utama,
% Sebagai contoh, sepuluh komponen pertama menjelaskan sekitar
% $\alpha\%$ variansi kumulatif pada kanal sensor~A
% dan $\beta\%$ pada kanal sensor~B.
% Hasil ini menunjukkan bahwa terdapat redundansi di antara fitur-fitur
% frekuensi yang diekstraksi, sehingga reduksi dimensi
% dapat dilakukan tanpa kehilangan informasi signifikan.
\subsection{Reduksi Dimensi Sebelum Visualisasi}
Sebelum diterapkan metode reduksi dimensi non-linear seperti \gls{tsne}
dan \gls{pacmap}, terlebih dahulu dilakukan reduksi dimensi linear
menggunakan \gls{pca} untuk menghilangkan derau dan mengurangi kompleksitas
fitur STFT yang berukuran tinggi ($513$ dimensi).
Langkah ini umum digunakan untuk meningkatkan stabilitas dan efisiensi
proses embedding \parencite{JMLR:v9:vandermaaten08a}.
Pada penelitian ini, beberapa nilai komponen PCA digunakan \\
($n_\text{components}\in\{512,128,32,8\}$)
untuk menilai pengaruh tingkat reduksi terhadap hasil proyeksi t-SNE
dan PaCMAP.
Gambar~\ref{fig:pca_tsne_pacmap} memperlihatkan contoh visualisasi
dua dimensi hasil reduksi berurutan PCA $\rightarrow$ t-SNE dan
PCA $\rightarrow$ PaCMAP pada dataset $\mathcal{D}_A$.
\begin{figure}[H]
\centering
\subfloat[PCA=512]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/tsne_original.png}}
\subfloat[PCA=16]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/tsne_pca16.png}}
\subfloat[PCA=8]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/tsne_pca8.png}}
\subfloat[PCA=4]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/tsne_pca4.png}} \\[1ex]
\subfloat[PCA=512]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/pacmap_original.png}}
\subfloat[PCA=16]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/pacmap_pca16.png}}
\subfloat[PCA=8]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/pacmap_pca8.png}}
\subfloat[PCA=4]{\includegraphics[width=.24\textwidth]{chapters/img/sensor1/pacmap_pca4.png}}
\caption{Visualisasi hasil reduksi bertahap pada $\mathcal{D}_A$ dengan PCA $\rightarrow$ t-SNE (baris atas)
dan PCA $\rightarrow$ PaCMAP (baris bawah).}
\label{fig:pca_tsne_pacmap_A}
\end{figure}
\begin{figure}[H]
\centering
\subfloat[PCA=512]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/tsne_original.png}}
\subfloat[PCA=16]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/tsne_pca16.png}}
\subfloat[PCA=8]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/tsne_pca8.png}}
\subfloat[PCA=4]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/tsne_pca4.png}} \\[1ex]
\subfloat[PCA=512]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/pacmap_original.png}}
\subfloat[PCA=16]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/pacmap_pca16.png}}
\subfloat[PCA=8]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/pacmap_pca8.png}}
\subfloat[PCA=4]{\includegraphics[width=.24\textwidth]{chapters/img/sensor2/pacmap_pca4.png}}
\caption{Visualisasi hasil reduksi bertahap pada $\mathcal{D}_B$ dengan PCA $\rightarrow$ t-SNE (baris atas)
dan PCA $\rightarrow$ PaCMAP (baris bawah).}
\label{fig:pca_tsne_pacmap_B}
\end{figure}
Hasil pada Gambar~\ref{fig:pca_tsne_pacmap} menunjukkan bahwa
pengurangan jumlah komponen PCA hingga 8 dimensi
masih mempertahankan pemisahan antar kelas secara visual,
sedangkan reduksi lebih jauh (misalnya $n_\text{components}=4$)
menyebabkan beberapa klaster saling tumpang tindih (\textit{overlap}).
Temuan ini mendukung pemilihan nilai $n_\text{components}$
sebagai salah satu parameter penting yang diuji dalam
pencarian \textit{grid} pada tahap optimasi model untuk mengurangi kompleksitas model dan efisiensi komputasi.
% \subsection{Visualisasi Ruang Fitur Non-Linear}
% Selain PCA, digunakan dua metode reduksi dimensi non-linear,
% yaitu \gls{tsne} dan \gls{pacmap},
% untuk memvisualisasikan struktur data dalam ruang dua dimensi.
% Kedua metode ini memproyeksikan vektor fitur berukuran $513$
% ke bidang dua dimensi dengan mempertahankan hubungan jarak
% antar sampel secara lokal.
% \begin{figure}[H]
% \centering
% % \subfloat[t-SNE pada $\mathcal{D}_A$]{%
% % \includegraphics[width=.48\textwidth]{chapters/img/sensor1/tsne_A.png}
% % }\hfill
% \subfloat[t-SNE pada $\mathcal{D}_B$]{%
% \includegraphics[width=.48\textwidth]{chapters/img/sensor1/tsne_B.png}
% }\\[1ex]
% \subfloat[PaCMAP pada $\mathcal{D}_A$]{%
% \includegraphics[width=.48\textwidth]{chapters/img/sensor1/pacmap_A.png}
% }\hfill
% \subfloat[PaCMAP pada $\mathcal{D}_B$]{%
% \includegraphics[width=.48\textwidth]{chapters/img/sensor1/pacmap_B.png}
% }
% \caption{Visualisasi dua dimensi hasil reduksi dimensi non-linear
% menggunakan t-SNE dan PaCMAP pada fitur STFT sensor A dan B.
% .}
% \label{fig:tsne_pacmap}
% \end{figure}
% Pada Gambar~\ref{fig:tsne_pacmap} tampak bahwa setiap kelas
% ($d_0$--$d_6$) membentuk klaster yang relatif terpisah,
% menandakan bahwa fitur hasil STFT memiliki kemampuan diskriminatif
% terhadap kondisi struktur.
% Beberapa tumpang tindih antar klaster (khususnya antara $d_i$ yang berdekatan)
% masih muncul akibat kemiripan respons getaran pada lokasi
% yang berdekatan, namun pola pemisahan antar kelompok
% masih terlihat jelas.
\subsection{Interpretasi dan Implikasi}
Hasil eksplorasi ini menunjukkan bahwa:
\begin{enumerate}
\item Variansi utama data dapat dijelaskan oleh sejumlah kecil komponen PCA,
sehingga reduksi dimensi berpotensi meningkatkan efisiensi komputasi
tanpa kehilangan informasi penting.
\item Visualisasi t-SNE dan PaCMAP memperlihatkan bahwa fitur STFT
mampu mengelompokkan kondisi struktur sesuai label kerusakan,
mendukung validitas pemilihan STFT sebagai metode ekstraksi fitur.
\item Perbedaan antara kanal sensor~A ($\mathcal{D}_A$) dan sensor~B ($\mathcal{D}_B$) tidak signifikan,
sehingga keduanya dapat diperlakukan sebagai dua sumber informasi
komplementer pada tahap pelatihan model.
\end{enumerate}
Temuan ini menjadi dasar untuk menentukan jumlah komponen PCA
yang akan digunakan pada \textit{grid search} saat optimasi \textit{hyperparameter} model SVM.
\section{Hasil \textit{Coarse Grid-Search}}
\label{sec:grid-results}
Setelah proses ekstraksi fitur dan pembentukan dataset berlabel,
tahap berikutnya adalah melakukan pencarian \textit{grid}
untuk mengoptimalkan parameter model \gls{svm}
dengan kernel \gls{rbf}.
Tiga parameter yang dioptimalkan adalah:
\begin{enumerate}
\item jumlah komponen utama \(\,n_{\text{components}}\,\) pada reduksi dimensi \gls{pca},
\item parameter regulasi \(C\),
\item parameter kernel \(\gamma\).
\end{enumerate}
Total kombinasi parameter yang diuji berjumlah \(5\times5\times8 = 200\) kandidat model
dengan skema \textit{stratified 5-fold cross-validation} menghasilkan total 1000 kali \textit{fitting}.
Setiap kombinasi dievaluasi menggunakan metrik akurasi rata-rata
pada data validasi.
\subsection{Evaluasi Keseluruhan}
Distribusi akurasi seluruh kandidat model ditunjukkan pada
Gambar~\ref{fig:grid_hist}.
Sebagian besar kombinasi menghasilkan akurasi di atas~95\%,
menunjukkan bahwa fitur STFT memiliki daya klasifikasi yang kuat
terhadap kondisi struktur.
\begin{figure}[H]
\centering
% \includegraphics[width=.65\textwidth]{figures/grid_hist.pdf}
\caption{Distribusi akurasi validasi silang dari 225 kombinasi parameter $(C,\gamma,n_{\text{components}})$.}
\label{fig:grid_hist}
\end{figure}
\subsection{Pengaruh Jumlah Komponen PCA}
Rata-rata akurasi tertinggi untuk setiap nilai $n_{\text{components}}$
ditampilkan pada Gambar~\ref{fig:pca_acc_overall}.
Terlihat bahwa akurasi meningkat hingga mencapai puncak pada rentang
$n_{\text{components}} = 64$--$128$, kemudian menurun ketika jumlah komponen
dikurangi secara agresif.
Hal ini menunjukkan bahwa sekitar 1025\% komponen utama sudah cukup
merepresentasikan informasi penting dari fitur STFT.
\begin{figure}[H]
\centering
% \includegraphics[width=.7\textwidth]{figures/pca_acc_overall.pdf}
\caption{Rata-rata akurasi terhadap jumlah komponen PCA berdasarkan hasil pencarian \textit{grid}.}
\label{fig:pca_acc_overall}
\end{figure}
\subsection{Peta Akurasi terhadap Parameter SVM}
Untuk setiap kanal sensor, peta akurasi terhadap parameter $C$ dan~$\gamma$
pada konfigurasi PCA terbaik ($n_{\text{components}}=128$)
ditunjukkan pada Gambar~\ref{fig:svm_heatmap}. Terlihat bahwa area akurasi tinggi terbentuk pada
nilai \(C\) menengah dan \(\gamma\) kecil,
yang menandakan keseimbangan antara margin yang cukup lebar
dan kompleksitas model yang moderat.
\begin{figure}
\centering
\subfloat[Baseline]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_original.png}}\hfill
\subfloat[PCA=256]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_pca256.png}}\hfill \\[1ex]
\subfloat[PCA=128]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_pca128.png}}\hfill
\subfloat[PCA=64]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_pca64.png}}\hfill \\[1ex]
\subfloat[PCA=32]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_pca32.png}}\hfill
\subfloat[PCA=16]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_pca16.png}}\hfill \\[1ex]
\subfloat[PCA=8]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_pca8.png}}\hfill
\subfloat[PCA=4]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_pca4.png}}\hfill
\caption{\textit{Heatmap mean test score} terhadap parameter $C$ dan~$\gamma$ untuk setiap komponen utama PCA pada Sensor A ($\mathcal{D}_A$).}
\label{fig:svm_heatmap_A}
\end{figure}
\begin{figure}
\centering
\subfloat[Baseline]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_original.png}}\hfill
\subfloat[PCA=256]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_pca256.png}}\hfill \\[1ex]
\subfloat[PCA=128]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_pca128.png}}\hfill
\subfloat[PCA=64]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_pca64.png}}\hfill \\[1ex]
\subfloat[PCA=32]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_pca32.png}}\hfill
\subfloat[PCA=16]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_pca16.png}}\hfill \\[1ex]
\subfloat[PCA=8]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_pca8.png}}\hfill
\subfloat[PCA=4]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_pca4.png}}\hfill
\caption{\textit{Heatmap mean test score} terhadap parameter $C$ dan~$\gamma$ untuk setiap komponen utama PCA pada Sensor B ($\mathcal{D}_B$).}
\label{fig:svm_heatmap_B}
\end{figure}
\subsection{Analisis Efisiensi Model pada \textit{Coarse Grid-Search}}
\label{sec:efficiency_analysis}
Selain mempertimbangkan akurasi rata-rata (\textit{mean test score})
sebagai satu-satunya metrik evaluasi, penelitian ini juga memperhitungkan
waktu pelatihan rata-rata (\textit{mean fit time}) untuk menilai efisiensi komputasi.
Hal ini penting karena peningkatan akurasi sering kali diikuti dengan
kenaikan waktu pelatihan yang tidak proporsional, sehingga diperlukan
kompromi antara performa dan kompleksitas.
Untuk mengukur keseimbangan tersebut, didefinisikan metrik efisiensi:
\begin{equation}
E_i = \frac{S_i}{T_i^{\alpha}},
\label{eq:efficiency_metric}
\end{equation}
dengan:
\begin{itemize}
\item $S_i$ = rata-rata skor akurasi hasil 5-\textit{fold cross-validation} (01),
\item $T_i$ = rata-rata waktu pelatihan per iterasi (dalam detik),
\end{itemize}
Metrik $E_i$ menggambarkan rasio akurasi terhadap biaya waktu pelatihan.
Semakin besar nilai $E_i$, semakin efisien model tersebut atau
model mampu mencapai akurasi tinggi dengan waktu pelatihan yang relatif singkat.
% \begin{figure}[H]
% \centering
% % \includegraphics[width=.7\textwidth]{figures/efficiency_score.pdf}
% \caption{Perbandingan metrik efisiensi ($E_i$) dan akurasi rata-rata ($S_i$)
% terhadap jumlah komponen PCA.}
% \label{fig:efficiency_score}
% \end{figure}
\begin{table}[H]
\centering
\begin{tabular}{rrrrrr}
\toprule
$n_{\text{components}}$ & $C (\log{2})$ & $\gamma (\log{2})$ & $S_i$ & $T_i$ & $E_i (\times10^{-3})$ \\
\midrule
4 & 5 & -5 & 0.80764 & 11.22306 & 71.96291 \\
8 & 5 & -5 & 0.97076 & 10.88293 & 89.20027 \\
16 & 5 & -5 & 0.99116 & 10.53770 & 94.05832 \\
32 & 10 & -10 & 0.99394 & 10.45783 & 95.04296 \\
64 & 10 & -10 & 0.99631 & 13.46819 & 73.97505 \\
128 & 5 & -10 & 0.99728 & 13.43715 & 74.21849 \\
256 & 5 & -10 & 0.99756 & 17.84189 & 55.91131 \\
512 & 5 & -10 & 0.99763 & 31.24036 & 31.93410 \\
\bottomrule
\end{tabular}
\caption{Hasil ringkasan nilai maksimum \textit{mean test score} untuk setiap konfigurasi $n_{\text{components}}$ pada Sensor A ($\mathcal{D}_A$).}
\label{tab:efficiency_summary_A}
\end{table}
\begin{table}[H]
\centering
\begin{tabular}{rrrrrr}
\toprule
$n_{\text{components}}$ & $C (\log{2})$ & $\gamma (\log{2})$ & $S_i$ & $T_i$ & $E_i (\times10^{-3})$ \\
\midrule
4 & 5 & -5 & 0.87845 & 13.77282 & 63.78107 \\
8 & 0 & -5 & 0.98051 & 12.51643 & 78.33758 \\
16 & 5 & -5 & 0.99443 & 10.90890 & 91.15776 \\
32 & 5 & -10 & 0.99596 & 13.42619 & 74.18057 \\
64 & 5 & -10 & 0.99735 & 11.40759 & 87.42906 \\
128 & 5 & -10 & 0.99728 & 14.54694 & 68.55632 \\
256 & 5 & -10 & 0.99777 & 20.27980 & 49.20029 \\
512 & 5 & -10 & 0.99791 & 39.63068 & 25.18027 \\
\bottomrule
\end{tabular}
\caption{Hasil ringkasan nilai maksimum \textit{mean test score} untuk setiap konfigurasi $n_{\text{components}}$ pada Sensor B ($\mathcal{D}_B$).}
\label{tab:efficiency_summary_B}
\end{table}
Hasil pada Tabel~\ref{tab:efficiency_summary_A} dan Tabel~\ref{tab:efficiency_summary_B} menunjukkan bahwa,
meskipun nilai akurasi tertinggi dicapai pada
$n_{\text{components}} = 512$ untuk kedua kanal sensor,
puncak nilai metrik efisiensi dicapai pada
$n_{\text{components}} = 32$ dengan $E = 0.9504$ untuk Sensor A ($\mathcal{D}_A$) dan $n_{\text{components}} = 16$ dengan $E = 0.9116$ untuk Sensor B ($\mathcal{D}_B$).
Artinya, pengurangan dimensi hingga 32 komponen untuk Sensor A dan 16 komponen untuk Sensor B
menghasilkan model yang hampir seakurat konfigurasi berdimensi penuh,
namun dengan waktu pelatihan yang berkurang lebih dari 75\%.
% Kompromi ini dianggap sebagai titik optimum antara performa dan efisiensi.
Berdasarkan kombinasi akurasi, waktu pelatihan, dan metrik efisiensi,
konfigurasi dengan $n_{\text{components}}=32$ untuk Sensor A dan $n_{\text{components}}=16$ untuk Sensor B dipilih sebagai
\textit{baseline} optimal untuk model akhir.
Model \textit{baseline} ini akan digunakan sebagai acuan pada tahap evaluasi model dan pencarian \textit{hyperparameter} lanjutan (\textit{fine grid-search})
yang dibahas pada subab berikutnya.
\section{Evaluasi Model \textit{Baseline}}
\label{sec:baseline_performance}
Model \textit{baseline} yang digunakan diperoleh dari \textit{coarse grid-search} pada subab \ref{sec:efficiency_analysis} adalah SVM dengan kernel RBF, 32 komponen PCA, dan parameter $C=2^{10}$, $\gamma=2^{-10}$ untuk Sensor A, sedangkan untuk Sensor B adalah SVM dengan kernel RBF, 16 komponen PCA, dan parameter $C=2^{5}$, $\gamma=2^{-5}$. Pada bagian ini, dilakukan evaluasi performa model \textit{baseline} dengan data uji yang berbeda (\textit{Dataset} B).
\subsection{Metrik Klasifikasi}
Metrik klasifikasi model \textit{baseline} pada dataset pengujian disajikan pada Tabel~\ref{tab:metrics-baseline_A} dan~\ref{tab:matrics-baseline_B}.
\begin{table}[htbp]
\centering
\caption{\textit{Classification report} model \textit{baseline} pada Sensor A}
\label{tab:metrics-baseline_A}
\begin{tabular}{lrrrr}
\toprule
& precision & recall & f1-score & support \\
\midrule
0 & 0.99 & 0.98 & 0.99 & 2565.00 \\
1 & 0.99 & 1.00 & 1.00 & 2565.00 \\
2 & 1.00 & 1.00 & 1.00 & 2565.00 \\
3 & 1.00 & 1.00 & 1.00 & 2565.00 \\
4 & 1.00 & 1.00 & 1.00 & 2565.00 \\
5 & 1.00 & 1.00 & 1.00 & 2565.00 \\
6 & 0.99 & 1.00 & 0.99 & 2565.00 \\
accuracy & 1.00 & 1.00 & 1.00 & 1.00 \\
macro avg & 1.00 & 1.00 & 1.00 & 17955.00 \\
weighted avg & 1.00 & 1.00 & 1.00 & 17955.00 \\
\bottomrule
\end{tabular}
\end{table}
\begin{table}[htbp]
\centering
\caption{\textit{Classification report} model \textit{baseline} pada Sensor B}
\label{tab:metrics-baseline_B}
\begin{tabular}{lrrrr}
\toprule
& precision & recall & f1-score & support \\
\midrule
0 & 0.98 & 0.99 & 0.99 & 2565.00 \\
1 & 0.99 & 1.00 & 0.99 & 2565.00 \\
2 & 1.00 & 1.00 & 1.00 & 2565.00 \\
3 & 1.00 & 1.00 & 1.00 & 2565.00 \\
4 & 1.00 & 1.00 & 1.00 & 2565.00 \\
5 & 1.00 & 1.00 & 1.00 & 2565.00 \\
6 & 1.00 & 1.00 & 1.00 & 2565.00 \\
accuracy & 1.00 & 1.00 & 1.00 & 1.00 \\
macro avg & 1.00 & 1.00 & 1.00 & 17955.00 \\
weighted avg & 1.00 & 1.00 & 1.00 & 17955.00 \\
\bottomrule
\end{tabular}
\end{table}
Hasil ini menunjukkan bahwa model \textit{baseline} kedua sensor mencapai akurasi 99\%. Nilai \textit{recall} yang relatif tinggi (99.0\%) menunjukkan bahwa model lebih sensitif untuk mendeteksi kelas kerusakan, meskipun nilai \textit{precision} yang sedikit lebih rendah, menunjukkan bahwa ada beberapa \textit{false-positive} yang dihasilkan.
\subsection{\textit{Confusion Matrix}}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{chapters/img/sensor1/cm_baseline_s1a_eval.png}
\caption{\textit{Confusion matrix} model \textit{baseline} SVM (RBF) pada Sensor A}
\label{fig:confusion-matrix-baseline_A}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{chapters/img/sensor2/cm_baseline_s2a_eval.png}
\caption{\textit{Confusion matrix} model \textit{baseline} SVM (RBF) pada Sensor B}
\label{fig:confusion-matrix-baseline_B}
\end{figure}
Dari Gambar~\ref{fig:confusion-matrix-baseline_A} dan~\ref{fig:confusion-matrix-baseline_B}, terlihat bahwa kedua model minim kesalahan klasifikasi, dengan sebagian besar prediksi berada di diagonal utama. Beberapa kesalahan klasifikasi minor terjadi paling banyak antara kelas 0 dengan kelas 1 dan kelas 6.
\section{\textit{Fine Grid-Search}}
Optimasi model yang dilakukan yaitu dengan melakukan \textit{fine grid-search} pada rentang \textit{hyperparameter} model \textit{baseline} yang digunakan pada Subab~\ref{sec:baseline_performance}. Untuk Sensor A dengan $n_{\text{components}} = 32$ rentang parameter yang dicari adalah
\begin{align*}
C &= \{\, 2^8,\, 2^{8.5},\, \ldots,\, 2^{12} \,\} \\
\gamma &= \{\, 2^{-12},\, 2^{-11.5},\, \ldots ,\, 2^{-8} \,\},
\end{align*}sedangkan Sensor B dengan $n_{\text{components}} = 16$ rentang parameter yang dicari adalah
\begin{align*}
C &= \{\, 2^3,\, 2^{3.5},\, \ldots,\, 2^{7} \,\} \\
\gamma &= \{\, 2^{-7},\, 2^{-6.5},\, \ldots ,\, 2^{-3} \,\}.
\end{align*}. Pada proses ini, \textit{standard scaler} dan \textit{stratified k-fold cross validation} dengan $k=5$ tetap digunakan untuk menjaga konsistensi evaluasi model, sehingga total kombinasi parameter yang diuji adalah \(9\times9 = 81\) kandidat model dengan total 405 kali \textit{fitting}.
\subsection{Diagram \textit{Fine Grid-Search Heatmap}}
Gambar~\ref{fig:svm_fine_heatmap} menunjukkan diagram \textit{heatmap} terhadap parameter \textit{fine grid-search} $C$ dan~$\gamma$ untuk masing-masing sensor. Akurasi tertinggi pada Sensor A diperoleh pada $C= \{\,2^{8}, \,2^{8.5}, \,2^{9}, \,2^{9.5}, \,2^{10}, \,2^{10.5},\,2^{11}, \,2^{11.5}, \,2^{12} \,\}$ dan $\gamma=2^{-9.5}$ dengan akurasi meningkat 0.15\% menjadi 99.54\%, sedangkan pada Sensor B diperoleh pada $C = \{\,2^{5},\,2^{5.5} \,\}$ dan $\gamma= \{\, 2^{-3},\, 2^{-3.5},\, 2^{-4}\,\}$ dengan akurasi meningkat 0.05\% menjadi 99.49\%. Hasil ini menunjukkan bahwa optimasi \textit{hyperparameter} lebih lanjut dapat meningkatkan performa model meskipun peningkatannya relatif kecil dibandingkan dengan model \textit{baseline}.
\begin{figure}
\centering
\subfloat[Sensor A (PCA 32)]{\includegraphics[width=.48\textwidth]{chapters/img/sensor1/grid_fine_pca32.png}}
\centering
\subfloat[Sensor B (PCA 16)]{\includegraphics[width=.48\textwidth]{chapters/img/sensor2/grid_fine_pca16.png}}
\caption{\textit{Heatmap mean test score} terhadap \textit{fine grid-search parameter} $C$ dan~$\gamma$}
\label{fig:svm_fine_heatmap}
\end{figure}
\section{Evaluasi Model \textit{Fine Grid-Search}}
Model \textit{fine grid-search} dilatih pada \textit{dataset} A dan perlu dievaluasi performanya dengan data uji yang berbeda (\textit{dataset} B) untuk mengukur peningkatan performa dibandingkan model \textit{baseline}.
\subsection{Metrik Klasifikasi}
Hasil performa model \textit{fine grid-search} pada data uji disajikan pada Tabel~\ref{tab:metrics-fine-a} dan~\ref{tab:metrics-fine-b}.
\begin{table}
\centering
\caption{\textit{Classification report} model Sensor A}
\label{tab:metrics-fine-a}
\begin{tabular}{lrrrr}
\toprule
& precision & recall & f1-score & support \\
\midrule
0 & 0.99 & 0.99 & 0.99 & 2565.00 \\
1 & 0.99 & 1.00 & 0.99 & 2565.00 \\
2 & 1.00 & 1.00 & 1.00 & 2565.00 \\
3 & 1.00 & 1.00 & 1.00 & 2565.00 \\
4 & 1.00 & 1.00 & 1.00 & 2565.00 \\
5 & 1.00 & 1.00 & 1.00 & 2565.00 \\
6 & 1.00 & 1.00 & 1.00 & 2565.00 \\
accuracy & 1.00 & 1.00 & 1.00 & 1.00 \\
macro avg & 1.00 & 1.00 & 1.00 & 17955.00 \\
weighted avg & 1.00 & 1.00 & 1.00 & 17955.00 \\
\bottomrule
\end{tabular}
\end{table}
\begin{table}
\centering
\caption{\textit{Classification report} model Sensor B}
\label{tab:metrics-fine-b}
\begin{tabular}{lrrrr}
\toprule
& precision & recall & f1-score & support \\
\midrule
0 & 0.98 & 0.97 & 0.98 & 2565.00 \\
1 & 0.99 & 1.00 & 1.00 & 2565.00 \\
2 & 1.00 & 1.00 & 1.00 & 2565.00 \\
3 & 1.00 & 1.00 & 1.00 & 2565.00 \\
4 & 0.99 & 1.00 & 1.00 & 2565.00 \\
5 & 1.00 & 1.00 & 1.00 & 2565.00 \\
6 & 0.98 & 0.99 & 0.99 & 2565.00 \\
accuracy & 0.99 & 0.99 & 0.99 & 0.99 \\
macro avg & 0.99 & 0.99 & 0.99 & 17955.00 \\
weighted avg & 0.99 & 0.99 & 0.99 & 17955.00 \\
\bottomrule
\end{tabular}
\end{table}
\subsection{\textit{Confusion Matrix}}
\begin{figure}[H]
\centering
\includegraphics[width=.8\textwidth]{chapters/img/sensor1/cm_fine_s1a_eval.png}
\caption{\textit{Confusion matrix} model \textit{fine grid-search} pada Sensor A}
\label{fig:cm_fine_s1a_eval}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=.8\textwidth]{chapters/img/sensor2/cm_fine_s2a_eval.png}
\caption{\textit{Confusion matrix} model \textit{fine grid-search} pada Sensor B}
\label{fig:cm_fine_s2a_eval}
\end{figure}
\section{Model \textit{Inference} dan Visualisasi Prediksi}
Setelah model \textit{fine grid-search} dievaluasi, dilakukan proses \textit{inference} pada data uji untuk memvisualisasikan prediksi model. Gambar~\ref{fig:inference_s1a} dan~\ref{fig:inference_s2a} menunjukkan hasil prediksi model pada Sensor A dan Sensor B dalam \textit{heatmap} dan grafik probabilitasnya.
% \section{Efisiensi Komputasi}
% \subsection{Perbandingan Waktu Latih}
% \subsection{Perbandingan Waktu \textit{Inference}}
% \begin{table}[htbp]
% \centering
% \caption{Perbandingan waktu inference model \textit{baseline} dan \textit{preprocessing pipeline}}
% \label{tab:training-time}
% \begin{tabular}{lrr}
% \hline
% Iterasi & \textit{Baseline} (detik) & \textit{preprocessing pipeline} (detik)\\
% 1 & & 6.53 \\
% 2 & & 6.08 \\
% 3 & & 6.08 \\
% 4 & & 6.10 \\
% 5 & & 6.20 \\
% Rata-rata & & 6.20 \\
% \hline
% \end{tabular}
% \end{table}
% \section{}
% Model \textit{baseline} yang dilakukan dengan \textit{preprocessing pipeline} mengurangi waktu latih sekitar x \%, sedangkan waktu \textit{inference} tiap sampel berkurang sekitar x \%. Hal ini menunjukkan keefektifan PCA dalam mereduksi dimensi fitur dan \textit{standard scaler}, dengan begitu dapat mengurangi beban komputasi tanpa mengorbankan akurasi.
% Konfigurasi terbaik diperoleh pada kombinasi fitur waktu--frekuensi dengan SVM-\textit{[kernel]}, menghasilkan Akurasi sebesar \textit{[acc\_best]}\%, Macro-F1 sebesar \textit{[f1\_best]}\%, dan Kappa sebesar \textit{[kappa\_best]} pada data uji (Tabel~\ref{tab:main-results}). Dibandingkan baseline domain waktu saja, Macro-F1 meningkat sekitar \textit{[delta\_f1\_time]} poin persentase; dibandingkan domain frekuensi saja, peningkatan mencapai \textit{[delta\_f1\_freq]} poin persentase. Hasil ini mengindikasikan bahwa informasi pelengkap antara dinamika temporal dan spektral berkontribusi nyata terhadap separabilitas kelas.
% Performa pada metrik Balanced Accuracy dan Macro-Recall juga konsisten, menandakan model tidak terlalu bias pada kelas mayoritas. Nilai Kappa \textit{[kappa\_best]} mengindikasikan tingkat kesepakatan yang \textit{[moderat/tinggi]} melampaui kebetulan.
% \section{Analisis Per-Kelas dan Kesalahan}
% \begin{figure}[htbp]
% \centering
% % \includegraphics[width=0.8\textwidth]{img/confusion_matrix.pdf}
% \fbox{\begin{minipage}[c][0.30\textheight][c]{0.80\textwidth}\centering
% Placeholder Confusion Matrix
% \end{minipage}}
% \caption{Confusion matrix pada data uji. Isikan gambar aktual dari pipeline evaluasi.}
% \label{fig:cm}
% \end{figure}
% \begin{table}[htbp]
% \centering
% \caption{Metrik per-kelas pada data uji. Gunakan bila diperlukan untuk melengkapi Confusion Matrix.}
% \label{tab:per-class}
% \begin{tabular}{lccc}
% \hline
% Kelas & Precision & Recall & F1 \\
% \hline
% A & -- & -- & -- \\
% B & -- & -- & -- \\
% C & -- & -- & -- \\
% % ... tambah baris sesuai jumlah kelas
% \hline
% \end{tabular}
% \end{table}
% Confusion Matrix pada Gambar~\ref{fig:cm} menunjukkan pola salah klasifikasi yang dominan antara kelas \textit{[kelas\_A]} dan \textit{[kelas\_B]}. Dua kelas ini memiliki respons spektral yang mirip pada rentang \textit{[f\_low--f\_high]} Hz, sehingga kesalahan terutama terjadi ketika amplitudo sinyal rendah atau \textit{signal-to-noise ratio} menurun. Sebaliknya, kelas \textit{[kelas\_C]} memperlihatkan separasi yang baik dengan Recall \textit{[recall\_C]}\% dan F1 \textit{[f1\_C]}\% (Tabel~\ref{tab:per-class}).
% Analisis kesalahan kasus-per-kasus menunjukkan bahwa \textit{[proporsi\_\%]}\% prediksi keliru terjadi pada sampel dengan \textit{[ciri sinyal/condisi uji]} dan \textit{[konfigurasi sensor]}. Hal ini menyarankan perlunya \textit{[strategi perbaikan, mis. penambahan fitur bandpass tertentu atau penyeimbangan kelas]}.
% \section{Ablasi dan Sensitivitas}
% \subsection{Ablasi Fitur}
% \begin{figure}[htbp]
% \centering
% \includegraphics[width=0.75\textwidth]{example-image-a}
% \fbox{\begin{minipage}[c][0.22\textheight][c]{0.70\textwidth}\centering
% Placeholder Bar Chart: Time vs Freq vs Kombinasi
% \end{minipage}}
% \caption{Perbandingan performa berdasarkan jenis fitur.}
% \label{fig:ablation-features}
% \end{figure}
% Studi ablation pada Gambar~\ref{fig:ablation-features} menegaskan bahwa kombinasi fitur memberikan peningkatan \textit{[delta\_ablation]} poin persentase pada Macro-F1 dibandingkan fitur domain waktu saja. Hal ini mengindikasikan bahwa karakteristik harmonik dan komponen frekuensi transien yang ditangkap STFT berkontribusi pada pemisahan kelas yang lebih baik.
% \subsection{Parameter STFT dan Windowing}
% \begin{table}[htbp]
% \centering
% \caption{Sensitivitas terhadap parameter STFT pada data validasi.}
% \label{tab:stft-sensitivity}
% \begin{tabular}{lcccc}
% \hline
% Window & n\_fft & Overlap & Akurasi & Macro-F1 \\
% \hline
% Hann & -- & -- & -- & -- \\
% Hann & -- & -- & -- & -- \\
% (Tanpa window) & -- & -- & -- & -- \\
% \hline
% \end{tabular}
% \end{table}
% Eksperimen sensitivitas pada Tabel~\ref{tab:stft-sensitivity} memperlihatkan adanya \textit{trade-off} antara resolusi waktu dan frekuensi. Peningkatan \textit{n\_fft} cenderung memperhalus resolusi frekuensi namun mengurangi ketelitian temporal, sedangkan overlap yang lebih besar \textit{[overlap\_\% range]}\% membantu stabilitas estimasi fitur pada sinyal bising. Penggunaan window Hann memberikan kenaikan Macro-F1 sekitar \textit{[delta\_hann]} poin dibanding tanpa window, menegaskan peran pengurangan \textit{spectral leakage}.
% \subsection{Pendekatan Sensor Terbatas}
% \begin{figure}[htbp]
% \centering
% % placeholder
% \includegraphics[width=0.75\textwidth]{example-image-a}
% \fbox{\begin{minipage}[c][0.22\textheight][c]{0.70\textwidth}\centering
% Placeholder: Performa vs Jumlah/Posisi Sensor
% \end{minipage}}
% \caption{Dampak jumlah/konfigurasi sensor terhadap performa.}
% \label{fig:sensor-limited}
% \end{figure}
% Hasil pada Gambar~\ref{fig:sensor-limited} menunjukkan bahwa pengurangan dari \textit{[n\_sensors\_full]} menjadi \textit{[n\_sensors\_min]} sensor hanya menurunkan Macro-F1 sekitar \textit{[delta\_perf\_sensors]} poin, khususnya ketika sensor ditempatkan pada \textit{[posisi sensor terbaik]}. Ini mengindikasikan bahwa pendekatan sensor terbatas tetap layak untuk implementasi dengan biaya perangkat keras yang lebih rendah, selama pemilihan posisi sensor dioptimalkan.
% \section{Robustness dan Generalisasi}
% \begin{table}[htbp]
% \centering
% \caption{Ringkasan kinerja antar-fold (jika menggunakan k-fold).}
% \label{tab:kfold}
% \begin{tabular}{lcc}
% \hline
% Metrik & Rata-rata & Deviasi Standar \\
% \hline
% Macro-F1 & -- & -- \\
% Akurasi & -- & -- \\
% \hline
% \end{tabular}
% \end{table}
% Pada skema validasi silang \textit{k}-fold, variasi performa relatif rendah dengan simpangan baku Macro-F1 sebesar \textit{[std\_f1]} (Tabel~\ref{tab:kfold}), menandakan stabilitas model terhadap variasi subset data. Penambahan noise sintetis pada tingkat SNR \textit{[snr levels]} menunjukkan penurunan performa yang \textit{[ringan/sedang/bermakna]} sekitar \textit{[delta\_snr]} poin; augmentasi \textit{[jenis augmentasi]} membantu mengkompensasi sebagian penurunan tersebut.
% Pada skenario \textit{domain shift} \textit{[nama skenario]}, model mempertahankan Macro-F1 sebesar \textit{[f1\_shift]}\%, yang menunjukkan \textit{[derajat generalisasi]} terhadap kondisi yang berbeda dari data pelatihan.
% \section{Perbandingan dengan Pustaka/Baseline}
% Temuan kami selaras dengan tren yang dilaporkan oleh \textcite{abdeljaber2017}, khususnya mengenai pentingnya informasi frekuensi untuk mendeteksi lokasi kerusakan. Meskipun demikian, perbedaan \textit{setup} eksperimen (\textit{[jenis struktur/skenario uji]}, konfigurasi sensor, dan definisi kelas) membuat angka metrik tidak dapat dibandingkan secara langsung. Oleh karena itu, perbandingan difokuskan pada pola dan arah peningkatan, bukan nilai absolut.
% \section{Kompleksitas dan Implementasi}
% Model SVM dengan fitur \textit{[jenis fitur terbaik]} menawarkan waktu inferensi sekitar \textit{[t\_infer\_ms]} ms per sampel pada \textit{[perangkat/CPU/GPU]}. Tahap ekstraksi STFT memerlukan \textit{[t\_stft\_ms]} ms per segmen dengan parameter \textit{[n\_fft]}, overlap \textit{[overlap\_\%]}\%, dan window Hann. Secara keseluruhan, latensi ujung-ke-ujung diperkirakan \textit{[t\_end2end\_ms]} ms, yang \textit{[memadai/belum memadai]} untuk aplikasi \textit{[real-time/near real-time]}.
% Dengan \textit{[n\_sensors\_min]} sensor, kebutuhan komputasi dan bandwidth data berkurang \textit{[proporsi pengurangan]} dibanding konfigurasi penuh, yang memperbaiki kelayakan implementasi lapangan tanpa mengorbankan akurasi secara signifikan.
% \section{Ringkasan Bab}
% \begin{itemize}
% \item Konfigurasi terbaik (\textit{[konfigurasi terbaik]}) mencapai Akurasi \textit{[acc\_best]}\%, Macro-F1 \textit{[f1\_best]}\%, dan Kappa \textit{[kappa\_best]} pada data uji.
% \item Kesalahan dominan terjadi antara kelas \textit{[kelas\_A]} dan \textit{[kelas\_B]} karena kemiripan respons pada \textit{[f\_low--f\_high]} Hz; strategi \textit{[strategi perbaikan]} direkomendasikan.
% \item Ablasi menegaskan manfaat kombinasi fitur; window Hann dan parameter STFT \textit{[n\_fft, overlap]} memberi keseimbangan resolusi yang baik.
% \item Pendekatan sensor terbatas dengan \textit{[n\_sensors\_min]} sensor tetap layak dengan penurunan performa \textit{[delta\_perf\_sensors]} poin.
% \item Model menunjukkan stabilitas antar-fold (\textit{[std\_f1]}) dan ketahanan \textit{[terhadap noise/domain shift]} dengan penyesuaian \textit{[augmentasi/penalaan]}.
% \end{itemize}

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2b429e2b45db4752eaaa769f35d9de0455f67a3c540b22fe40940bfb09847fb
size 69364

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:231eecf31113cb6e602ef94d0316dccc2da11a0843fc0cf1c07fae280931dd43
size 370078

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b9c0aa8274d4b7bd9095598e9e3b9853d461de18837fab2fe459a3e68f43cc9e
size 1196576

BIN
latex/chapters/img/flow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:976b59a668753aa5526f1f535d41cc1f8d14b2bd3f7af0cad79367e4c0bd056b
size 101919

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0db69ce2a557747b859a529273c14c542030f7cebb99aa0e3c0286f2dee2625b
size 103958

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a797b23032f469942623ee5f3c0e63c5c617f479813f38b9b42a2f45a9402a44
size 82443

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a9000564e224fb539aaf6248ce51d50ae0723e2b54b898d0168e168d097ca8b7
size 84759

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f508d537ef40e1c5f96c0aa962be6279072e0971c064f398bbde8834b7745ff3
size 258668

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8066c6a0bcfdca8cbb3e8a2bf45f008da269d3a27a00d7f5b819ae0b0722ffe8
size 106637

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9ebcc8e82e82118dacbebcd8a65ddeb24aaae5d785b91d51ea5627072e46d1df
size 107256

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d47abef46dd76a8295245d97e142130cbe2611adf0c680cbda00141d4bb2ec66
size 122507

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0b391cca56d8bfdbf92d0728dc1beed74d15919d0a1083cdda9094a4994d63eb
size 105020

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c834d24b9ec043adc18f83e00bac718fe10e7bdcfefc926c68a7e1b5013a417c
size 116388

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a25fee61921224f4c0e12f935b5886d063ab7c5d379ed5e2f969e6887297053b
size 139087

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6ec29314beeb4ee90a696b404cf6a1759435988832311aa4a14a15da2beeebb5
size 117619

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ccbeabc5d2b40a1a94925541ea1c51b28eed47fa8e7d2405af517bec1293403a
size 133276

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d25f5e991ef79828a2f87c8c640d4117d942a182224d95c903a15f64bc0e9ddd
size 126291

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d25f5e991ef79828a2f87c8c640d4117d942a182224d95c903a15f64bc0e9ddd
size 126291

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3012d2d45133d67cb63f72ac29d3b9b15cb33c8d96b359e748093acf0da88728
size 121465

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5e69d498fa3980fa4a3765d930e904c99c712297562a5a9983ee8873d9326743
size 183478

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:27b36bb18430aace2077c7c51211e76e73b3ed753b8456fb1a13c4be636c3389
size 448492

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:229ecc80bb58bf6da90f18e0103dbdb8285a5c5c95cedac7cc8e6a93545cd0a3
size 271444

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4c7888bb21ef7a3d7dad8b9e815b7eb56c822be7662d7800ffc0f10e0afbd783
size 29882

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:07e0b699840fc4d5ff7bb9530602f7a13008cdc193c7c6c334790efd52d87a3e
size 668812

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:657fed97c4027f88f7831c02b6728209769bae7a536e163491f5665923bdb530
size 294823

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c2f4cfaaad0b7ef1bec2679acd0f022e0a66f15a7855c8f266fd56acfbd6390e
size 252348

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f84f425416abde3da0f0e4303895899d8f2149d3340f01a4578073083f8eb265
size 378337

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0302a06bc570f8006ad5f3c0db14ab8050b0321410308de254b3c2c06304003c
size 320951

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da42463b34afa744ae106d06348918edaea39c277e9f2c051c778aa69a9b25c3
size 291464

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9314c1abb3fa6aa42d50c8d4bdd9de26c17f0f79a84e141966b59427f5b69ec2
size 359676

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a03f6a6ac939bc322023e6933a590a9bd5bc2c92e57f3c338f986d6260eebddc
size 289930

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cb9af7df4069086aa95678c984fb28c1d7df729f60f529116191f4455abbb086
size 749475

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1c15322ed17a4c18715d4944c45aa074469ffb2da2398108eb8d42ea26b51909
size 413507

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d914de5c60529f0c4fd4738a3a6516e8b40032b3fa7f0a523d90d69a8157d5e5
size 292193

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:67bd04de25bede3eb4f68b604257284a782ff33d815f9e9d7fbd1bccb6cd7249
size 321818

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e23f6770f578f5a83b4dec7086a7018cac72c6cc07d6e90592450147371b6487
size 81996

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6f62708b784c9866851345d5ddb0c77b8d4acf2cfd786b415944d61e3f174790
size 82826

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:86890d5f72b0769398020df79a37a4b8204f204e32c2269c9f7eda40b37607f3
size 240617

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d56ab3807e8bed61127116e2bbbd0bfef62098695418bc039a48ccab77cf5f73
size 108247

Some files were not shown because too many files have changed in this diff Show More