Compare commits
25 Commits
feat/90-fe
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb9dee10de | ||
|
|
93d720b676 | ||
|
|
52dccce7e2 | ||
|
|
bf0de65fb7 | ||
|
|
7ca70fbdc3 | ||
|
|
b35944ee3e | ||
|
|
8f51963d0f | ||
|
|
5c513e4629 | ||
|
|
38ece73768 | ||
|
|
e5b9806462 | ||
|
|
8dbb448b32 | ||
|
|
033d949325 | ||
|
|
643c0ebce1 | ||
|
|
4851a9aa5d | ||
|
|
fd765b113f | ||
|
|
fe801b0a1c | ||
|
|
dbc62fea32 | ||
|
|
1ad235866e | ||
|
|
05796d0165 | ||
|
|
f8e9ac93a0 | ||
|
|
04546f8c35 | ||
|
|
26450026bb | ||
|
|
3a17cc1331 | ||
|
|
e9f953f731 | ||
|
|
2c5c78b83c |
52
.github/workflows/latex-lint.yml
vendored
Normal file
52
.github/workflows/latex-lint.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: LaTeX Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
paths:
|
||||
- 'latex/**/*.tex'
|
||||
- 'latex/main.tex'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install chktex
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y chktex
|
||||
|
||||
- name: Run chktex inside latex/
|
||||
working-directory: latex
|
||||
run: |
|
||||
TEX_FILES=$(find . -type f -name "*.tex")
|
||||
if [ -z "$TEX_FILES" ]; then
|
||||
echo "No .tex files found in latex/. Skipping lint."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "🔍 Linting .tex files with chktex..."
|
||||
FAIL=0
|
||||
|
||||
for f in $TEX_FILES; do
|
||||
echo "▶ Checking $f"
|
||||
# Run chktex and show output; capture error status
|
||||
if ! chktex "$f"; then
|
||||
echo "::warning file=$f::ChkTeX found issues in $f"
|
||||
FAIL=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $FAIL -ne 0 ]; then
|
||||
echo "::error::❌ Lint errors or warnings were found in one or more .tex files above."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ All files passed chktex lint."
|
||||
fi
|
||||
102
.github/workflows/latexdiff.yml
vendored
Normal file
102
.github/workflows/latexdiff.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
name: LaTeX Diff
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
base_branch:
|
||||
description: 'Base branch (older version)'
|
||||
required: true
|
||||
compare_branch:
|
||||
description: 'Compare branch (new version)'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
latexdiff:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/xu-cheng/texlive-full:latest
|
||||
options: --user root
|
||||
|
||||
steps:
|
||||
- name: Install latexpand (Perl script)
|
||||
run: |
|
||||
tlmgr init-usertree
|
||||
tlmgr install latexpand
|
||||
|
||||
- name: Checkout base branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.base_branch }}
|
||||
path: base
|
||||
|
||||
- name: Checkout compare branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.compare_branch }}
|
||||
path: compare
|
||||
|
||||
|
||||
- name: Create output folder
|
||||
run: mkdir -p diff_output
|
||||
|
||||
- name: Flatten base/main.tex (with latexpand)
|
||||
run: |
|
||||
cd base/latex
|
||||
echo "📂 Listing files in base/latex:"
|
||||
ls -R
|
||||
echo "🔄 Flattening with latexpand..."
|
||||
latexpand --verbose --keep-comments --output=../../diff_output/base_flat.tex main.tex
|
||||
echo "✅ Preview of base_flat.tex:"
|
||||
head -n 50 ../../diff_output/base_flat.tex
|
||||
|
||||
|
||||
- name: Flatten compare/main.tex (with latexpand)
|
||||
run: |
|
||||
cd compare/latex
|
||||
echo "📂 Listing files in compare/latex:"
|
||||
ls -R
|
||||
echo "🔄 Flattening with latexpand..."
|
||||
latexpand --verbose --keep-comments --output=../../diff_output/compare_flat.tex main.tex
|
||||
echo "✅ Preview of compare_flat.tex:"
|
||||
head -n 50 ../../diff_output/compare_flat.tex
|
||||
|
||||
- name: Generate diff.tex using latexdiff
|
||||
run: |
|
||||
latexdiff diff_output/base_flat.tex diff_output/compare_flat.tex > diff_output/diff.tex
|
||||
|
||||
- name: Copy thesis.cls to diff_output
|
||||
run: cp compare/latex/thesis.cls diff_output/
|
||||
|
||||
- name: Copy chapters/img into diff_output
|
||||
run: |
|
||||
# Create the same chapters/img path inside diff_output
|
||||
mkdir -p diff_output/chapters/img
|
||||
# Copy all images from compare branch into diff_output
|
||||
cp -R compare/latex/chapters/img/* diff_output/chapters/img/
|
||||
|
||||
- name: Copy .bib files into diff_output
|
||||
run: |
|
||||
mkdir -p diff_output
|
||||
cp compare/latex/*.bib diff_output/
|
||||
|
||||
- name: Override “\input{preamble/fonts}” in diff.tex
|
||||
run: |
|
||||
sed -i "/\\input{preamble\/fonts}/c % — replaced by CI: use TeX Gyre fonts instead of Times New Roman\/Arial\n\\\setmainfont{TeX Gyre Termes}\n\\\setsansfont{TeX Gyre Heros}\n\\\setmonofont{TeX Gyre Cursor}" diff_output/diff.tex
|
||||
|
||||
- name: Print preview of diff.tex (after font override)
|
||||
run: |
|
||||
echo "📄 Preview of diff_output/diff.tex after font override:"
|
||||
head -n 50 diff_output/diff.tex
|
||||
|
||||
- name: Compile diff.tex to PDF
|
||||
working-directory: diff_output
|
||||
continue-on-error: true
|
||||
run: |
|
||||
xelatex -interaction=nonstopmode diff.tex
|
||||
xelatex -interaction=nonstopmode diff.tex
|
||||
|
||||
- name: Upload diff output files
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: latex-diff-output
|
||||
path: diff_output/
|
||||
29
.github/workflows/latexmk.yml
vendored
Normal file
29
.github/workflows/latexmk.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Render XeLaTeX on PR to dev
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
build-pdf:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Compile XeLaTeX
|
||||
uses: dante-ev/latex-action@2021-A
|
||||
with:
|
||||
root_file: main.tex
|
||||
working_directory: latex
|
||||
compiler: xelatex
|
||||
args: -interaction=nonstopmode -halt-on-error -file-line-error
|
||||
extra_system_packages: "fonts-freefont-otf"
|
||||
|
||||
- name: Upload compiled PDF
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: compiled-pdf
|
||||
path: latex/main.pdf
|
||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -1,7 +1,4 @@
|
||||
{
|
||||
"python.analysis.extraPaths": [
|
||||
"./code/src/features",
|
||||
"${workspaceFolder}/code/src"
|
||||
],
|
||||
"python.analysis.extraPaths": ["./code/src/features"],
|
||||
"jupyter.notebookFileRoot": "${workspaceFolder}/code"
|
||||
}
|
||||
|
||||
10
README.md
10
README.md
@@ -4,20 +4,14 @@ This repository contains the work related to my thesis, which focuses on damage
|
||||
|
||||
**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
|
||||
|
||||
2. run the notebook
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sensor1 = pd.read_csv('D:/thesis/data/converted/raw/DAMAGE_1/DAMAGE_0_TEST1_01.csv',sep=',')\n",
|
||||
"sensor2 = pd.read_csv('D:/thesis/data/converted/raw/DAMAGE_1/DAMAGE_0_TEST1_02.csv',sep=',')"
|
||||
"sensor1 = pd.read_csv('D:/thesis/data/converted/raw/DAMAGE_1/DAMAGE_1_TEST1_01.csv',sep=',')\n",
|
||||
"sensor2 = pd.read_csv('D:/thesis/data/converted/raw/DAMAGE_1/DAMAGE_1_TEST1_02.csv',sep=',')"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -101,16 +101,13 @@
|
||||
"source": [
|
||||
"# Combined Plot for sensor 1 and sensor 2 from data1 file in which motor is operated at 800 rpm\n",
|
||||
"\n",
|
||||
"plt.plot(df1['s2'], label='Sensor 1', color='C1', alpha=0.6)\n",
|
||||
"plt.plot(df1['s1'], label='Sensor 2', color='C0', alpha=0.6)\n",
|
||||
"plt.plot(df1['s2'], label='sensor 2')\n",
|
||||
"plt.plot(df1['s1'], label='sensor 1', alpha=0.5)\n",
|
||||
"plt.xlabel(\"Number of samples\")\n",
|
||||
"plt.ylabel(\"Amplitude\")\n",
|
||||
"plt.title(\"Raw vibration signal\")\n",
|
||||
"plt.ylim(-7.5, 5)\n",
|
||||
"plt.legend()\n",
|
||||
"plt.locator_params(axis='x', nbins=8)\n",
|
||||
"plt.ylim(-1, 1) # Adjust range as needed\n",
|
||||
"plt.grid(True, linestyle='--', alpha=0.5)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
@@ -337,44 +334,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from mpl_toolkits.mplot3d import Axes3D\n",
|
||||
"\n",
|
||||
"# Assuming ready_data1a[0] is a DataFrame or 2D array\n",
|
||||
"spectrogram_data = ready_data1a[0].values # Convert to NumPy array if it's a DataFrame\n",
|
||||
"\n",
|
||||
"# Get the dimensions of the spectrogram\n",
|
||||
"num_frequencies, num_time_frames = spectrogram_data.shape\n",
|
||||
"\n",
|
||||
"# Create frequency and time arrays\n",
|
||||
"frequencies = np.arange(num_frequencies) # Replace with actual frequency values if available\n",
|
||||
"time_frames = np.arange(num_time_frames) # Replace with actual time values if available\n",
|
||||
"\n",
|
||||
"# Create a meshgrid for plotting\n",
|
||||
"T, F = np.meshgrid(time_frames, frequencies)\n",
|
||||
"\n",
|
||||
"# Create a 3D plot\n",
|
||||
"fig = plt.figure(figsize=(12, 8))\n",
|
||||
"ax = fig.add_subplot(111, projection='3d')\n",
|
||||
"\n",
|
||||
"# Plot the surface\n",
|
||||
"surf = ax.plot_surface(T, F, spectrogram_data, cmap='bwr', edgecolor='none')\n",
|
||||
"\n",
|
||||
"# Add labels and a color bar\n",
|
||||
"ax.set_xlabel('Time Frames')\n",
|
||||
"ax.set_ylabel('Frequency [Hz]')\n",
|
||||
"ax.set_zlabel('Magnitude')\n",
|
||||
"ax.set_title('3D Spectrogram')\n",
|
||||
"# Resize the z-axis (shrink it)\n",
|
||||
"z_min, z_max = 0, 0.1 # Replace with your desired range\n",
|
||||
"ax.set_zlim(z_min, z_max)\n",
|
||||
"ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1, 1, 0.5, 1])) # Shrink z-axis by 50%\n",
|
||||
"ax.set_facecolor('white')\n",
|
||||
"fig.colorbar(surf, ax=ax, shrink=0.5, aspect=10)\n",
|
||||
"\n",
|
||||
"# Show the plot\n",
|
||||
"plt.show()"
|
||||
"len(ready_data1a)\n",
|
||||
"# plt.pcolormesh(ready_data1[0])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -383,32 +344,12 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from cmcrameri import cm\n",
|
||||
"# Create a figure and subplots\n",
|
||||
"fig, axes = plt.subplots(2, 3, figsize=(15, 8), sharex=True, sharey=True)\n",
|
||||
"\n",
|
||||
"# Flatten the axes array for easier iteration\n",
|
||||
"axes = axes.flatten()\n",
|
||||
"\n",
|
||||
"# Loop through each subplot and plot the data\n",
|
||||
"for i in range(6):\n",
|
||||
" pcm = axes[i].pcolormesh(ready_data1a[i].transpose(), cmap='bwr', vmax=0.03, vmin=0.0)\n",
|
||||
" axes[i].set_title(f'Case {i} Sensor A', fontsize=12)\n",
|
||||
"\n",
|
||||
"# Add a single color bar for all subplots\n",
|
||||
"# Use the first `pcolormesh` object (or any valid one) for the color bar\n",
|
||||
"cbar = fig.colorbar(pcm, ax=axes, orientation='vertical')\n",
|
||||
"# cbar.set_label('Magnitude')\n",
|
||||
"\n",
|
||||
"# Set shared labels\n",
|
||||
"fig.text(0.5, 0.04, 'Time Frames', ha='center', fontsize=12)\n",
|
||||
"fig.text(0.04, 0.5, 'Frequency [Hz]', va='center', rotation='vertical', fontsize=12)\n",
|
||||
"\n",
|
||||
"# Adjust layout\n",
|
||||
"# plt.tight_layout(rect=[0.05, 0.05, 1, 1]) # Leave space for shared labels\n",
|
||||
"plt.subplots_adjust(left=0.1, right=0.75, top=0.9, bottom=0.1, wspace=0.2, hspace=0.2)\n",
|
||||
"\n",
|
||||
"plt.show()"
|
||||
" plt.pcolormesh(ready_data1a[i])\n",
|
||||
" plt.title(f'STFT Magnitude for case {i} sensor 1')\n",
|
||||
" plt.xlabel(f'Frequency [Hz]')\n",
|
||||
" plt.ylabel(f'Time [sec]')\n",
|
||||
" plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -594,8 +535,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"len(y_data[0])\n",
|
||||
"# y_data"
|
||||
"# len(y_data[0])\n",
|
||||
"y_data"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -633,16 +574,6 @@
|
||||
"X2a, y = create_ready_data('D:/thesis/data/converted/raw/sensor2')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"X1a.iloc[-1,:]\n",
|
||||
"# y[2565]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -688,24 +619,137 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from src.ml.model_selection import train_and_evaluate_model\n",
|
||||
"from sklearn.svm import SVC\n",
|
||||
"# Define models for sensor1\n",
|
||||
"models_sensor1 = {\n",
|
||||
" # \"Random Forest\": RandomForestClassifier(),\n",
|
||||
" # \"Bagged Trees\": BaggingClassifier(estimator=DecisionTreeClassifier(), n_estimators=10),\n",
|
||||
" # \"Decision Tree\": DecisionTreeClassifier(),\n",
|
||||
" # \"KNN\": KNeighborsClassifier(),\n",
|
||||
" # \"LDA\": LinearDiscriminantAnalysis(),\n",
|
||||
" \"SVM\": SVC(),\n",
|
||||
" # \"XGBoost\": XGBClassifier()\n",
|
||||
"}\n",
|
||||
"accuracies1 = []\n",
|
||||
"accuracies2 = []\n",
|
||||
"\n",
|
||||
"results_sensor1 = []\n",
|
||||
"for name, model in models_sensor1.items():\n",
|
||||
" res = train_and_evaluate_model(model, name, \"sensor1\", x_train1, y_train, x_test1, y_test, export='D:/thesis/models/sensor1')\n",
|
||||
" results_sensor1.append(res)\n",
|
||||
" print(f\"{name} on sensor1: Accuracy = {res['accuracy']:.2f}%\")\n"
|
||||
"\n",
|
||||
"# 1. Random Forest\n",
|
||||
"rf_model1 = RandomForestClassifier()\n",
|
||||
"rf_model1.fit(x_train1, y_train)\n",
|
||||
"rf_pred1 = rf_model1.predict(x_test1)\n",
|
||||
"acc1 = accuracy_score(y_test, rf_pred1) * 100\n",
|
||||
"accuracies1.append(acc1)\n",
|
||||
"# format with color coded if acc1 > 90\n",
|
||||
"acc1 = f\"\\033[92m{acc1:.2f}\\033[00m\" if acc1 > 90 else f\"{acc1:.2f}\"\n",
|
||||
"print(\"Random Forest Accuracy for sensor 1:\", acc1)\n",
|
||||
"rf_model2 = RandomForestClassifier()\n",
|
||||
"rf_model2.fit(x_train2, y_train)\n",
|
||||
"rf_pred2 = rf_model2.predict(x_test2)\n",
|
||||
"acc2 = accuracy_score(y_test, rf_pred2) * 100\n",
|
||||
"accuracies2.append(acc2)\n",
|
||||
"# format with color coded if acc2 > 90\n",
|
||||
"acc2 = f\"\\033[92m{acc2:.2f}\\033[00m\" if acc2 > 90 else f\"{acc2:.2f}\"\n",
|
||||
"print(\"Random Forest Accuracy for sensor 2:\", acc2)\n",
|
||||
"# print(rf_pred)\n",
|
||||
"# print(y_test)\n",
|
||||
"\n",
|
||||
"# 2. Bagged Trees\n",
|
||||
"bagged_model1 = BaggingClassifier(estimator=DecisionTreeClassifier(), n_estimators=10)\n",
|
||||
"bagged_model1.fit(x_train1, y_train)\n",
|
||||
"bagged_pred1 = bagged_model1.predict(x_test1)\n",
|
||||
"acc1 = accuracy_score(y_test, bagged_pred1) * 100\n",
|
||||
"accuracies1.append(acc1)\n",
|
||||
"# format with color coded if acc1 > 90\n",
|
||||
"acc1 = f\"\\033[92m{acc1:.2f}\\033[00m\" if acc1 > 90 else f\"{acc1:.2f}\"\n",
|
||||
"print(\"Bagged Trees Accuracy for sensor 1:\", acc1)\n",
|
||||
"bagged_model2 = BaggingClassifier(estimator=DecisionTreeClassifier(), n_estimators=10)\n",
|
||||
"bagged_model2.fit(x_train2, y_train)\n",
|
||||
"bagged_pred2 = bagged_model2.predict(x_test2)\n",
|
||||
"acc2 = accuracy_score(y_test, bagged_pred2) * 100\n",
|
||||
"accuracies2.append(acc2)\n",
|
||||
"# format with color coded if acc2 > 90\n",
|
||||
"acc2 = f\"\\033[92m{acc2:.2f}\\033[00m\" if acc2 > 90 else f\"{acc2:.2f}\"\n",
|
||||
"print(\"Bagged Trees Accuracy for sensor 2:\", acc2)\n",
|
||||
"\n",
|
||||
"# 3. Decision Tree\n",
|
||||
"dt_model = DecisionTreeClassifier()\n",
|
||||
"dt_model.fit(x_train1, y_train)\n",
|
||||
"dt_pred1 = dt_model.predict(x_test1)\n",
|
||||
"acc1 = accuracy_score(y_test, dt_pred1) * 100\n",
|
||||
"accuracies1.append(acc1)\n",
|
||||
"# format with color coded if acc1 > 90\n",
|
||||
"acc1 = f\"\\033[92m{acc1:.2f}\\033[00m\" if acc1 > 90 else f\"{acc1:.2f}\"\n",
|
||||
"print(\"Decision Tree Accuracy for sensor 1:\", acc1)\n",
|
||||
"dt_model2 = DecisionTreeClassifier()\n",
|
||||
"dt_model2.fit(x_train2, y_train)\n",
|
||||
"dt_pred2 = dt_model2.predict(x_test2)\n",
|
||||
"acc2 = accuracy_score(y_test, dt_pred2) * 100\n",
|
||||
"accuracies2.append(acc2)\n",
|
||||
"# format with color coded if acc2 > 90\n",
|
||||
"acc2 = f\"\\033[92m{acc2:.2f}\\033[00m\" if acc2 > 90 else f\"{acc2:.2f}\"\n",
|
||||
"print(\"Decision Tree Accuracy for sensor 2:\", acc2)\n",
|
||||
"\n",
|
||||
"# 4. KNeighbors\n",
|
||||
"knn_model = KNeighborsClassifier()\n",
|
||||
"knn_model.fit(x_train1, y_train)\n",
|
||||
"knn_pred1 = knn_model.predict(x_test1)\n",
|
||||
"acc1 = accuracy_score(y_test, knn_pred1) * 100\n",
|
||||
"accuracies1.append(acc1)\n",
|
||||
"# format with color coded if acc1 > 90\n",
|
||||
"acc1 = f\"\\033[92m{acc1:.2f}\\033[00m\" if acc1 > 90 else f\"{acc1:.2f}\"\n",
|
||||
"print(\"KNeighbors Accuracy for sensor 1:\", acc1)\n",
|
||||
"knn_model2 = KNeighborsClassifier()\n",
|
||||
"knn_model2.fit(x_train2, y_train)\n",
|
||||
"knn_pred2 = knn_model2.predict(x_test2)\n",
|
||||
"acc2 = accuracy_score(y_test, knn_pred2) * 100\n",
|
||||
"accuracies2.append(acc2)\n",
|
||||
"# format with color coded if acc2 > 90\n",
|
||||
"acc2 = f\"\\033[92m{acc2:.2f}\\033[00m\" if acc2 > 90 else f\"{acc2:.2f}\"\n",
|
||||
"print(\"KNeighbors Accuracy for sensor 2:\", acc2)\n",
|
||||
"\n",
|
||||
"# 5. Linear Discriminant Analysis\n",
|
||||
"lda_model = LinearDiscriminantAnalysis()\n",
|
||||
"lda_model.fit(x_train1, y_train)\n",
|
||||
"lda_pred1 = lda_model.predict(x_test1)\n",
|
||||
"acc1 = accuracy_score(y_test, lda_pred1) * 100\n",
|
||||
"accuracies1.append(acc1)\n",
|
||||
"# format with color coded if acc1 > 90\n",
|
||||
"acc1 = f\"\\033[92m{acc1:.2f}\\033[00m\" if acc1 > 90 else f\"{acc1:.2f}\"\n",
|
||||
"print(\"Linear Discriminant Analysis Accuracy for sensor 1:\", acc1)\n",
|
||||
"lda_model2 = LinearDiscriminantAnalysis()\n",
|
||||
"lda_model2.fit(x_train2, y_train)\n",
|
||||
"lda_pred2 = lda_model2.predict(x_test2)\n",
|
||||
"acc2 = accuracy_score(y_test, lda_pred2) * 100\n",
|
||||
"accuracies2.append(acc2)\n",
|
||||
"# format with color coded if acc2 > 90\n",
|
||||
"acc2 = f\"\\033[92m{acc2:.2f}\\033[00m\" if acc2 > 90 else f\"{acc2:.2f}\"\n",
|
||||
"print(\"Linear Discriminant Analysis Accuracy for sensor 2:\", acc2)\n",
|
||||
"\n",
|
||||
"# 6. Support Vector Machine\n",
|
||||
"svm_model = SVC()\n",
|
||||
"svm_model.fit(x_train1, y_train)\n",
|
||||
"svm_pred1 = svm_model.predict(x_test1)\n",
|
||||
"acc1 = accuracy_score(y_test, svm_pred1) * 100\n",
|
||||
"accuracies1.append(acc1)\n",
|
||||
"# format with color coded if acc1 > 90\n",
|
||||
"acc1 = f\"\\033[92m{acc1:.2f}\\033[00m\" if acc1 > 90 else f\"{acc1:.2f}\"\n",
|
||||
"print(\"Support Vector Machine Accuracy for sensor 1:\", acc1)\n",
|
||||
"svm_model2 = SVC()\n",
|
||||
"svm_model2.fit(x_train2, y_train)\n",
|
||||
"svm_pred2 = svm_model2.predict(x_test2)\n",
|
||||
"acc2 = accuracy_score(y_test, svm_pred2) * 100\n",
|
||||
"accuracies2.append(acc2)\n",
|
||||
"# format with color coded if acc2 > 90\n",
|
||||
"acc2 = f\"\\033[92m{acc2:.2f}\\033[00m\" if acc2 > 90 else f\"{acc2:.2f}\"\n",
|
||||
"print(\"Support Vector Machine Accuracy for sensor 2:\", acc2)\n",
|
||||
"\n",
|
||||
"# 7. XGBoost\n",
|
||||
"xgboost_model = XGBClassifier()\n",
|
||||
"xgboost_model.fit(x_train1, y_train)\n",
|
||||
"xgboost_pred1 = xgboost_model.predict(x_test1)\n",
|
||||
"acc1 = accuracy_score(y_test, xgboost_pred1) * 100\n",
|
||||
"accuracies1.append(acc1)\n",
|
||||
"# format with color coded if acc1 > 90\n",
|
||||
"acc1 = f\"\\033[92m{acc1:.2f}\\033[00m\" if acc1 > 90 else f\"{acc1:.2f}\"\n",
|
||||
"print(\"XGBoost Accuracy:\", acc1)\n",
|
||||
"xgboost_model2 = XGBClassifier()\n",
|
||||
"xgboost_model2.fit(x_train2, y_train)\n",
|
||||
"xgboost_pred2 = xgboost_model2.predict(x_test2)\n",
|
||||
"acc2 = accuracy_score(y_test, xgboost_pred2) * 100\n",
|
||||
"accuracies2.append(acc2)\n",
|
||||
"# format with color coded if acc2 > 90\n",
|
||||
"acc2 = f\"\\033[92m{acc2:.2f}\\033[00m\" if acc2 > 90 else f\"{acc2:.2f}\"\n",
|
||||
"print(\"XGBoost Accuracy:\", acc2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -714,35 +758,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"models_sensor2 = {\n",
|
||||
" # \"Random Forest\": RandomForestClassifier(),\n",
|
||||
" # \"Bagged Trees\": BaggingClassifier(estimator=DecisionTreeClassifier(), n_estimators=10),\n",
|
||||
" # \"Decision Tree\": DecisionTreeClassifier(),\n",
|
||||
" # \"KNN\": KNeighborsClassifier(),\n",
|
||||
" # \"LDA\": LinearDiscriminantAnalysis(),\n",
|
||||
" \"SVM\": SVC(),\n",
|
||||
" # \"XGBoost\": XGBClassifier()\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"results_sensor2 = []\n",
|
||||
"for name, model in models_sensor2.items():\n",
|
||||
" res = train_and_evaluate_model(model, name, \"sensor2\", x_train2, y_train, x_test2, y_test, export='D:/thesis/models/sensor2')\n",
|
||||
" results_sensor2.append(res)\n",
|
||||
" print(f\"{name} on sensor2: Accuracy = {res['accuracy']:.2f}%\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"all_results = {\n",
|
||||
" \"sensor1\": results_sensor1,\n",
|
||||
" \"sensor2\": results_sensor2\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"print(all_results)"
|
||||
"print(accuracies1)\n",
|
||||
"print(accuracies2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -754,48 +771,36 @@
|
||||
"import numpy as np\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"def prepare_plot_data(results_dict):\n",
|
||||
" # Gather unique model names\n",
|
||||
" models_set = {entry['model'] for sensor in results_dict.values() for entry in sensor}\n",
|
||||
" models = sorted(list(models_set))\n",
|
||||
" \n",
|
||||
" # Create dictionaries mapping sensor -> accuracy list ordered by model name\n",
|
||||
" sensor_accuracies = {}\n",
|
||||
" for sensor, entries in results_dict.items():\n",
|
||||
" # Build a mapping: model -> accuracy for the given sensor\n",
|
||||
" mapping = {entry['model']: entry['accuracy'] for entry in entries}\n",
|
||||
" # Order the accuracies consistent with the sorted model names\n",
|
||||
" sensor_accuracies[sensor] = [mapping.get(model, 0) for model in models]\n",
|
||||
" \n",
|
||||
" return models, sensor_accuracies\n",
|
||||
"models = [rf_model, bagged_model, dt_model, knn_model, lda_model, svm_model, xgboost_model]\n",
|
||||
"model_names = [\"Random Forest\", \"Bagged Trees\", \"Decision Tree\", \"KNN\", \"LDA\", \"SVM\", \"XGBoost\"]\n",
|
||||
"\n",
|
||||
"def plot_accuracies(models, sensor_accuracies):\n",
|
||||
" bar_width = 0.35\n",
|
||||
" x = np.arange(len(models))\n",
|
||||
" sensors = list(sensor_accuracies.keys())\n",
|
||||
" \n",
|
||||
" plt.figure(figsize=(10, 6))\n",
|
||||
" # Assume two sensors for plotting grouped bars\n",
|
||||
" plt.bar(x - bar_width/2, sensor_accuracies[sensors[0]], width=bar_width, color='blue', label=sensors[0])\n",
|
||||
" plt.bar(x + bar_width/2, sensor_accuracies[sensors[1]], width=bar_width, color='orange', label=sensors[1])\n",
|
||||
" \n",
|
||||
" # Add text labels on top of bars\n",
|
||||
" for i, (a1, a2) in enumerate(zip(sensor_accuracies[sensors[0]], sensor_accuracies[sensors[1]])):\n",
|
||||
" plt.text(x[i] - bar_width/2, a1 + 0.1, f\"{a1:.2f}%\", ha='center', va='bottom', color='black')\n",
|
||||
" plt.text(x[i] + bar_width/2, a2 + 0.1, f\"{a2:.2f}%\", ha='center', va='bottom', color='black')\n",
|
||||
" \n",
|
||||
" plt.xlabel('Model Name')\n",
|
||||
" plt.ylabel('Accuracy (%)')\n",
|
||||
" plt.title('Accuracy of Classifiers for Each Sensor')\n",
|
||||
" plt.xticks(x, models)\n",
|
||||
" plt.legend()\n",
|
||||
" plt.ylim(0, 105)\n",
|
||||
" plt.tight_layout()\n",
|
||||
" plt.show()\n",
|
||||
"bar_width = 0.35 # Width of each bar\n",
|
||||
"index = np.arange(len(model_names)) # Index for the bars\n",
|
||||
"\n",
|
||||
"# Use the functions\n",
|
||||
"models, sensor_accuracies = prepare_plot_data(all_results)\n",
|
||||
"plot_accuracies(models, sensor_accuracies)\n"
|
||||
"# Plotting the bar graph\n",
|
||||
"plt.figure(figsize=(14, 8))\n",
|
||||
"\n",
|
||||
"# Bar plot for Sensor 1\n",
|
||||
"plt.bar(index, accuracies1, width=bar_width, color='blue', label='Sensor 1')\n",
|
||||
"\n",
|
||||
"# Bar plot for Sensor 2\n",
|
||||
"plt.bar(index + bar_width, accuracies2, width=bar_width, color='orange', label='Sensor 2')\n",
|
||||
"\n",
|
||||
"# Add values on top of each bar\n",
|
||||
"for i, acc1, acc2 in zip(index, accuracies1, accuracies2):\n",
|
||||
" plt.text(i, acc1 + .1, f'{acc1:.2f}%', ha='center', va='bottom', color='black')\n",
|
||||
" plt.text(i + bar_width, acc2 + 1, f'{acc2:.2f}%', ha='center', va='bottom', color='black')\n",
|
||||
"\n",
|
||||
"# Customize the plot\n",
|
||||
"plt.xlabel('Model Name →')\n",
|
||||
"plt.ylabel('Accuracy →')\n",
|
||||
"plt.title('Accuracy of classifiers for Sensors 1 and 2 with 513 features')\n",
|
||||
"plt.xticks(index + bar_width / 2, model_names) # Set x-tick positions\n",
|
||||
"plt.legend()\n",
|
||||
"plt.ylim(0, 100)\n",
|
||||
"\n",
|
||||
"# Show the plot\n",
|
||||
"plt.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -839,8 +844,6 @@
|
||||
"source": [
|
||||
"from sklearn.metrics import accuracy_score, classification_report\n",
|
||||
"# 4. Validate on Dataset B\n",
|
||||
"from joblib import load\n",
|
||||
"svm_model = load('D:/thesis/models/sensor1/SVM.joblib')\n",
|
||||
"y_pred_svm = svm_model.predict(X1b)\n",
|
||||
"\n",
|
||||
"# 5. Evaluate\n",
|
||||
@@ -848,30 +851,6 @@
|
||||
"print(classification_report(y, y_pred_svm))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Model sensor 1 to predict sensor 2 data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import accuracy_score, classification_report\n",
|
||||
"# 4. Validate on Dataset B\n",
|
||||
"from joblib import load\n",
|
||||
"svm_model = load('D:/thesis/models/sensor1/SVM.joblib')\n",
|
||||
"y_pred_svm = svm_model.predict(X2b)\n",
|
||||
"\n",
|
||||
"# 5. Evaluate\n",
|
||||
"print(\"Accuracy on Dataset B:\", accuracy_score(y, y_pred_svm))\n",
|
||||
"print(classification_report(y, y_pred_svm))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -931,7 +910,7 @@
|
||||
"# Plot\n",
|
||||
"disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)\n",
|
||||
"disp.plot(cmap=plt.cm.Blues) # You can change colormap\n",
|
||||
"plt.title(\"SVM Sensor1 CM Train w/ Dataset A Val w/ Dataset B from Sensor2 readings\")\n",
|
||||
"plt.title(\"SVM Sensor1 CM Train w/ Dataset A Val w/ Dataset B\")\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
@@ -949,14 +928,14 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 1. Predict sensor 1 on Dataset A\n",
|
||||
"y_test_pred = svm_model.predict(x_test1)\n",
|
||||
"y_train_pred = svm_model.predict(x_train1)\n",
|
||||
"\n",
|
||||
"# 2. Import confusion matrix tools\n",
|
||||
"from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"# 3. Create and plot confusion matrix\n",
|
||||
"cm_train = confusion_matrix(y_test, y_test_pred)\n",
|
||||
"cm_train = confusion_matrix(y_train, y_train_pred)\n",
|
||||
"labels = svm_model.classes_\n",
|
||||
"\n",
|
||||
"disp = ConfusionMatrixDisplay(confusion_matrix=cm_train, display_labels=labels)\n",
|
||||
|
||||
@@ -55,101 +55,3 @@ def create_ready_data(
|
||||
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:
|
||||
# Train the model
|
||||
model.fit(x_train, y_train)
|
||||
|
||||
try:
|
||||
y_pred = model.predict(x_test)
|
||||
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
|
||||
|
||||
@@ -3,7 +3,7 @@ Alur keseluruhan penelitian ini dilakukan melalui tahapan-tahapan sebagai beriku
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.3\linewidth]{chapters/img/flow.png}
|
||||
\includegraphics[width=0.3\linewidth]{chapters/id/flow.png}
|
||||
\caption{Diagram alir tahapan penelitian}
|
||||
\label{fig:flowchart}
|
||||
\end{figure}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
% % A new command that enables us to enter bi-lingual (Slovene and English) terms
|
||||
% % syntax: \addterm[options]{label}{Slovene}{Slovene first use}{English}{Slovene
|
||||
% % description}
|
||||
% \newcommand{\addterm}[6][]{
|
||||
% \newglossaryentry{#2}{
|
||||
% name={#3 (angl.\ #5)},
|
||||
% first={#4 (\emph{#5})},
|
||||
% text={#3},
|
||||
% sort={#3},
|
||||
% description={#6},
|
||||
% #1 % pass additional options to \newglossaryentry
|
||||
% }
|
||||
% }
|
||||
|
||||
% % A new command that enables us to enter (English) acronyms with bi-lingual
|
||||
% % (Slovene and English) long versions
|
||||
% % syntax: \addacronym[options]{label}{abbreviation}{Slovene long}{Slovene first
|
||||
% % use long}{English long}{Slovene description}
|
||||
% \newcommand{\addacronym}[7][]{
|
||||
% % Create the main glossary entry with \newacronym
|
||||
% % \newacronym[key-val list]{label}{abbrv}{long}
|
||||
% \newacronym[
|
||||
% name={#4 (angl.\ #6,\ #3)},
|
||||
% first={\emph{#5} (angl.\ \emph{#6},\ \emph{#3})},
|
||||
% sort={#4},
|
||||
% description={#7},
|
||||
% #1 % pass additional options to \newglossaryentry
|
||||
% ]
|
||||
% {#2}{#3}{#4}
|
||||
% % Create a cross-reference from the abbreviation to the main glossary entry by
|
||||
% % creating an auxiliary glossary entry (note: we set the label of this entry
|
||||
% % to '<original label>_auxiliary' to avoid clashes)
|
||||
% \newglossaryentry{#2_auxiliary}{
|
||||
% name={#3},
|
||||
% sort={#3},
|
||||
% description={\makefirstuc{#6}},
|
||||
% see=[See:]{#2}
|
||||
% }
|
||||
% }
|
||||
|
||||
% % Change the text of the cross-reference links to the Slovene long version.
|
||||
% \renewcommand*{\glsseeitemformat}[1]{\emph{\acrlong{#1}}.}
|
||||
|
||||
% Define the Indonesian term and link it to the English term
|
||||
\newglossaryentry{jaringansaraf}{
|
||||
name=Jaringan Saraf,
|
||||
description={The Indonesian term for \gls{nn}}
|
||||
}
|
||||
% \newglossaryentry{pemelajaranmesin}{
|
||||
% name=Pemelajaran Mesin,
|
||||
% description={Lihat \gls{machinelearning}}
|
||||
% }
|
||||
|
||||
% Define the English term and link it to its acronym
|
||||
\newglossaryentry{neuralnetwork}{
|
||||
name=Neural Network,
|
||||
description={A computational model inspired by the human brain, see \gls{nn}}
|
||||
}
|
||||
|
||||
% \newglossaryentry{machinelearning}{
|
||||
% name=Machine Learning,
|
||||
% description={A program or system that trains a model from input data. The trained model can make useful predictions from new (never-before-seen) data drawn from the same distribution as the one used to train the model.}}
|
||||
% \newglossaryentry{pemelajaranmesin}{
|
||||
% name={pemelajaran mesin (angl.\ #5)},
|
||||
% first={pemelajaran mesin (\emph{machine learning})},
|
||||
% text={pemelajaran mesin},
|
||||
% sort={ },
|
||||
% description={#6},
|
||||
% #1 % pass additional options to \newglossaryentry
|
||||
% }
|
||||
\longnewglossaryentry{machinelearning}{name={machine learning}}
|
||||
{A program or system that trains a model from input data. The trained model can make useful predictions from new (never-before-seen) data drawn from the same distribution as the one used to train the model.}
|
||||
\newterm[see={machinelearning}]{pemelajaranmesin}
|
||||
% \newglossaryentry{pemelajaran mesin}{}
|
||||
% \addterm{machinelearning}{pemelajaran mesin}{pemelajaran mesin}{machine learning}{A program or system that trains a model from input data. The trained model can make useful predictions from new (never-before-seen) data drawn from the same distribution as the one used to train the model.}
|
||||
\newacronym
|
||||
[description={statistical pattern recognition technique}]
|
||||
{svm}{SVM}{support vector machine}
|
||||
@@ -1,18 +1,14 @@
|
||||
\documentclass[draftmark]{thesis}
|
||||
|
||||
% Metadata
|
||||
\title{Prediksi Lokasi Kerusakan dengan Machine Learning}
|
||||
\author{Rifqi Damar Panuluh}
|
||||
\date{\today}
|
||||
\authorid{20210110224}
|
||||
\firstadvisor{Ir. Muhammad Ibnu Syamsi, Ph.D.}
|
||||
\secondadvisor{}
|
||||
\headdepartement{Puji Harsanto, S.T., M.T., Ph.D.}
|
||||
\headdepartementid{19740607201404123064}
|
||||
\faculty{Fakultas Teknik}
|
||||
\program{Program Studi Teknik Sipil}
|
||||
\university{Universitas Muhammadiyah Yogyakarta}
|
||||
\yearofsubmission{2025}
|
||||
% Title Information
|
||||
\setthesisinfo
|
||||
{Prediksi Lokasi Kerusakan dengan Machine Learning}
|
||||
{Rifqi Damar Panuluh}
|
||||
{20210110224}
|
||||
{PROGRAM STUDI TEKNIK SIPIL}
|
||||
{FAKULTAS TEKNIK}
|
||||
{UNIVERSITAS MUHAMMADIYAH YOGYAKARTA}
|
||||
{2025}
|
||||
|
||||
% Input preamble
|
||||
\input{preamble/packages}
|
||||
@@ -20,19 +16,22 @@
|
||||
\input{preamble/macros}
|
||||
|
||||
\begin{document}
|
||||
% \input{frontmatter/maketitle}
|
||||
% \input{frontmatter/maketitle_secondary}
|
||||
|
||||
\maketitle
|
||||
\frontmatter
|
||||
% \input{frontmatter/approval}\clearpage
|
||||
% \input{frontmatter/originality}\clearpage
|
||||
% \input{frontmatter/acknowledgement}\clearpage
|
||||
% \tableofcontents
|
||||
\input{frontmatter/approval}\clearpage
|
||||
\input{frontmatter/originality}\clearpage
|
||||
\input{frontmatter/acknowledgement}\clearpage
|
||||
\tableofcontents
|
||||
\clearpage
|
||||
\mainmatter
|
||||
\pagestyle{fancyplain}
|
||||
% Include content
|
||||
\include{content/abstract}
|
||||
\include{content/introduction}
|
||||
\include{chapters/01_introduction}
|
||||
\include{chapters/id/02_literature_review/index}
|
||||
\include{chapters/id/03_methodology/index}
|
||||
\include{content/chapter2}
|
||||
\include{content/conclusion}
|
||||
|
||||
% Bibliography
|
||||
% \bibliographystyle{IEEEtran}
|
||||
|
||||
11
latex/metadata.tex
Normal file
11
latex/metadata.tex
Normal file
@@ -0,0 +1,11 @@
|
||||
\newcommand{\studentname}{Rifqi Damar Panuluh}
|
||||
\newcommand{\studentid}{20210110224}
|
||||
\newcommand{\thesistitle}{Prediksi Lokasi Kerusakan dengan Machine Learning}
|
||||
\newcommand{\firstadvisor}{Ir. Muhammad Ibnu Syamsi, Ph.D.}
|
||||
\newcommand{\secondadvisor}{}
|
||||
\newcommand{\headdepartement}{Puji Harsanto, S.T. M.T., Ph.D.}
|
||||
\newcommand{\headdepartementid}{19740607201404123064}
|
||||
\newcommand{\faculty}{Fakultas Teknik}
|
||||
\newcommand{\program}{Teknik Sipil}
|
||||
\newcommand{\university}{Universitas Muhammadiyah Yogyakarta}
|
||||
\newcommand{\yearofsubmission}{2025}
|
||||
230
latex/thesis.cls
230
latex/thesis.cls
@@ -1,7 +1,7 @@
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesClass{thesis}[2025/05/10 Bachelor Thesis Class]
|
||||
|
||||
\newif\if@draftmark \@draftmarkfalse
|
||||
\newif\if@draftmark
|
||||
\@draftmarkfalse
|
||||
|
||||
\DeclareOption{draftmark}{\@draftmarktrue}
|
||||
@@ -12,7 +12,6 @@
|
||||
\RequirePackage{polyglossia}
|
||||
\RequirePackage{fontspec}
|
||||
\RequirePackage{titlesec}
|
||||
\RequirePackage{titling}
|
||||
\RequirePackage{fancyhdr}
|
||||
\RequirePackage{geometry}
|
||||
\RequirePackage{setspace}
|
||||
@@ -25,31 +24,30 @@
|
||||
\RequirePackage{svg} % Allows including SVG images directly
|
||||
\RequirePackage{indentfirst} % Makes first paragraph after headings indented
|
||||
\RequirePackage{float} % Provides [H] option to force figure/table placement
|
||||
\RequirePackage[style=apa, backend=biber]{biblatex}
|
||||
\RequirePackage[acronym, nogroupskip, toc]{glossaries}
|
||||
|
||||
% Polyglossia set language
|
||||
\setdefaultlanguage[variant=indonesian]{malay} % Proper Indonesian language setup
|
||||
\setotherlanguage{english} % Enables English as secondary language
|
||||
\DefineBibliographyStrings{english}{% % Customizes bibliography text
|
||||
andothers={dkk\adddot}, % Changes "et al." to "dkk."
|
||||
pages={hlm\adddot}, % Changes "pp." to "hlm."
|
||||
}
|
||||
+ \setdefaultlanguage[variant=indonesian]{malay} % Proper Indonesian language setup
|
||||
+ \setotherlanguage{english} % Enables English as secondary language
|
||||
|
||||
+ \DefineBibliographyStrings{english}{% % Customizes bibliography text
|
||||
+ andothers={dkk\adddot}, % Changes "et al." to "dkk."
|
||||
+ pages={hlm\adddot}, % Changes "pp." to "hlm."
|
||||
+ }
|
||||
|
||||
% Conditionally load the watermark package and settings
|
||||
\if@draftmark
|
||||
\RequirePackage{draftwatermark}
|
||||
\SetWatermarkText{nuluh/thesis (wip) [draft: \today]}
|
||||
\SetWatermarkText{nuluh/thesis (wip) draft: \today}
|
||||
\SetWatermarkColor[gray]{0.8} % Opacity: 0.8 = 20% transparent
|
||||
\SetWatermarkFontSize{1.5cm}
|
||||
\SetWatermarkAngle{90}
|
||||
\SetWatermarkHorCenter{1.5cm}
|
||||
\RequirePackage[left]{lineno}
|
||||
\linenumbers
|
||||
\fi
|
||||
|
||||
% Page layout
|
||||
\geometry{left=4cm, top=3cm, right=3cm, bottom=3cm}
|
||||
\geometry{left=3cm, top=3cm, right=3cm, bottom=3cm}
|
||||
\setlength{\parskip}{0.5em}
|
||||
\setlength{\parindent}{0pt}
|
||||
\onehalfspacing
|
||||
|
||||
% Fonts
|
||||
@@ -58,45 +56,19 @@
|
||||
\setsansfont{Arial}
|
||||
\setmonofont{Courier New}
|
||||
|
||||
\makeatletter
|
||||
% Extracting the Year from \today
|
||||
\newcommand{\theyear}{%
|
||||
\expandafter\@car\expandafter\@gobble\the\year\@nil
|
||||
% Metadata commands
|
||||
\input{metadata}
|
||||
|
||||
\newcommand{\setthesisinfo}[7]{%
|
||||
\renewcommand{\thesistitle}{#1}%
|
||||
\renewcommand{\studentname}{#2}%
|
||||
\renewcommand{\studentid}{#3}%
|
||||
\renewcommand{\program}{#4}%
|
||||
\renewcommand{\faculty}{#5}%
|
||||
\renewcommand{\university}{#6}%
|
||||
\renewcommand{\yearofsubmission}{#7}%
|
||||
}
|
||||
|
||||
% Declare internal macros as initially empty
|
||||
\newcommand{\@authorid}{}
|
||||
\newcommand{\@firstadvisor}{}
|
||||
\newcommand{\@secondadvisor}{}
|
||||
\newcommand{\@headdepartement}{}
|
||||
\newcommand{\@headdepartementid}{}
|
||||
\newcommand{\@faculty}{}
|
||||
\newcommand{\@program}{}
|
||||
\newcommand{\@university}{}
|
||||
\newcommand{\@yearofsubmission}{}
|
||||
|
||||
% Define user commands to set these values.
|
||||
\newcommand{\authorid}[1]{\gdef\@authorid{#1}}
|
||||
\newcommand{\firstadvisor}[1]{\gdef\@firstadvisor{#1}}
|
||||
\newcommand{\secondadvisor}[1]{\gdef\@secondadvisor{#1}}
|
||||
\newcommand{\headdepartement}[1]{\gdef\@headdepartement{#1}}
|
||||
\newcommand{\headdepartementid}[1]{\gdef\@headdepartementid{#1}}
|
||||
\newcommand{\faculty}[1]{\gdef\@faculty{#1}}
|
||||
\newcommand{\program}[1]{\gdef\@program{#1}}
|
||||
\newcommand{\university}[1]{\gdef\@university{#1}}
|
||||
\newcommand{\yearofsubmission}[1]{\gdef\@yearofsubmission{#1}}
|
||||
|
||||
% Now expose robust “the‑” getters to access the values
|
||||
\newcommand{\theauthorid}{\@authorid}
|
||||
\newcommand{\thefirstadvisor}{\@firstadvisor}
|
||||
\newcommand{\thesecondadvisor}{\@secondadvisor}
|
||||
\newcommand{\theheaddepartement}{\@headdepartement}
|
||||
\newcommand{\theheaddepartementid}{\@headdepartementid}
|
||||
\newcommand{\thefaculty}{\@faculty}
|
||||
\newcommand{\theprogram}{\@program}
|
||||
\newcommand{\theuniversity}{\@university}
|
||||
\newcommand{\theyearofsubmission}{\@yearofsubmission}
|
||||
\makeatother
|
||||
% % Header and footer
|
||||
\fancypagestyle{fancy}{%
|
||||
\fancyhf{}
|
||||
@@ -138,6 +110,11 @@
|
||||
\renewcommand{\cftchappresnum}{BAB~}
|
||||
\renewcommand{\cftchapaftersnum}{\quad}
|
||||
|
||||
% \titlespacing*{\chapter}{0pt}{-10pt}{20pt}
|
||||
|
||||
% Redefine \maketitle
|
||||
\renewcommand{\maketitle}{\input{frontmatter/maketitle}}
|
||||
|
||||
% Chapter & Section format
|
||||
\renewcommand{\cftchapfont}{\normalsize\MakeUppercase}
|
||||
% \renewcommand{\cftsecfont}{}
|
||||
@@ -159,15 +136,11 @@
|
||||
\setlength{\cftsubsecnumwidth}{2.5em}
|
||||
\setlength{\cftfignumwidth}{5em}
|
||||
\setlength{\cfttabnumwidth}{4em}
|
||||
\renewcommand \cftchapdotsep{1} % https://tex.stackexchange.com/a/273764
|
||||
\renewcommand \cftsecdotsep{1} % https://tex.stackexchange.com/a/273764
|
||||
\renewcommand \cftsubsecdotsep{1} % https://tex.stackexchange.com/a/273764
|
||||
\renewcommand \cftfigdotsep{1.5} % https://tex.stackexchange.com/a/273764
|
||||
\renewcommand \cfttabdotsep{1.5} % https://tex.stackexchange.com/a/273764
|
||||
\renewcommand \cftchapdotsep{1} % Denser dots (closer together) https://tex.stackexchange.com/a/273764
|
||||
\renewcommand \cftsecdotsep{1} % Apply to sections too
|
||||
\renewcommand \cftsubsecdotsep{1} % Apply to subsections too
|
||||
\renewcommand{\cftchapleader}{\normalfont\cftdotfill{\cftsecdotsep}}
|
||||
\renewcommand{\cftchappagefont}{\normalfont}
|
||||
|
||||
% Add Prefix in the Lof and LoT entries
|
||||
\renewcommand{\cftfigpresnum}{\figurename~}
|
||||
\renewcommand{\cfttabpresnum}{\tablename~}
|
||||
|
||||
@@ -192,147 +165,6 @@
|
||||
% \renewcommand{\cfttoctitlefont}{\bfseries\MakeUppercase}
|
||||
% \renewcommand{\cftaftertoctitle}{\vskip 2em}
|
||||
|
||||
% Defines a new glossary called “notation”
|
||||
\newglossary[nlg]{notation}{not}{ntn}{Notation}
|
||||
|
||||
% Define the header for the location column
|
||||
\providecommand*{\locationname}{Location}
|
||||
|
||||
% Define the new glossary style called 'mylistalt' for main glossaries
|
||||
\makeatletter
|
||||
\newglossarystyle{mylistalt}{%
|
||||
% start the list, initializing glossaries internals
|
||||
\renewenvironment{theglossary}%
|
||||
{\glslistinit\begin{enumerate}}%
|
||||
{\end{enumerate}}%
|
||||
% suppress all headers/groupskips
|
||||
\renewcommand*{\glossaryheader}{}%
|
||||
\renewcommand*{\glsgroupheading}[1]{}%
|
||||
\renewcommand*{\glsgroupskip}{}%
|
||||
% main entries: let \item produce "1." etc., then break
|
||||
\renewcommand*{\glossentry}[2]{%
|
||||
\item \glstarget{##1}{\glossentryname{##1}}%
|
||||
\mbox{}\\
|
||||
\glossentrydesc{##1}\space
|
||||
[##2] % appears on page x
|
||||
}%
|
||||
% sub-entries as separate paragraphs, still aligned
|
||||
\renewcommand*{\subglossentry}[3]{%
|
||||
\par
|
||||
\glssubentryitem{##2}%
|
||||
\glstarget{##2}{\strut}\space
|
||||
\glossentrydesc{##2}\space ##3%
|
||||
}%
|
||||
}
|
||||
|
||||
|
||||
% Define the new glossary style 'altlong3customheader' for notation
|
||||
\newglossarystyle{altlong3customheader}{%
|
||||
% The glossary will be a longtable environment with three columns:
|
||||
% 1. Symbol (left-aligned)
|
||||
% 2. Description (paragraph, width \glsdescwidth)
|
||||
% 3. Location (paragraph, width \glspagelistwidth)
|
||||
\renewenvironment{theglossary}%
|
||||
{\begin{longtable}{lp{\glsdescwidth}p{\glspagelistwidth}}}%
|
||||
{\end{longtable}}%
|
||||
% Define the table header row
|
||||
\renewcommand*{\symbolname}{Simbol}
|
||||
\renewcommand*{\descriptionname}{Keterangan}
|
||||
\renewcommand*{\locationname}{Halaman}
|
||||
\renewcommand*{\glossaryheader}{%
|
||||
\bfseries\symbolname & \bfseries\descriptionname & \bfseries\locationname \tabularnewline\endhead}%
|
||||
% Suppress group headings (e.g., A, B, C...)
|
||||
\renewcommand*{\glsgroupheading}[1]{}%
|
||||
% Define how a main glossary entry is displayed
|
||||
% ##1 is the entry label
|
||||
% ##2 is the location list (page numbers)
|
||||
\renewcommand{\glossentry}[2]{%
|
||||
\glsentryitem{##1}% Inserts entry number if entrycounter option is used
|
||||
\glstarget{##1}{\glossentryname{##1}} & % Column 1: Symbol (with hyperlink target)
|
||||
\glossentrydesc{##1}\glspostdescription & % Column 2: Description (with post-description punctuation)
|
||||
##2\tabularnewline % Column 3: Location list
|
||||
}%
|
||||
% Define how a sub-entry is displayed
|
||||
% ##1 is the sub-entry level (e.g., 1 for first sub-level)
|
||||
% ##2 is the entry label
|
||||
% ##3 is the location list
|
||||
\renewcommand{\subglossentry}[3]{%
|
||||
& % Column 1 (Symbol) is left blank for sub-entries to create an indented look
|
||||
\glssubentryitem{##2}% Inserts sub-entry number if subentrycounter is used
|
||||
\glstarget{##2}{\strut}\glossentrydesc{##2}\glspostdescription & % Column 2: Description (target on strut for hyperlink)
|
||||
##3\tabularnewline % Column 3: Location list
|
||||
}%
|
||||
% Define the skip between letter groups (if group headings were enabled)
|
||||
% For 3 columns, we need 2 ampersands for a full blank row if not using \multicolumn
|
||||
\ifglsnogroupskip
|
||||
\renewcommand*{\glsgroupskip}{}%
|
||||
\else
|
||||
\renewcommand*{\glsgroupskip}{& & \tabularnewline}%
|
||||
\fi
|
||||
}
|
||||
|
||||
% Define a new style 'supercol' based on 'super' for acronyms glossaries
|
||||
\newglossarystyle{supercol}{%
|
||||
\setglossarystyle{super}% inherit everything from the original
|
||||
% override just the main-entry format:
|
||||
\renewcommand*{\glossentry}[2]{%
|
||||
\glsentryitem{##1}%
|
||||
\glstarget{##1}{\glossentryname{##1}}\space % <-- added colon here
|
||||
&: \glossentrydesc{##1}\glspostdescription\space ##2\tabularnewline
|
||||
}%
|
||||
% likewise for sub‐entries, if you want a colon there too:
|
||||
\renewcommand*{\subglossentry}[3]{%
|
||||
&:
|
||||
\glssubentryitem{##2}%
|
||||
\glstarget{##2}{\strut}\glossentryname{##2}\space % <-- and here
|
||||
\glossentrydesc{##2}\glspostdescription\space ##3\tabularnewline
|
||||
}%
|
||||
}
|
||||
\makeatother
|
||||
|
||||
% A new command that enables us to enter bi-lingual (Bahasa Indonesia and English) terms
|
||||
% syntax: \addterm[options]{label}{Bahasa Indonesia}{Bahasa Indonesia first use}{English}{Bahasa Indonesia
|
||||
% description}
|
||||
\newcommand{\addterm}[6][]{
|
||||
\newglossaryentry{#2}{
|
||||
name={#3 (angl.\ #5)},
|
||||
first={#4 (\emph{#5})},
|
||||
text={#3},
|
||||
sort={#3},
|
||||
description={#6},
|
||||
#1 % pass additional options to \newglossaryentry
|
||||
}
|
||||
}
|
||||
|
||||
% A new command that enables us to enter (English) acronyms with bi-lingual
|
||||
% (Bahasa Indonesia and English) long versions
|
||||
% syntax: \addacronym[options]{label}{abbreviation}{Bahasa Indonesia long}{Bahasa Indonesia first
|
||||
% use long}{English long}{Bahasa Indonesia description}
|
||||
\newcommand{\addacronym}[7][]{
|
||||
% Create the main glossary entry with \newacronym
|
||||
% \newacronym[key-val list]{label}{abbrv}{long}
|
||||
\newacronym[
|
||||
name={#4 (angl.\ #6,\ #3)},
|
||||
first={\emph{#5} (angl.\ \emph{#6},\ \emph{#3})},
|
||||
sort={#4},
|
||||
description={#7},
|
||||
#1 % pass additional options to \newglossaryentry
|
||||
]
|
||||
{#2}{#3}{#4}
|
||||
% Create a cross-reference from the abbreviation to the main glossary entry by
|
||||
% creating an auxiliary glossary entry (note: we set the label of this entry
|
||||
% to '<original label>_auxiliary' to avoid clashes)
|
||||
\newglossaryentry{#2_auxiliary}{
|
||||
name={#3},
|
||||
sort={#3},
|
||||
description={\makefirstuc{#6}},
|
||||
see=[See:]{#2}
|
||||
}
|
||||
}
|
||||
|
||||
% Change the text of the cross-reference links to the Bahasa Indonesia long version.
|
||||
\renewcommand*{\glsseeitemformat}[1]{\emph{\acrlong{#1}}.}
|
||||
|
||||
% % Apply a custom fancyhdr layout only on the first page of each \chapter, and use no header/footer elsewhere
|
||||
% % \let\oldchapter\chapter
|
||||
% % \renewcommand{\chapter}{%
|
||||
|
||||
Reference in New Issue
Block a user