Hello

Le 2024-05-10 à 12 h 31, 张浩 a écrit :

Recently, I have encountered many doubts in the process of developing using the org.apache.sis.measure package. I found that many useful classes, such as AbstractConverter and its subclasses, as well as the UnitRegistry class, are not public. Therefore, I cannot reuse existing converters like LinearConverter class, nor can I extend based on AbstractConverter, let alone use UnitRegistry to register some special units that cannot be derived from SI units.

In principle, in should not be necessary to make those classes public for allowing custom unit definitions. However, I understand that creating a custom UnitConverter is a bit tedious, so I just made AbstractConverter public (for SIS 1.5) for reducing user's implementation effort.


For example, I now hope to implement two units representing power - dBm and dBw - and realize mutual conversion with WATT; also to achieve mutual mapping between symbols and unit instances. But after much thought, I still don't know how to use the classes under org.apache.sis.measure package to construct these two units.

With the current SIS release (1.4), the following should work, were DBWConverter is a custom converter given later:

   static final Unit<Power> dBW = Units.WATT.transform(DBWConverter.FORWARD);
   static final Unit<Power> dBm = 
Units.WATT.divide(1000).transform(DBWConverter.FORWARD);

   static final UnitFormat FORMAT = new UnitFormat(Locale.US);
   static {
        FORMAT.label(dBW, "dBW");
        FORMAT.label(dBm, "dBm");
   }

It should be all needed. Unit conversions between dBW or dBm and other units of power should work (I tried a few). For getting a unit from a symbol, or printing a unit, it would be necessary to use FORMAT.parse("dBW") and FORMAT.format(dBW) instead of Units.parse("dBW") and dBW.toString(). If the latter is anoying, it is possible to cheat as below:

   Unit<Power> dBW = Units.WATT.transform(DBWConverter.FORWARD);
   FORMAT.label(dBW, "dBW");
   dBW = FORMAT.parse("dbW");

For the upcoming SIS release (1.5), I made the task a bit easier (the call to alternate(String) will not work with SIS 1.4 because JSR-385 specification said that it should not be allowed if the unit is not an unscaled unit. For SIS 1.5, I relaxed this restriction):

   static final Unit<Power> dBW = 
Units.logarithm(Units.WATT).divide(10).alternate("dBW");

Unit converter is below (reminder: should not be needed anymore with SIS 1.5):

   class DBWConverter implements UnitConverter {
        static final DBWConverter FORWARD = new DBWConverter(false);
        static final DBWConverter INVERSE = new DBWConverter(true);

        private final boolean inverse;

        private DBWConverter(boolean inverse) {
            this.inverse = inverse;
        }

        @Override public boolean isIdentity() {return false;}
        @Override public boolean isLinear()   {return false;}

        @Override
        public UnitConverter inverse() {
            return inverse ? FORWARD : INVERSE;
        }

        @Override
        public Number convert(Number value) {
            return convert(value.doubleValue());
        }

        @Override
        public double convert(double value) {
            return inverse ? Math.log10(value)*10 : Math.pow(10, value/10);
        }

        @Override
        public UnitConverter concatenate(UnitConverter uc) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public List<? extends UnitConverter> getConversionSteps() {
            return List.of(this);
        }
   }

Martin

Reply via email to