feat: add system gain dB control to filter coefficients

This commit is contained in:
ws50529
2026-05-08 11:37:48 +08:00
parent 5568651cc3
commit 48eeb11d26
3 changed files with 34 additions and 15 deletions
+1 -1
View File
@@ -35,4 +35,4 @@ ehthumbs.db
Desktop.ini
# Agent Skills
.agent/
.agents/
+12 -6
View File
@@ -12,6 +12,7 @@ createApp({
"Bandpass (帶通)", "Notch (陷波器)", "1P1Z (一極一零)",
"2P2Z (二極二零)", "PID 控制器", "SOGI-Alpha (帶通)", "SOGI-Beta (低通)"
],
systemGainDB: 0.0,
params: {
fc: 1000.0, order: 1,
bp_f_low: 500.0, bp_f_high: 2000.0, bp_order: 1,
@@ -38,6 +39,9 @@ createApp({
}
},
computed: {
linearSystemGain() {
return Math.pow(10, this.systemGainDB / 20.0);
},
maxLogB() {
if (this.sense_b === '1%') return Math.log10(1.01);
if (this.sense_b === '2x') return Math.log10(2.0);
@@ -50,7 +54,7 @@ createApp({
},
fixedPointCoeffs() {
const scale = Math.pow(2, this.shiftBits);
const b_raw = this.parseCoeffs(this.b_str);
const b_raw = this.parseCoeffs(this.b_str).map(x => x * this.linearSystemGain);
const a_raw = this.parseCoeffs(this.a_str);
const b = b_raw.map((x, i) => ({ label: `b${i}`, val: Math.round(x * scale) }));
@@ -59,8 +63,8 @@ createApp({
return { b, a };
},
floatingCoeffs() {
const b = this.parseCoeffs(this.b_str).map((x, i) => ({ label: `b${i}`, val: x }));
const a = this.parseCoeffs(this.a_str).map((x, i) => ({ label: `a${i}`, val: x }));
const b = this.parseCoeffs(this.b_str).map((x, i) => ({ label: `b${i}`, val: parseFloat((x * this.linearSystemGain).toPrecision(6)) }));
const a = this.parseCoeffs(this.a_str).map((x, i) => ({ label: `a${i}`, val: parseFloat(x.toPrecision(6)) }));
return { b, a };
}
},
@@ -185,7 +189,7 @@ createApp({
this.loadingBode = true;
this.globalError = null;
try {
let b = this.parseCoeffs(this.b_str);
let b = this.parseCoeffs(this.b_str).map(val => val * this.linearSystemGain);
let a = this.parseCoeffs(this.a_str);
if (b.length === 0) b = [1.0];
if (a.length === 0) a = [1.0];
@@ -334,8 +338,9 @@ createApp({
this.loadingFilter = true;
this.globalError = null;
const formData = new FormData();
const final_b_str = this.parseCoeffs(this.b_str).map(val => val * this.linearSystemGain).join(', ');
formData.append('file', this.csvFile);
formData.append('b', this.b_str);
formData.append('b', final_b_str);
formData.append('a', this.a_str);
formData.append('col_idx', this.selectedColumn);
try {
@@ -373,8 +378,9 @@ createApp({
async downloadCsv() {
if (!this.csvFile) return;
const formData = new FormData();
const final_b_str = this.parseCoeffs(this.b_str).map(val => val * this.linearSystemGain).join(', ');
formData.append('file', this.csvFile);
formData.append('b', this.b_str);
formData.append('b', final_b_str);
formData.append('a', this.a_str);
formData.append('col_idx', this.selectedColumn);
try {
+21 -8
View File
@@ -15,6 +15,7 @@
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>
<link rel="stylesheet" href="style.css">
<link rel="icon" type="image/png" href="logo.png">
</head>
<body class="bg-slate-50 dark:bg-darker text-slate-900 dark:text-gray-200 min-h-screen transition-colors duration-300">
@@ -22,9 +23,12 @@
<!-- 頂部導覽列 -->
<header
class="bg-white dark:bg-dark border-b border-slate-200 dark:border-gray-800 p-4 shadow-md flex justify-between items-center z-10">
<h1
class="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-emerald-600 dark:from-blue-400 dark:to-emerald-400">
差分方程式分析 (Difference Equation Analyzer)</h1>
<div class="flex items-center gap-3">
<img src="logo.png" alt="Logo" class="h-10 w-10 object-contain rounded-lg shadow-sm">
<h1
class="text-xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-emerald-600 dark:from-blue-400 dark:to-emerald-400">
差分方程式分析 (Difference Equation Analyzer)</h1>
</div>
<div class="flex items-center gap-4">
<!-- 模式切換按鈕 -->
<button @click="toggleDarkMode"
@@ -221,11 +225,20 @@
<section>
<h2 class="text-sm font-semibold text-slate-500 dark:text-gray-400 uppercase tracking-wider mb-3">
系統參數</h2>
<label class="text-sm text-slate-500 dark:text-gray-400 flex justify-between mb-1"><span>取樣頻率 fs
(Hz)</span><span class="text-emerald-600 dark:text-emerald-400">{{ formatK(fs)
}}</span></label>
<input type="number" v-model.number="fs" @change="onFsChange"
class="w-full bg-white dark:bg-gray-800 border border-slate-200 dark:border-gray-700 rounded-lg p-3 text-base focus:border-blue-500 outline-none transition-all text-slate-900 dark:text-gray-100">
<div class="space-y-3">
<div>
<label class="text-sm text-slate-500 dark:text-gray-400 flex justify-between mb-1"><span>取樣頻率 fs
(Hz)</span><span class="text-emerald-600 dark:text-emerald-400">{{ formatK(fs)
}}</span></label>
<input type="number" v-model.number="fs" @change="onFsChange"
class="w-full bg-white dark:bg-gray-800 border border-slate-200 dark:border-gray-700 rounded-lg p-3 text-base focus:border-blue-500 outline-none transition-all text-slate-900 dark:text-gray-100">
</div>
<div>
<label class="text-sm text-slate-500 dark:text-gray-400 flex justify-between mb-1"><span>系統整體增益 (System Gain)</span><span class="text-blue-600 dark:text-blue-400">{{ systemGainDB }} dB (線性倍率: {{ linearSystemGain.toFixed(4) }}x)</span></label>
<input type="number" v-model.number="systemGainDB" @change="updateBodePlot(); if(filterDone) processFilter();" step="1"
class="w-full bg-white dark:bg-gray-800 border border-slate-200 dark:border-gray-700 rounded-lg p-3 text-base focus:border-blue-500 outline-none transition-all text-slate-900 dark:text-gray-100">
</div>
</div>
</section>
<hr class="border-slate-200 dark:border-gray-800">