@things-factory/spc 8.0.0 → 9.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/client/bootstrap.ts +0 -1
- package/client/index.ts +0 -0
- package/client/pages/spc-chart-page.ts +0 -336
- package/client/route.ts +0 -7
- package/client/tsconfig.json +0 -13
- package/server/controllers/data-use-case-spc.ts +0 -44
- package/server/controllers/index.ts +0 -1
- package/server/controllers/rules/cp-cpk.ts +0 -29
- package/server/controllers/spc-chart/c.ts +0 -31
- package/server/controllers/spc-chart/histogram.ts +0 -38
- package/server/controllers/spc-chart/i.ts +0 -31
- package/server/controllers/spc-chart/index.ts +0 -171
- package/server/controllers/spc-chart/mr.ts +0 -30
- package/server/controllers/spc-chart/np.ts +0 -30
- package/server/controllers/spc-chart/p.ts +0 -29
- package/server/controllers/spc-chart/pareto.ts +0 -32
- package/server/controllers/spc-chart/r.ts +0 -34
- package/server/controllers/spc-chart/u.ts +0 -31
- package/server/controllers/spc-chart/x-bar-r.ts +0 -53
- package/server/controllers/spc-chart/x-bar.ts +0 -53
- package/server/index.ts +0 -10
- package/server/service/index.ts +0 -21
- package/server/service/spc-chart/index.ts +0 -5
- package/server/service/spc-chart/spc-chart-query.ts +0 -102
- package/server/service/spc-chart/spc-chart-type.ts +0 -105
- package/server/tsconfig.json +0 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/spc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0-beta.3",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "dist-client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create ./server/migrations/migration"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@operato/dataset": "^
|
|
31
|
-
"@operato/form": "^
|
|
32
|
-
"@operato/spc": "^
|
|
33
|
-
"@things-factory/dataset": "^
|
|
34
|
-
"@things-factory/shell": "^
|
|
30
|
+
"@operato/dataset": "^9.0.0-beta",
|
|
31
|
+
"@operato/form": "^9.0.0-beta",
|
|
32
|
+
"@operato/spc": "^9.0.0-beta",
|
|
33
|
+
"@things-factory/dataset": "^9.0.0-beta.3",
|
|
34
|
+
"@things-factory/shell": "^9.0.0-beta.0"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "1d7e0dd4c88f3c3f3bd311c00e4b1d1542d53634"
|
|
37
37
|
}
|
package/client/bootstrap.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function bootstrap() {}
|
package/client/index.ts
DELETED
|
File without changes
|
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
import '@material/web/icon/icon.js'
|
|
2
|
-
|
|
3
|
-
import '@operato/app/filters-form.js'
|
|
4
|
-
import '@operato/spc/ox-chart-xbar-r.js'
|
|
5
|
-
import '@operato/spc/ox-chart-i-mr.js'
|
|
6
|
-
import '@operato/spc/ox-chart-u.js'
|
|
7
|
-
import '@operato/spc/ox-chart-c.js'
|
|
8
|
-
import '@operato/spc/ox-chart-p.js'
|
|
9
|
-
import '@operato/spc/ox-chart-np.js'
|
|
10
|
-
|
|
11
|
-
import { ScrollbarStyles, CommonHeaderStyles } from '@operato/styles'
|
|
12
|
-
import { PageView, store } from '@operato/shell'
|
|
13
|
-
import { css, html, PropertyValues, nothing } from 'lit'
|
|
14
|
-
import { customElement, property, query, state } from 'lit/decorators.js'
|
|
15
|
-
import { client } from '@operato/graphql'
|
|
16
|
-
import { i18next, localize } from '@operato/i18n'
|
|
17
|
-
import { isMobileDevice } from '@operato/utils'
|
|
18
|
-
import { FilterConfig, FilterValue, OxFiltersFormBase } from '@operato/form'
|
|
19
|
-
|
|
20
|
-
import { connect } from 'pwa-helpers/connect-mixin'
|
|
21
|
-
import gql from 'graphql-tag'
|
|
22
|
-
|
|
23
|
-
function formatDate(timestamp: number) {
|
|
24
|
-
const date = new Date(timestamp)
|
|
25
|
-
const year = date.getFullYear()
|
|
26
|
-
const month = String(date.getMonth() + 1).padStart(2, '0') // 월은 0부터 시작하므로 1을 더함
|
|
27
|
-
const day = String(date.getDate()).padStart(2, '0')
|
|
28
|
-
const hours = String(date.getHours()).padStart(2, '0')
|
|
29
|
-
const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
30
|
-
const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
31
|
-
|
|
32
|
-
return `${month}-${day} ${hours}:${minutes}`
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@customElement('spc-chart-page')
|
|
36
|
-
export class SpcChartPage extends connect(store)(localize(i18next)(PageView)) {
|
|
37
|
-
static styles = [
|
|
38
|
-
ScrollbarStyles,
|
|
39
|
-
CommonHeaderStyles,
|
|
40
|
-
css`
|
|
41
|
-
:host {
|
|
42
|
-
display: flex;
|
|
43
|
-
flex-direction: column;
|
|
44
|
-
|
|
45
|
-
width: 100%;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.chart {
|
|
49
|
-
flex: 1;
|
|
50
|
-
padding: var(--spacing-medium);
|
|
51
|
-
}
|
|
52
|
-
`
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
@state() dataSetId?: string = ''
|
|
56
|
-
@state() variable?: string = ''
|
|
57
|
-
@state() chartType?: string = ''
|
|
58
|
-
@state() spcChart: any
|
|
59
|
-
@state() filtersValue?: FilterValue[]
|
|
60
|
-
@state() variables: { display: string; value: string }[] = []
|
|
61
|
-
|
|
62
|
-
@query('ox-filters-form-base') formBase!: OxFiltersFormBase
|
|
63
|
-
|
|
64
|
-
private get filtersConfig(): FilterConfig[] {
|
|
65
|
-
return [
|
|
66
|
-
{
|
|
67
|
-
name: 'dataSetId',
|
|
68
|
-
type: 'resource-id',
|
|
69
|
-
label: 'dataset',
|
|
70
|
-
operator: 'eq',
|
|
71
|
-
options: {
|
|
72
|
-
queryName: 'dataSets'
|
|
73
|
-
},
|
|
74
|
-
onchange: (value, formBase) => {
|
|
75
|
-
requestAnimationFrame(async () => {
|
|
76
|
-
const variableFilter = formBase.getFieldByName('variable') as HTMLInputElement
|
|
77
|
-
variableFilter.value = ''
|
|
78
|
-
|
|
79
|
-
this.variables = [
|
|
80
|
-
{
|
|
81
|
-
display: '',
|
|
82
|
-
value: ''
|
|
83
|
-
},
|
|
84
|
-
...(await this.fetchVariables(value as string))
|
|
85
|
-
]
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
this.dataSetId = value
|
|
89
|
-
|
|
90
|
-
return false /* whether filters-change event triggered or not */
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
name: 'variable',
|
|
95
|
-
type: 'select',
|
|
96
|
-
label: 'variable',
|
|
97
|
-
operator: 'eq',
|
|
98
|
-
options: () => this.variables,
|
|
99
|
-
onchange: value => (this.variable = value)
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: 'chartType',
|
|
103
|
-
type: 'select',
|
|
104
|
-
label: 'chart',
|
|
105
|
-
operator: 'eq',
|
|
106
|
-
options: ['Xbar-R', 'I-MR', 'C', 'U', 'P', 'NP'],
|
|
107
|
-
onchange: value => (this.chartType = value)
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
name: 'dateRange',
|
|
111
|
-
type: 'date',
|
|
112
|
-
label: 'date',
|
|
113
|
-
operator: 'between',
|
|
114
|
-
value: [
|
|
115
|
-
{
|
|
116
|
-
name: 'today',
|
|
117
|
-
params: {
|
|
118
|
-
relativeDays: -30
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
name: 'today',
|
|
123
|
-
params: {
|
|
124
|
-
relativeDays: -1
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
]
|
|
128
|
-
}
|
|
129
|
-
]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
get context() {
|
|
133
|
-
return {
|
|
134
|
-
title: i18next.t('title.spc-chart'),
|
|
135
|
-
help: 'spc/spc-chart'
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
render() {
|
|
140
|
-
const { dataSet = {}, variable, charts = [] } = this.spcChart || {}
|
|
141
|
-
|
|
142
|
-
var plotters: { chart: string; data: any[] }[] = []
|
|
143
|
-
|
|
144
|
-
switch (this.chartType) {
|
|
145
|
-
case 'Xbar-R':
|
|
146
|
-
const xbar = charts.find(r => r.chartType == 'Xbar')
|
|
147
|
-
const r = charts.find(r => r.chartType == 'R')
|
|
148
|
-
|
|
149
|
-
plotters.push({ chart: 'xbar-r', data: xbar?.plots ?? [] })
|
|
150
|
-
break
|
|
151
|
-
|
|
152
|
-
case 'I-MR':
|
|
153
|
-
const i = charts.find(r => r.chartType == 'I')
|
|
154
|
-
const mr = charts.find(r => r.chartType == 'MR')
|
|
155
|
-
|
|
156
|
-
plotters.push({ chart: 'i-mr', data: i?.plots ?? [] })
|
|
157
|
-
break
|
|
158
|
-
|
|
159
|
-
case 'P':
|
|
160
|
-
const p = charts.find(r => r.chartType == 'P')
|
|
161
|
-
plotters.push({ chart: 'p', data: p?.plots ?? [] })
|
|
162
|
-
break
|
|
163
|
-
|
|
164
|
-
case 'NP':
|
|
165
|
-
const np = charts.find(r => r.chartType == 'NP')
|
|
166
|
-
plotters.push({ chart: 'np', data: np?.plots ?? [] })
|
|
167
|
-
break
|
|
168
|
-
|
|
169
|
-
case 'C':
|
|
170
|
-
const c = charts.find(r => r.chartType == 'C')
|
|
171
|
-
plotters.push({ chart: 'c', data: c?.plots ?? [] })
|
|
172
|
-
break
|
|
173
|
-
|
|
174
|
-
case 'U':
|
|
175
|
-
const u = charts.find(r => r.chartType == 'U')
|
|
176
|
-
plotters.push({ chart: 'u', data: u?.plots ?? [] })
|
|
177
|
-
|
|
178
|
-
default:
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
plotters = plotters.map(plotter => {
|
|
182
|
-
return {
|
|
183
|
-
...plotter,
|
|
184
|
-
data: plotter.data.map(plot => {
|
|
185
|
-
return {
|
|
186
|
-
...plot,
|
|
187
|
-
x: formatDate(Number(plot.x))
|
|
188
|
-
}
|
|
189
|
-
})
|
|
190
|
-
}
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
return html`
|
|
194
|
-
<div class="header">
|
|
195
|
-
<div class="title"><md-icon>apps</md-icon>${i18next.t('title.spc-chart')}</div>
|
|
196
|
-
<ox-filters-form-base
|
|
197
|
-
class="filters"
|
|
198
|
-
.value=${this.filtersValue}
|
|
199
|
-
.filters=${this.filtersConfig}
|
|
200
|
-
?url-params-sensitive=${false}
|
|
201
|
-
@filters-change=${(e: CustomEvent) => {
|
|
202
|
-
this.fetchSpcChart()
|
|
203
|
-
}}
|
|
204
|
-
>
|
|
205
|
-
</ox-filters-form-base>
|
|
206
|
-
</div>
|
|
207
|
-
|
|
208
|
-
${plotters.map(({ chart, data }) =>
|
|
209
|
-
chart == 'xbar-r'
|
|
210
|
-
? html` <ox-chart-xbar-r class="chart" .plots=${data}></ox-chart-xbar-r> `
|
|
211
|
-
: chart == 'i-mr'
|
|
212
|
-
? html` <ox-chart-i-mr class="chart" .plots=${data}></ox-chart-i-mr> `
|
|
213
|
-
: chart == 'u'
|
|
214
|
-
? html` <ox-chart-u class="chart" .plots=${data}></ox-chart-u> `
|
|
215
|
-
: chart == 'c'
|
|
216
|
-
? html` <ox-chart-c class="chart" .plots=${data}></ox-chart-c> `
|
|
217
|
-
: chart == 'p'
|
|
218
|
-
? html` <ox-chart-p class="chart" .plots=${data}></ox-chart-p> `
|
|
219
|
-
: chart == 'np'
|
|
220
|
-
? html` <ox-chart-np class="chart" .plots=${data}></ox-chart-np> `
|
|
221
|
-
: nothing
|
|
222
|
-
)}
|
|
223
|
-
`
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
updated(changes: PropertyValues<this>) {
|
|
227
|
-
if (!changes.has('spcChart')) {
|
|
228
|
-
this.fetchSpcChart()
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async pageUpdated(changes: any, lifecycle: any) {
|
|
233
|
-
if (this.active) {
|
|
234
|
-
this.dataSetId = lifecycle.resourceId
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
async fetchSpcChart() {
|
|
239
|
-
const {
|
|
240
|
-
dataSetId,
|
|
241
|
-
dateRange: [fromDate, toDate],
|
|
242
|
-
variable,
|
|
243
|
-
chartType
|
|
244
|
-
} = (await this.formBase.getQueryFilters()).reduce((sum, field) => {
|
|
245
|
-
sum[field.name] = field.value
|
|
246
|
-
return sum
|
|
247
|
-
}, {} as any)
|
|
248
|
-
|
|
249
|
-
if (!(dataSetId && fromDate && toDate && variable && chartType)) {
|
|
250
|
-
return
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const response = await client.query({
|
|
254
|
-
query: gql`
|
|
255
|
-
query spcChart(
|
|
256
|
-
$dataSetId: String!
|
|
257
|
-
$variable: String!
|
|
258
|
-
$chartType: String!
|
|
259
|
-
$fromDate: String!
|
|
260
|
-
$toDate: String!
|
|
261
|
-
) {
|
|
262
|
-
spcChart(
|
|
263
|
-
dataSetId: $dataSetId
|
|
264
|
-
variable: $variable
|
|
265
|
-
chartType: $chartType
|
|
266
|
-
fromDate: $fromDate
|
|
267
|
-
toDate: $toDate
|
|
268
|
-
) {
|
|
269
|
-
dataSet {
|
|
270
|
-
id
|
|
271
|
-
name
|
|
272
|
-
}
|
|
273
|
-
variable
|
|
274
|
-
charts {
|
|
275
|
-
chartType
|
|
276
|
-
controlLimits {
|
|
277
|
-
ucl
|
|
278
|
-
lcl
|
|
279
|
-
cl
|
|
280
|
-
}
|
|
281
|
-
specLimits {
|
|
282
|
-
usl
|
|
283
|
-
lsl
|
|
284
|
-
target
|
|
285
|
-
}
|
|
286
|
-
plots {
|
|
287
|
-
x
|
|
288
|
-
values
|
|
289
|
-
xbar
|
|
290
|
-
r
|
|
291
|
-
i
|
|
292
|
-
mr
|
|
293
|
-
n
|
|
294
|
-
defects
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
`,
|
|
300
|
-
variables: {
|
|
301
|
-
dataSetId,
|
|
302
|
-
variable,
|
|
303
|
-
chartType,
|
|
304
|
-
fromDate,
|
|
305
|
-
toDate
|
|
306
|
-
}
|
|
307
|
-
})
|
|
308
|
-
|
|
309
|
-
this.spcChart = response.data.spcChart
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
async fetchVariables(id: string): Promise<{ display: string; value: string }[]> {
|
|
313
|
-
const response = await client.query({
|
|
314
|
-
query: gql`
|
|
315
|
-
query dataSet($id: String!) {
|
|
316
|
-
dataSet(id: $id) {
|
|
317
|
-
dataItems {
|
|
318
|
-
name
|
|
319
|
-
tag
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
`,
|
|
324
|
-
variables: {
|
|
325
|
-
id
|
|
326
|
-
}
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
return response.data.dataSet.dataItems.map(dataItem => {
|
|
330
|
-
return {
|
|
331
|
-
display: dataItem.name,
|
|
332
|
-
value: dataItem.name
|
|
333
|
-
}
|
|
334
|
-
})
|
|
335
|
-
}
|
|
336
|
-
}
|
package/client/route.ts
DELETED
package/client/tsconfig.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig-base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"experimentalDecorators": true,
|
|
5
|
-
"skipLibCheck": true,
|
|
6
|
-
"strict": true,
|
|
7
|
-
"declaration": true,
|
|
8
|
-
"module": "esnext",
|
|
9
|
-
"outDir": "../dist-client",
|
|
10
|
-
"baseUrl": "./"
|
|
11
|
-
},
|
|
12
|
-
"include": ["./**/*"]
|
|
13
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { DataItemSpecSet, DataUseCase, EvaluationResult } from '@things-factory/dataset'
|
|
2
|
-
|
|
3
|
-
export class DataUseCaseSPC implements DataUseCase {
|
|
4
|
-
getSpecification(): DataItemSpecSet {
|
|
5
|
-
return {
|
|
6
|
-
name: 'SPC',
|
|
7
|
-
description: 'Statistical Process Control Data Spec',
|
|
8
|
-
help: '',
|
|
9
|
-
specs: [
|
|
10
|
-
{
|
|
11
|
-
type: 'spc-limits' /* 'A value which seperates acceptability from unacceptability' */,
|
|
12
|
-
label: 'control limits',
|
|
13
|
-
name: 'controlLimits'
|
|
14
|
-
}
|
|
15
|
-
]
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
evaluate(spec: any, values: any | any[]): EvaluationResult {
|
|
20
|
-
const { minimum, maximum, acceptables } = spec['controlLimits']
|
|
21
|
-
|
|
22
|
-
if (!(values instanceof Array)) {
|
|
23
|
-
values = [values]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
for (let i = 0; i < values.length; i++) {
|
|
27
|
-
const value = values[i]
|
|
28
|
-
|
|
29
|
-
if (minimum != null && value < minimum) {
|
|
30
|
-
return { oos: true, ooc: true }
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (maximum != null && value > maximum) {
|
|
34
|
-
return { oos: true, ooc: true }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (acceptables != null && !acceptables.includes(value)) {
|
|
38
|
-
return { oos: true, ooc: true }
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return { oos: false, ooc: false }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './data-use-case-spc'
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { SPCChartPlot } from '../../service/spc-chart/spc-chart-type'
|
|
2
|
-
|
|
3
|
-
interface ProcessCapabilityAnalysis {
|
|
4
|
-
cp: number
|
|
5
|
-
cpk: number
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function calculateProcessCapability(plots: SPCChartPlot[], USL: number, LSL: number): ProcessCapabilityAnalysis {
|
|
9
|
-
// 전체 평균 계산
|
|
10
|
-
const overallMean = plots.reduce((sum, plot) => sum + plot.xbar, 0) / plots.length
|
|
11
|
-
|
|
12
|
-
// 전체 표준 편차 계산
|
|
13
|
-
let allValues = plots.flatMap(plot => plot.values)
|
|
14
|
-
const meanOfAllValues = allValues.reduce((sum, value) => sum + value, 0) / allValues.length
|
|
15
|
-
const squaredDiffs = allValues.map(value => Math.pow(value - meanOfAllValues, 2))
|
|
16
|
-
const variance = squaredDiffs.reduce((sum, diff) => sum + diff, 0) / (allValues.length - 1)
|
|
17
|
-
const stdDeviation = Math.sqrt(variance)
|
|
18
|
-
|
|
19
|
-
// CP 계산
|
|
20
|
-
const cp = (USL - LSL) / (6 * stdDeviation)
|
|
21
|
-
|
|
22
|
-
// CPK 계산
|
|
23
|
-
const cpk = Math.min((USL - overallMean) / (3 * stdDeviation), (overallMean - LSL) / (3 * stdDeviation))
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
cp,
|
|
27
|
-
cpk
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { SPCChartPlot, SPCChartAnalysis } from '../../service/spc-chart/spc-chart-type'
|
|
2
|
-
|
|
3
|
-
export function calculateCChartAnalysisResult(plots: SPCChartPlot[]): SPCChartAnalysis {
|
|
4
|
-
// 각 샘플의 평균을 계산
|
|
5
|
-
plots = plots.map(plot => ({
|
|
6
|
-
...plot,
|
|
7
|
-
defects: plot.values.map(Boolean).length,
|
|
8
|
-
n: plot.values.length
|
|
9
|
-
}))
|
|
10
|
-
|
|
11
|
-
// 총 결함 수를 계산합니다.
|
|
12
|
-
const totalDefects = plots.reduce((sum, { defects }) => sum + defects, 0)
|
|
13
|
-
|
|
14
|
-
// 평균 결함 수(C-bar)를 계산합니다.
|
|
15
|
-
const cl = totalDefects / plots.length
|
|
16
|
-
|
|
17
|
-
// 상한 제어선(UCL)과 하한 제어선(LCL)을 계산합니다.
|
|
18
|
-
// 포아송 분포를 가정할 때, UCL = C-bar + 3*sqrt(C-bar), LCL = C-bar - 3*sqrt(C-bar) (단, LCL이 음수인 경우 0으로 설정)
|
|
19
|
-
const ucl = cl + 3 * Math.sqrt(cl)
|
|
20
|
-
const lcl = Math.max(cl - 3 * Math.sqrt(cl), 0)
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
chartType: 'C',
|
|
24
|
-
controlLimits: {
|
|
25
|
-
ucl,
|
|
26
|
-
lcl,
|
|
27
|
-
cl
|
|
28
|
-
},
|
|
29
|
-
plots
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
interface HistogramSample {
|
|
2
|
-
value: number
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
interface HistogramBin {
|
|
6
|
-
binRange: string // 구간을 나타내는 문자열, 예: "0-1"
|
|
7
|
-
count: number // 해당 구간에 속하는 데이터의 개수
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface HistogramResult {
|
|
11
|
-
chartType: 'Histogram'
|
|
12
|
-
bins: HistogramBin[] // 히스토그램의 각 구간과 해당 구간의 데이터 개수
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function calculateHistogram(samples: HistogramSample[], numBins: number): HistogramResult {
|
|
16
|
-
const values = samples.map(sample => sample.value)
|
|
17
|
-
const minValue = Math.min(...values)
|
|
18
|
-
const maxValue = Math.max(...values)
|
|
19
|
-
const range = maxValue - minValue
|
|
20
|
-
const binWidth = range / numBins
|
|
21
|
-
|
|
22
|
-
// 초기화된 구간 배열 생성
|
|
23
|
-
const bins: HistogramBin[] = Array.from({ length: numBins }, (_, i) => ({
|
|
24
|
-
binRange: `${(minValue + i * binWidth).toFixed(2)}-${(minValue + (i + 1) * binWidth).toFixed(2)}`,
|
|
25
|
-
count: 0
|
|
26
|
-
}))
|
|
27
|
-
|
|
28
|
-
// 각 샘플을 적절한 구간에 할당하고 개수를 세어 구간의 개수를 업데이트합니다.
|
|
29
|
-
samples.forEach(sample => {
|
|
30
|
-
const binIndex = Math.min(numBins - 1, Math.floor((sample.value - minValue) / binWidth))
|
|
31
|
-
bins[binIndex].count++
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
chartType: 'Histogram',
|
|
36
|
-
bins
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { SPCChartPlot, SPCChartAnalysis } from '../../service/spc-chart/spc-chart-type'
|
|
2
|
-
|
|
3
|
-
export function calculateIChartAnalysisResult(plots: SPCChartPlot[]): SPCChartAnalysis {
|
|
4
|
-
// 각 샘플의 평균을 계산
|
|
5
|
-
plots = plots.map((plot, index) => ({
|
|
6
|
-
...plot,
|
|
7
|
-
i: plot.values[0],
|
|
8
|
-
mr: index == 0 ? 0 : Math.abs(plot.values[0] - plots[index - 1].values[0])
|
|
9
|
-
}))
|
|
10
|
-
|
|
11
|
-
// 개별 측정값의 평균을 계산하여 중심선(cl)을 구합니다.
|
|
12
|
-
const cl = plots.reduce((acc, plot) => acc + plot.values[0], 0) / plots.length
|
|
13
|
-
|
|
14
|
-
// 개별 측정값의 표준편차를 계산합니다.
|
|
15
|
-
const standardDeviation = Math.sqrt(plots.reduce((acc, plot) => acc + Math.pow(plot.values[0] - cl, 2), 0) / plots.length)
|
|
16
|
-
|
|
17
|
-
// 공정 변동을 고려하여 상한 제어선(ucl)과 하한 제어선(lcl)을 계산합니다.
|
|
18
|
-
// 여기서는 3시그마(3 * 표준편차)를 사용합니다. 상황에 따라 적절한 시그마 수준을 조정할 수 있습니다.
|
|
19
|
-
const ucl = cl + 3 * standardDeviation
|
|
20
|
-
const lcl = cl - 3 * standardDeviation
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
chartType: 'I',
|
|
24
|
-
controlLimits: {
|
|
25
|
-
cl,
|
|
26
|
-
ucl,
|
|
27
|
-
lcl
|
|
28
|
-
},
|
|
29
|
-
plots
|
|
30
|
-
}
|
|
31
|
-
}
|