修复: 连接空分箱间的实际功率曲线
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
|
"test": "node --test",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ import {
|
|||||||
startWindJob,
|
startWindJob,
|
||||||
uploadWindChunk,
|
uploadWindChunk,
|
||||||
} from '../utils/api';
|
} from '../utils/api';
|
||||||
import { alignDesignCurveToActualCurve, buildPowerCurveModel } from '../utils/powerCurveModel';
|
import {
|
||||||
|
alignDesignCurveToActualCurve,
|
||||||
|
buildPowerCurveModel,
|
||||||
|
getDrawableActualCurve,
|
||||||
|
} from '../utils/powerCurveModel';
|
||||||
|
|
||||||
const REQUIRED_FIELDS = [
|
const REQUIRED_FIELDS = [
|
||||||
{ key: 'time', label: '时间' },
|
{ key: 'time', label: '时间' },
|
||||||
@@ -817,15 +821,6 @@ function hexToRgba(color, opacity) {
|
|||||||
return `rgba(${(value >> 16) & 255}, ${(value >> 8) & 255}, ${value & 255}, ${alpha})`;
|
return `rgba(${(value >> 16) & 255}, ${(value >> 8) & 255}, ${value & 255}, ${alpha})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVisibleActualCurve(actualCurve) {
|
|
||||||
const sorted = [...actualCurve].sort((left, right) => left.wind_speed - right.wind_speed);
|
|
||||||
const validIndexes = sorted
|
|
||||||
.map((point, index) => (Number.isFinite(point.average_power) ? index : -1))
|
|
||||||
.filter((index) => index >= 0);
|
|
||||||
if (!validIndexes.length) return sorted;
|
|
||||||
return sorted.slice(validIndexes[0], validIndexes[validIndexes.length - 1] + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderPowerCurvePng({ actualCurve, designCurve, scatterPoints, filteredPoints, showActual, showDesign, showScatter, showFiltered, options, scales }) {
|
function renderPowerCurvePng({ actualCurve, designCurve, scatterPoints, filteredPoints, showActual, showDesign, showScatter, showFiltered, options, scales }) {
|
||||||
const width = 1800;
|
const width = 1800;
|
||||||
const height = 1160;
|
const height = 1160;
|
||||||
@@ -1247,7 +1242,7 @@ function PowerCurveChart({
|
|||||||
}), [curveScatterPoints, points, validDesign]);
|
}), [curveScatterPoints, points, validDesign]);
|
||||||
const actualCurve = curveModel.actualCurve;
|
const actualCurve = curveModel.actualCurve;
|
||||||
const visibleActualCurve = useMemo(
|
const visibleActualCurve = useMemo(
|
||||||
() => getVisibleActualCurve(actualCurve),
|
() => getDrawableActualCurve(actualCurve),
|
||||||
[actualCurve],
|
[actualCurve],
|
||||||
);
|
);
|
||||||
const visibleDesignCurve = useMemo(
|
const visibleDesignCurve = useMemo(
|
||||||
@@ -1402,7 +1397,7 @@ function PowerCurveChart({
|
|||||||
stroke: activeChartOptions.actual_color,
|
stroke: activeChartOptions.actual_color,
|
||||||
width: 0.01,
|
width: 0.01,
|
||||||
paths: uPlot.paths.spline(),
|
paths: uPlot.paths.spline(),
|
||||||
spanGaps: false,
|
spanGaps: true,
|
||||||
points: { show: false },
|
points: { show: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ export function buildActualCurveFromFixedBins(scatterPoints = [], binSize = 0.5)
|
|||||||
.sort((left, right) => left.wind_speed - right.wind_speed);
|
.sort((left, right) => left.wind_speed - right.wind_speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDrawableActualCurve(actualCurve = []) {
|
||||||
|
return actualCurve
|
||||||
|
.filter((point) => validNumber(point?.wind_speed) && validNumber(point?.average_power))
|
||||||
|
.sort((left, right) => left.wind_speed - right.wind_speed);
|
||||||
|
}
|
||||||
|
|
||||||
function interpolatePowerAtWindSpeed(designCurve, windSpeed) {
|
function interpolatePowerAtWindSpeed(designCurve, windSpeed) {
|
||||||
if (!designCurve.length || windSpeed < designCurve[0].wind_speed - EPSILON
|
if (!designCurve.length || windSpeed < designCurve[0].wind_speed - EPSILON
|
||||||
|| windSpeed > designCurve[designCurve.length - 1].wind_speed + EPSILON) {
|
|| windSpeed > designCurve[designCurve.length - 1].wind_speed + EPSILON) {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
import { buildActualCurveFromDesign, getDrawableActualCurve } from './powerCurveModel.js';
|
||||||
|
|
||||||
|
test('getDrawableActualCurve skips empty design bins and keeps adjacent valid points', () => {
|
||||||
|
const actualCurve = buildActualCurveFromDesign(
|
||||||
|
[
|
||||||
|
{ wind_speed: 19.6, active_power: 5520 },
|
||||||
|
{ wind_speed: 20.8, active_power: 5510 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ wind_speed: 19.5, design_power: 5500 },
|
||||||
|
{ wind_speed: 20, design_power: 5500 },
|
||||||
|
{ wind_speed: 20.5, design_power: 5500 },
|
||||||
|
{ wind_speed: 21, design_power: 5500 },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
getDrawableActualCurve(actualCurve).map((point) => ({
|
||||||
|
wind_speed: point.wind_speed,
|
||||||
|
average_power: point.average_power,
|
||||||
|
})),
|
||||||
|
[
|
||||||
|
{ wind_speed: 19.5, average_power: 5520 },
|
||||||
|
{ wind_speed: 21, average_power: 5510 },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user