161 lines
5.1 KiB
C++
161 lines
5.1 KiB
C++
/*
|
|
* This program source code file
|
|
* is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "eseries.h"
|
|
#include <array>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
const double epsilon = 1e-12; // machine epsilon for floating-point equality testing
|
|
|
|
// First value of resistor in Ohm
|
|
// It should be first value of the decade, i.e. power of 10
|
|
// This value is only pertinent to the resistor calculator.
|
|
// It is used to reduce the computational complexity of its calculations.
|
|
// There are valid resistor values using E-series numbers below this
|
|
// value and above the below LAST_VALUE.
|
|
#define RES_EQUIV_CALC_FIRST_VALUE 10
|
|
|
|
// Last value of resistor in Ohm
|
|
// This value is only pertinent to the resistor calculator. See above.
|
|
#define RES_EQUIV_CALC_LAST_VALUE 1e6
|
|
|
|
// Struct representing resistance value together with its composition, e.g. {20.0, "10R + 10R"}
|
|
struct RESISTANCE
|
|
{
|
|
double value;
|
|
std::string name;
|
|
|
|
RESISTANCE( double aValue = 0.0, std::string aName = "" ) :
|
|
value( aValue ), name( std::move( aName ) )
|
|
{
|
|
}
|
|
};
|
|
|
|
|
|
class RES_EQUIV_CALC
|
|
/*! \brief Performs calculations on E-series values primarily to find target values
|
|
* as combinations (serial, parallel) of them.
|
|
*
|
|
* RES_EQUIV_CALC class stores and performs calcuations on E-series values. It currently
|
|
* is targeted toward the resistor calculator and hard codes some limitations
|
|
* to optimize its use in the resistor calculator.
|
|
*
|
|
* At this time these limitations are that this class handles only E-series up to
|
|
* E24 and it does not consider resistor values below 10 Ohm or above 1M Ohm.
|
|
*/
|
|
{
|
|
public:
|
|
RES_EQUIV_CALC();
|
|
|
|
enum
|
|
{
|
|
S2R,
|
|
S3R,
|
|
S4R,
|
|
NUMBER_OF_LEVELS
|
|
};
|
|
|
|
/**
|
|
* Set E-series to be used in calculations.
|
|
* Correct values are from 0 to 4 inclusive,
|
|
* representing series (consecutively) E1, E3, E6, E12, E24.
|
|
* After changing the series, NewCalc must be called before running calculations.
|
|
*/
|
|
void SetSeries( uint32_t aSeries );
|
|
|
|
/**
|
|
* Initialize next calculation, clear exclusion mask
|
|
* and erase results from previous calculation.
|
|
*
|
|
* @param aTargetValue is the value (in Ohms) to be looked for
|
|
*/
|
|
void NewCalc( double aTargetValue );
|
|
|
|
/**
|
|
* If any value of the selected E-series not available, it can be entered as an exclude value.
|
|
*
|
|
* @param aValue is the value (in Ohms) to exclude from calculation
|
|
* Values to exclude are set to true in the current exclusion mask and will not be
|
|
* considered during calculations.
|
|
*/
|
|
void Exclude( double aValue );
|
|
|
|
/**
|
|
* Executes all the calculations.
|
|
* Results are to be retrieved using GetResults (below).
|
|
*/
|
|
void Calculate();
|
|
|
|
/**
|
|
* Accessor to calculation results.
|
|
* Empty std::optional means that the exact value can be achieved using fewer resistors.
|
|
*/
|
|
const std::array<std::optional<RESISTANCE>, NUMBER_OF_LEVELS>& GetResults()
|
|
{
|
|
return m_results;
|
|
}
|
|
|
|
private:
|
|
/**
|
|
* Add values from aList to m_e_series tables.
|
|
* Covers all decades between FIRST_VALUE and LAST_VALUE.
|
|
*/
|
|
std::vector<RESISTANCE> buildSeriesData( const ESERIES::ESERIES_VALUES& aList );
|
|
|
|
/**
|
|
* Build 1R buffer, which is selected E-series table with excluded values removed.
|
|
*/
|
|
void prepare1RBuffer();
|
|
|
|
/**
|
|
* Build 2R buffer, which consists of all possible combinations of two resistors
|
|
* from 1R buffer (serial and parallel), sorted by value.
|
|
*/
|
|
void prepare2RBuffer();
|
|
|
|
/**
|
|
* Find in 2R buffer two values nearest to the given value (one smaller and one larger).
|
|
* It always returns two valid values, even for input out of range or Nan.
|
|
*/
|
|
std::pair<RESISTANCE&, RESISTANCE&> findIn2RBuffer( double aTargetValue );
|
|
|
|
/**
|
|
* Calculate the best combination consisting of exactly 2, 3 or 4 resistors.
|
|
*/
|
|
RESISTANCE calculate2RSolution();
|
|
RESISTANCE calculate3RSolution();
|
|
RESISTANCE calculate4RSolution();
|
|
|
|
private:
|
|
std::vector<std::vector<RESISTANCE>> m_e_series;
|
|
std::vector<bool> m_exclude_mask;
|
|
std::vector<RESISTANCE> m_buffer_1R;
|
|
std::vector<RESISTANCE> m_buffer_2R;
|
|
|
|
uint32_t m_series = ESERIES::E6;
|
|
double m_target = 0;
|
|
|
|
std::array<std::optional<RESISTANCE>, NUMBER_OF_LEVELS> m_results;
|
|
}; |