aramej

Trojfázové striedavé napätia a prúdy s fázorovým diagramom

Jun 25th, 2024
643
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 11.11 KB | Source Code | 0 0
  1. import React, { useState, useEffect, useRef } from 'react';
  2.  
  3. const TrojfazoveNapatiaAPrudy = () => {
  4.   const [time, setTime] = useState(0);
  5.   const [frequency, setFrequency] = useState(50);
  6.   const [speed, setSpeed] = useState(1);
  7.   const [voltageAmplitude, setVoltageAmplitude] = useState(325);
  8.   const [currentAmplitude, setCurrentAmplitude] = useState(91.92);
  9.   const [powerFactor, setPowerFactor] = useState(0.89);
  10.   const [loadType, setLoadType] = useState('R');
  11.   const [visibleWaves, setVisibleWaves] = useState({
  12.     L1: true, L2: true, L3: true,
  13.     I1: true, I2: true, I3: true
  14.   });
  15.   const [showPhasorDiagram, setShowPhasorDiagram] = useState(false);
  16.   const animationRef = useRef();
  17.  
  18.   const width = 800;
  19.   const height = 850;
  20.   const margin = { top: 20, right: 180, bottom: 50, left: 60 };
  21.   const chartWidth = width - margin.left - margin.right;
  22.   const chartHeight = (height - margin.top - margin.bottom - 250) / 2;
  23.  
  24.   const xScale = (t) => (t / 0.04) * chartWidth;
  25.   const yScaleVoltage = (v) => chartHeight / 2 - (v / (voltageAmplitude * 1.2)) * (chartHeight / 2);
  26.   const yScaleCurrent = (i) => chartHeight / 2 - (i / (currentAmplitude * 1.2)) * (chartHeight / 2);
  27.  
  28.   useEffect(() => {
  29.     const animate = () => {
  30.       setTime((prevTime) => (prevTime + 0.0005 * speed) % 0.04);
  31.       animationRef.current = requestAnimationFrame(animate);
  32.     };
  33.     animationRef.current = requestAnimationFrame(animate);
  34.     return () => cancelAnimationFrame(animationRef.current);
  35.   }, [speed]);
  36.  
  37.   const calculatePhaseShift = () => {
  38.     const phaseAngle = Math.acos(powerFactor);
  39.     switch (loadType) {
  40.       case 'R': return 0;
  41.       case 'L': return -phaseAngle;
  42.       case 'C': return phaseAngle;
  43.       default: return 0;
  44.     }
  45.   };
  46.  
  47.   const phaseShift = calculatePhaseShift();
  48.  
  49.   const generatePath = (amplitude, phase, yScale, isVoltage) => {
  50.     let path = `M ${xScale(0)} ${yScale(amplitude * Math.sin(2 * Math.PI * frequency * time + phase + (isVoltage ? 0 : phaseShift)))}`;
  51.     for (let t = 0.0001; t <= 0.04; t += 0.0001) {
  52.       const x = xScale(t);
  53.       const y = yScale(amplitude * Math.sin(2 * Math.PI * frequency * (t + time) + phase + (isVoltage ? 0 : phaseShift)));
  54.       path += ` L ${x} ${y}`;
  55.     }
  56.     return path;
  57.   };
  58.  
  59.   const phases = [
  60.     { name: 'L1', color: '#FF0000', phase: 0 },
  61.     { name: 'L2', color: '#00FF00', phase: -2 * Math.PI / 3 },
  62.     { name: 'L3', color: '#0000FF', phase: 2 * Math.PI / 3 },
  63.   ];
  64.  
  65.   const rmsVoltage = (voltageAmplitude / Math.sqrt(2)).toFixed(2);
  66.   const rmsCurrent = (currentAmplitude / Math.sqrt(2)).toFixed(2);
  67.  
  68.   const renderChart = (yScale, amplitude, title, unit, isVoltage = true) => (
  69.     <g>
  70.       <text x={chartWidth / 2} y={-10} textAnchor="middle" fontWeight="bold">{title}</text>
  71.       {/* Grid */}
  72.       {Array.from({length: 9}, (_, i) => i * chartHeight / 8).map(y => (
  73.         <line key={y} x1={0} y1={y} x2={chartWidth} y2={y} stroke="#ddd" strokeDasharray="3,3" />
  74.       ))}
  75.       {Array.from({length: 9}, (_, i) => i * chartWidth / 8).map(x => (
  76.         <line key={x} x1={x} y1={0} x2={x} y2={chartHeight} stroke="#ddd" strokeDasharray="3,3" />
  77.       ))}
  78.       {/* X-axis */}
  79.       <line x1={0} y1={chartHeight} x2={chartWidth} y2={chartHeight} stroke="black" />
  80.       {[0, 0.01, 0.02, 0.03, 0.04].map((tick) => (
  81.         <g key={tick} transform={`translate(${xScale(tick)},${chartHeight})`}>
  82.           <line y2={5} stroke="black" />
  83.           <text y={20} textAnchor="middle">{tick.toFixed(2)}</text>
  84.         </g>
  85.       ))}
  86.       {/* Y-axis */}
  87.       <line x1={0} y1={0} x2={0} y2={chartHeight} stroke="black" />
  88.       {[-amplitude, -amplitude/2, 0, amplitude/2, amplitude].map((tick) => (
  89.         <g key={tick} transform={`translate(0,${yScale(tick)})`}>
  90.           <line x2={-5} stroke="black" />
  91.           <text x={-10} dy=".32em" textAnchor="end">{tick.toFixed(0)}</text>
  92.         </g>
  93.       ))}
  94.       <text transform={`rotate(-90) translate(-${chartHeight / 2},${-margin.left + 20})`} textAnchor="middle">{unit}</text>
  95.       {/* Waveforms */}
  96.       {phases.map(({ color, phase, name }) => (
  97.         visibleWaves[isVoltage ? name : `I${name.slice(1)}`] && (
  98.           <path
  99.             key={name}
  100.             d={generatePath(amplitude, phase, yScale, isVoltage)}
  101.             fill="none"
  102.             stroke={color}
  103.             strokeWidth="2"
  104.           />
  105.         )
  106.       ))}
  107.     </g>
  108.   );
  109.  
  110.   const renderPhasorDiagram = () => {
  111.     const centerX = chartWidth / 2;
  112.     const centerY = chartHeight / 2;
  113.     const radius = Math.min(centerX, centerY) * 0.8;
  114.  
  115.     const drawPhasor = (angle, length, color, label) => {
  116.       const x = centerX + length * Math.cos(angle);
  117.       const y = centerY - length * Math.sin(angle);
  118.       return (
  119.         <g key={label}>
  120.           <line x1={centerX} y1={centerY} x2={x} y2={y} stroke={color} strokeWidth="2" />
  121.           <text x={x + 10 * Math.cos(angle)} y={y - 10 * Math.sin(angle)} fill={color}>{label}</text>
  122.         </g>
  123.       );
  124.     };
  125.  
  126.     return (
  127.       <g>
  128.         <circle cx={centerX} cy={centerY} r={radius} stroke="#ddd" fill="none" />
  129.         {phases.map(({ name, color, phase }) => (
  130.           <React.Fragment key={name}>
  131.             {drawPhasor(phase, radius, color, `U${name.slice(1)}`)}
  132.             {drawPhasor(phase + phaseShift, radius * currentAmplitude / voltageAmplitude, color, `I${name.slice(1)}`)}
  133.           </React.Fragment>
  134.         ))}
  135.       </g>
  136.     );
  137.   };
  138.  
  139.   const toggleWave = (wave) => {
  140.     setVisibleWaves(prev => ({ ...prev, [wave]: !prev[wave] }));
  141.   };
  142.  
  143.   return (
  144.     <div>
  145.       <h2 style={{ textAlign: 'center' }}>Trojfázové striedavé napätia a prúdy s fázorovým diagramom</h2>
  146.       <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', marginBottom: '10px', gap: '20px' }}>
  147.         <label>
  148.           Frekvencia (Hz):
  149.           <input
  150.             type="number"
  151.             value={frequency}
  152.             onChange={(e) => setFrequency(Number(e.target.value))}
  153.             min="1"
  154.             max="100"
  155.             step="1"
  156.           />
  157.         </label>
  158.         <div>
  159.           <label htmlFor="speedSlider">Rýchlosť animácie: {speed.toFixed(2)}x</label>
  160.           <input
  161.             id="speedSlider"
  162.             type="range"
  163.             min="0"
  164.             max="2"
  165.             step="0.01"
  166.             value={speed}
  167.             onChange={(e) => setSpeed(Number(e.target.value))}
  168.             style={{ width: '200px' }}
  169.           />
  170.         </div>
  171.         <div>
  172.           <label htmlFor="voltageSlider">Amplitúda napätia: {voltageAmplitude.toFixed(0)} V</label>
  173.           <input
  174.             id="voltageSlider"
  175.             type="range"
  176.             min="100"
  177.             max="500"
  178.             step="1"
  179.             value={voltageAmplitude}
  180.             onChange={(e) => setVoltageAmplitude(Number(e.target.value))}
  181.             style={{ width: '200px' }}
  182.           />
  183.         </div>
  184.         <div>
  185.           <label htmlFor="currentSlider">Amplitúda prúdu: {currentAmplitude.toFixed(2)} A</label>
  186.           <input
  187.             id="currentSlider"
  188.             type="range"
  189.             min="10"
  190.             max="200"
  191.             step="0.1"
  192.             value={currentAmplitude}
  193.             onChange={(e) => setCurrentAmplitude(Number(e.target.value))}
  194.             style={{ width: '200px' }}
  195.           />
  196.         </div>
  197.         <div>
  198.           <label htmlFor="powerFactorSlider">Účinník: {powerFactor.toFixed(2)}</label>
  199.           <input
  200.             id="powerFactorSlider"
  201.             type="range"
  202.             min="0"
  203.             max="1"
  204.             step="0.01"
  205.             value={powerFactor}
  206.             onChange={(e) => setPowerFactor(Number(e.target.value))}
  207.             style={{ width: '200px' }}
  208.           />
  209.         </div>
  210.         <div>
  211.           <label>Typ záťaže:</label>
  212.           <select value={loadType} onChange={(e) => setLoadType(e.target.value)}>
  213.             <option value="R">Odporová (R)</option>
  214.             <option value="L">Induktívna (L)</option>
  215.             <option value="C">Kapacitná (C)</option>
  216.           </select>
  217.         </div>
  218.         <div>
  219.           <label>
  220.             <input
  221.               type="checkbox"
  222.               checked={showPhasorDiagram}
  223.               onChange={() => setShowPhasorDiagram(!showPhasorDiagram)}
  224.             />
  225.             Zobraziť fázorový diagram
  226.           </label>
  227.         </div>
  228.       </div>
  229.       <svg width={width} height={height}>
  230.         <g transform={`translate(${margin.left},${margin.top})`}>
  231.           {showPhasorDiagram ? (
  232.             renderPhasorDiagram()
  233.           ) : (
  234.             <>
  235.               {renderChart(yScaleVoltage, voltageAmplitude, "Napätie", "Napätie (V)", true)}
  236.               <g transform={`translate(0,${chartHeight + margin.top})`}>
  237.                 {renderChart(yScaleCurrent, currentAmplitude, "Prúd", "Prúd (A)", false)}
  238.               </g>
  239.             </>
  240.           )}
  241.           {/* Legend and toggles */}
  242.           <g transform={`translate(${chartWidth + 10}, 0)`}>
  243.             {phases.map(({ name, color }, index) => (
  244.               <g key={name} transform={`translate(0, ${index * 40})`}>
  245.                 <rect width={15} height={15} fill={color} />
  246.                 <text x={20} y={12}>{name}</text>
  247.                 <foreignObject x="0" y="20" width="100" height="20">
  248.                   <label style={{ fontSize: '12px' }}>
  249.                     <input
  250.                       type="checkbox"
  251.                       checked={visibleWaves[name]}
  252.                       onChange={() => toggleWave(name)}
  253.                     />
  254.                     Zobraziť
  255.                   </label>
  256.                 </foreignObject>
  257.               </g>
  258.             ))}
  259.             {phases.map(({ name, color }, index) => (
  260.               <g key={`I${name}`} transform={`translate(0, ${(index + 3) * 40})`}>
  261.                 <rect width={15} height={15} fill={color} />
  262.                 <text x={20} y={12}>{`I${name.slice(1)}`}</text>
  263.                 <foreignObject x="0" y="20" width="100" height="20">
  264.                   <label style={{ fontSize: '12px' }}>
  265.                     <input
  266.                       type="checkbox"
  267.                       checked={visibleWaves[`I${name.slice(1)}`]}
  268.                       onChange={() => toggleWave(`I${name.slice(1)}`)}
  269.                     />
  270.                     Zobraziť
  271.                   </label>
  272.                 </foreignObject>
  273.               </g>
  274.             ))}
  275.           </g>
  276.           {/* Key values */}
  277.           <g transform={`translate(${chartWidth + 10}, ${chartHeight * 2 + margin.top * 2})`}>
  278.             <text y="20">RMS Napätie: {rmsVoltage} V</text>
  279.             <text y="40">RMS Prúd: {rmsCurrent} A</text>
  280.             <text y="60">Frekvencia: {frequency} Hz</text>
  281.             <text y="80">Typ záťaže: {loadType === 'R' ? 'Odporová' : loadType === 'L' ? 'Induktívna' : 'Kapacitná'}</text>
  282.             <text y="100">Účinník: {powerFactor.toFixed(2)}</text>
  283.             <text y="120">Fázový posun: {(phaseShift * 180 / Math.PI).toFixed(2)}°</text>
  284.           </g>
  285.         </g>
  286.       </svg>
  287.     </div>
  288.   );
  289. };
  290.  
  291. export default TrojfazoveNapatiaAPrudy;
Advertisement
Add Comment
Please, Sign In to add comment