예제 #1
0
파일: IC.py 프로젝트: rlcjj/QuantStudio
class ICDecay(BaseModule):
    """IC 衰减"""
    #TestFactor = Enum(None, arg_type="SingleOption", label="测试因子", order=0)
    FactorOrder = Enum("降序",
                       "升序",
                       arg_type="SingleOption",
                       label="排序方向",
                       order=1)
    #PriceFactor = Enum(None, arg_type="SingleOption", label="价格因子", order=2)
    #IndustryFactor = Enum("无", arg_type="SingleOption", label="行业因子", order=3)
    #WeightFactor = Enum("等权", arg_type="SingleOption", label="权重因子", order=4)
    CalcDTs = List(dt.datetime, arg_type="DateList", label="计算时点", order=5)
    LookBack = ListInt(np.arange(1, 13).tolist(),
                       arg_type="NultiOpotion",
                       label="回溯期数",
                       order=6)
    CorrMethod = Enum("spearman",
                      "pearson",
                      "kendall",
                      arg_type="SingleOption",
                      label="相关性算法",
                      order=7)
    IDFilter = Str(arg_type="IDFilter", label="筛选条件", order=8)

    def __init__(self, factor_table, name="IC 衰减", sys_args={}, **kwargs):
        self._FactorTable = factor_table
        super().__init__(name=name, sys_args=sys_args, **kwargs)

    def __QS_initArgs__(self):
        DefaultNumFactorList, DefaultStrFactorList = getFactorList(
            dict(self._FactorTable.getFactorMetaData(key="DataType")))
        self.add_trait(
            "TestFactor",
            Enum(*DefaultNumFactorList,
                 arg_type="SingleOption",
                 label="测试因子",
                 order=0))
        self.add_trait(
            "PriceFactor",
            Enum(*DefaultNumFactorList,
                 arg_type="SingleOption",
                 label="价格因子",
                 order=2))
        self.PriceFactor = searchNameInStrList(DefaultNumFactorList,
                                               ['价', 'Price', 'price'])
        self.add_trait(
            "IndustryFactor",
            Enum(*(["无"] + DefaultStrFactorList),
                 arg_type="SingleOption",
                 label="行业因子",
                 order=3))
        self.add_trait(
            "WeightFactor",
            Enum(*(["等权"] + DefaultNumFactorList),
                 arg_type="SingleOption",
                 label="权重因子",
                 order=4))

    def __QS_start__(self, mdl, dts, **kwargs):
        if self._isStarted: return ()
        super().__QS_start__(mdl=mdl, dts=dts, **kwargs)
        self._Output = {"IC": [[] for i in self.LookBack]}
        self._Output["时点"] = []
        self._CurCalcInd = 0
        return (self._FactorTable, )

    def __QS_move__(self, idt, **kwargs):
        if self._iDT == idt: return 0
        if self.CalcDTs:
            if idt not in self.CalcDTs[self._CurCalcInd:]: return 0
            self._CurCalcInd = self.CalcDTs[self._CurCalcInd:].index(
                idt) + self._CurCalcInd
            LastInd = self._CurCalcInd - 1
            LastDateTime = self.CalcDTs[LastInd]
        else:
            self._CurCalcInd = self._Model.DateTimeIndex
            LastInd = self._CurCalcInd - 1
            LastDateTime = self._Model.DateTimeSeries[LastInd]
        if (LastInd < 0):
            for i, iRollBack in enumerate(self.LookBack):
                self._Output["IC"][i].append(np.nan)
            self._Output["时点"].append(idt)
            return 0
        Price = self._FactorTable.readData(
            dts=[LastDateTime, idt],
            ids=self._FactorTable.getID(ifactor_name=self.PriceFactor),
            factor_names=[self.PriceFactor]).iloc[0]
        Ret = Price.iloc[1] / Price.iloc[0] - 1
        for i, iRollBack in enumerate(self.LookBack):
            iPreInd = self._CurCalcInd - iRollBack
            if iPreInd < 0:
                self._Output["IC"][i].append(np.nan)
                continue
            iPreDT = self.CalcDTs[iPreInd]
            iPreIDs = self._FactorTable.getFilteredID(
                idt=iPreDT, id_filter_str=self.IDFilter)
            iRet = Ret.loc[iPreIDs].copy()
            if self.IndustryFactor != "无":
                IndustryData = self._FactorTable.readData(
                    dts=[iPreDT],
                    ids=iPreIDs,
                    factor_names=[self.IndustryFactor]).iloc[0, 0, :]
                AllIndustry = IndustryData.unique()
                # 进行收益率的行业调整
                if self.WeightFactor == "等权":
                    for iIndustry in AllIndustry:
                        iRet[IndustryData == iIndustry] -= iRet[
                            IndustryData == iIndustry].mean()
                else:
                    WeightData = self._FactorTable.readData(
                        dts=[iPreDT],
                        ids=iPreIDs,
                        factor_names=[self.WeightFactor]).iloc[0, 0, :]
                    for iIndustry in AllIndustry:
                        iWeight = WeightData[IndustryData == iIndustry]
                        iiRet = iRet[IndustryData == iIndustry]
                        iRet[IndustryData == iIndustry] -= (
                            iiRet * iWeight).sum() / iWeight[pd.notnull(
                                iWeight) & pd.notnull(iiRet)].sum(skipna=False)
            iFactorExpose = self._FactorTable.readData(dts=[iPreDT],
                                                       ids=iPreIDs,
                                                       factor_names=[
                                                           self.TestFactor
                                                       ]).iloc[0, 0, :]
            self._Output["IC"][i].append(
                iFactorExpose.corr(iRet, method=self.CorrMethod))
        self._Output["时点"].append(idt)
        return 0

    def __QS_end__(self):
        if not self._isStarted: return 0
        self._Output["IC"] = pd.DataFrame(np.array(self._Output["IC"]).T,
                                          index=self._Output.pop("时点"),
                                          columns=list(self.LookBack))
        if self.FactorOrder == "升序": self._Output["IC"] = -self._Output["IC"]
        self._Output["统计数据"] = pd.DataFrame(index=self._Output["IC"].columns)
        self._Output["统计数据"]["IC平均值"] = self._Output["IC"].mean()
        nDT = pd.notnull(self._Output["IC"]).sum()
        self._Output["统计数据"]["标准差"] = self._Output["IC"].std()
        self._Output["统计数据"]["IC_IR"] = self._Output["统计数据"][
            "IC平均值"] / self._Output["统计数据"]["标准差"]
        self._Output["统计数据"]["t统计量"] = self._Output["统计数据"]["IC_IR"] * nDT**0.5
        self._Output["统计数据"]["胜率"] = (self._Output["IC"] > 0).sum() / nDT
        return 0

    def genMatplotlibFig(self, file_path=None):
        Fig, Axes = plt.subplots(figsize=(16, 8))
        xData = np.arange(0, self._Output["统计数据"].shape[0])
        xTickLabels = [str(i) for i in self._Output["统计数据"].index]
        yMajorFormatter = FuncFormatter(_QS_formatMatplotlibPercentage)
        Axes.yaxis.set_major_formatter(yMajorFormatter)
        Axes.bar(xData,
                 self._Output["统计数据"]["IC平均值"].values,
                 label="IC",
                 color="b")
        Axes.set_xticks(xData)
        Axes.set_xticklabels(xTickLabels)
        Axes.legend(loc='upper left')
        RAxes = Axes.twinx()
        RAxes.yaxis.set_major_formatter(yMajorFormatter)
        RAxes.plot(xData,
                   self._Output["统计数据"]["胜率"].values,
                   label="胜率",
                   color="r",
                   alpha=0.6,
                   lw=3)
        RAxes.legend(loc="upper right")
        plt.setp(Axes.get_xticklabels(), visible=True, rotation=0, ha='center')
        if file_path is not None:
            Fig.savefig(file_path, dpi=150, bbox_inches='tight')
        return Fig

    def _repr_html_(self):
        if len(self.ArgNames) > 0:
            HTML = "参数设置: "
            HTML += '<ul align="left">'
            for iArgName in self.ArgNames:
                if iArgName != "计算时点":
                    HTML += "<li>" + iArgName + ": " + str(
                        self.Args[iArgName]) + "</li>"
                elif self.Args[iArgName]:
                    HTML += "<li>" + iArgName + ": 自定义时点</li>"
                else:
                    HTML += "<li>" + iArgName + ": 所有时点</li>"
            HTML += "</ul>"
        else:
            HTML = ""
        Formatters = [_QS_formatPandasPercentage] * 2 + [
            lambda x: '{0:.4f}'.format(x), lambda x: '{0:.2f}'.format(x),
            _QS_formatPandasPercentage
        ]
        iHTML = self._Output["统计数据"].to_html(formatters=Formatters)
        Pos = iHTML.find(">")
        HTML += iHTML[:Pos] + ' align="center"' + iHTML[Pos:]
        Fig = self.genMatplotlibFig()
        # figure 保存为二进制文件
        Buffer = BytesIO()
        plt.savefig(Buffer, bbox_inches='tight')
        PlotData = Buffer.getvalue()
        # 图像数据转化为 HTML 格式
        ImgStr = "data:image/png;base64," + base64.b64encode(PlotData).decode()
        HTML += ('<img src="%s">' % ImgStr)
        return HTML
예제 #2
0
class BiasTest(BaseModule):
    """BiasTest"""
    RiskTable = Instance(RiskTable, arg_type="RiskTable", label="风险表", order=0)
    CalcDTs = List(dt.datetime, arg_type="DateList", label="计算时点", order=1)
    IDFilter = Str(arg_type="IDFilter", label="筛选条件", order=2)
    #PriceFactor = Enum(None, arg_type="SingleOption", label="价格因子", order=3)
    #WeightFactors = ListStr(arg_type="MultiOption", label="权重因子", order=4 option_range=())
    #StyleFactors = ListStr(arg_type="MultiOption", label="风格因子", order=5, option_range=())
    #IndustryFactor = Enum("无", arg_type="SingleOption", label="行业因子", order=6)
    #IndustryNeutralFactors = ListStr(arg_type="MultiOption", label="行业中性因子", order=7, option_range=())
    RandomNums = ListInt([20, 50, 100, 200],
                         arg_type="NultiOpotion",
                         label="随机组合",
                         order=8)
    LookBack = Int(12, arg_type="Integer", label="回溯期数", order=9)

    def __init__(self, factor_table, name="BiasTest", sys_args={}, **kwargs):
        self._FactorTable = factor_table
        super().__init__(name=name, sys_args=sys_args, **kwargs)

    def __QS_initArgs__(self):
        DefaultNumFactorList, DefaultStrFactorList = getFactorList(
            dict(self._FactorTable.getFactorMetaData(key="DataType")))
        self.add_trait(
            "PriceFactor",
            Enum(*DefaultNumFactorList,
                 arg_type="SingleOption",
                 label="价格因子",
                 order=3))
        self.PriceFactor = searchNameInStrList(DefaultNumFactorList,
                                               ['价', 'Price', 'price'])
        self.add_trait(
            "WeightFactors",
            ListStr(["等权"],
                    arg_type="MultiOption",
                    label="权重因子",
                    order=4,
                    option_range=tuple(["等权"] + DefaultNumFactorList)))
        self.add_trait(
            "StyleFactors",
            ListStr(arg_type="MultiOption",
                    label="风格因子",
                    order=5,
                    option_range=tuple(DefaultNumFactorList)))
        self.add_trait(
            "IndustryFactor",
            Enum(*(["无"] + DefaultStrFactorList),
                 arg_type="SingleOption",
                 label="行业因子",
                 order=6))
        self.add_trait(
            "IndustryNeutralFactors",
            ListStr(arg_type="MultiOption",
                    label="行业中性因子",
                    order=7,
                    option_range=tuple(DefaultNumFactorList)))

    def __QS_start__(self, mdl, dts, **kwargs):
        if self._isStarted: return ()
        super().__QS_start__(mdl=mdl, dts=dts, **kwargs)
        self._WeightFactors = list(self.WeightFactors)
        self._HasEW = ("等权" in self._WeightFactors)
        if self._HasEW: self._WeightFactors.remove("等权")
        self._Output = {}
        self._CurCalcInd = 0
        self._Portfolios = OrderedDict()
        self._CovMatrix = None
        return (self._FactorTable, )

    def _genPortfolio(self, idt, ids):
        PortfolioDict = OrderedDict()
        if self._WeightFactors:
            WeightData = self._FactorTable.readData(
                factor_names=self._WeightFactors, dts=[idt], ids=ids).iloc[:,
                                                                           0]
        else:
            WeightData = pd.DataFrame()
        if self._HasEW:
            WeightData["等权"] = pd.Series(1, index=ids) / len(ids)
        if self.IndustryFactor != "无":
            Industry = self._FactorTable.readData(
                factor_names=[self.IndustryFactor], dts=[idt], ids=ids).iloc[0,
                                                                             0]
            AllIndustries = Industry[pd.notnull(Industry)].unique()
            AllIndustries.sort()
        if self.StyleFactors:
            StyleFactorData = self._FactorTable.readData(factor_names=list(
                self.StyleFactors),
                                                         dts=[idt],
                                                         ids=ids).iloc[:, 0]
        if self.IndustryNeutralFactors:
            IndNeutralData = self._FactorTable.readData(factor_names=list(
                self.IndustryNeutralFactors),
                                                        dts=[idt],
                                                        ids=ids).iloc[:, 0]
        for iWeightFactor in WeightData:
            iWeightData = WeightData[iWeightFactor]
            iMask = (pd.notnull(iWeightData) & (iWeightData != 0))
            iWeightData = iWeightData[iMask]
            # 全部 ID 组合
            PortfolioDict[
                "全体%s加权组合" %
                (iWeightFactor, )] = iWeightData / iWeightData.abs().sum()
            # 行业组合
            if self.IndustryFactor != "无":
                for jIndustry in AllIndustries:
                    ijMask = (Industry[iMask] == jIndustry)
                    ijWeightData = iWeightData[ijMask]
                    PortfolioDict[
                        "%s行业%s加权组合" %
                        (jIndustry, iWeightFactor
                         )] = ijWeightData / ijWeightData.abs().sum()
                    # 行业中性组合
                    for kFactor in self.IndustryNeutralFactors:
                        kTopPortfolio = ("%sTop%s加权组合" %
                                         (kFactor, iWeightFactor))
                        kBottomPortfolio = ("%sBottom%s加权组合" %
                                            (kFactor, iWeightFactor))
                        ijkIndNeutralData = IndNeutralData[kFactor][iMask][
                            ijMask]
                        ijkThreshold = ijkIndNeutralData.median()
                        PortfolioDict[kTopPortfolio] = PortfolioDict.get(
                            kTopPortfolio, []) + ijkIndNeutralData[
                                ijkIndNeutralData > ijkThreshold].index.tolist(
                                )
                        PortfolioDict[kBottomPortfolio] = PortfolioDict.get(
                            kBottomPortfolio, []
                        ) + ijkIndNeutralData[
                            ijkIndNeutralData <= ijkThreshold].index.tolist()
                for kFactor in self.IndustryNeutralFactors:
                    kTopPortfolio = ("%sTop%s加权组合" % (kFactor, iWeightFactor))
                    kPortfolio = iWeightData.loc[PortfolioDict.pop(
                        kTopPortfolio)]
                    PortfolioDict[kTopPortfolio] = kPortfolio / kPortfolio.abs(
                    ).sum()
                    kBottomPortfolio = ("%sBottom%s加权组合" %
                                        (kFactor, iWeightFactor))
                    kPortfolio = iWeightData.loc[PortfolioDict.pop(
                        kBottomPortfolio)]
                    PortfolioDict[
                        kBottomPortfolio] = kPortfolio / kPortfolio.abs().sum(
                        )
            # 风格因子组合
            for jFactor in self.StyleFactors:
                jFactorData = StyleFactorData[jFactor][iMask]
                ijWeightData = iWeightData[
                    jFactorData >= jFactorData.quantile(0.8)]
                PortfolioDict["%s风格Top%s加权组合" %
                              (jFactor, iWeightFactor
                               )] = ijWeightData / ijWeightData.abs().sum()
                ijWeightData = iWeightData[
                    jFactorData <= jFactorData.quantile(0.2)]
                PortfolioDict["%s风格Bottom%s加权组合" %
                              (jFactor, iWeightFactor
                               )] = ijWeightData / ijWeightData.abs().sum()
            # 随机组合
            for jNum in self.RandomNums:
                PortfolioDict["随机%d%s加权组合" %
                              (jNum, iWeightFactor)] = genRandomPortfolio(
                                  ids, target_num=20, weight=iWeightData)
        return PortfolioDict

    def __QS_move__(self, idt, **kwargs):
        if self._iDT == idt: return 0
        self._iDT = idt
        if self.CalcDTs:
            if idt not in self.CalcDTs[self._CurCalcInd:]: return 0
            self._CurCalcInd = self.CalcDTs[self._CurCalcInd:].index(
                idt) + self._CurCalcInd
            LastInd = self._CurCalcInd - 1
            LastDateTime = self.CalcDTs[LastInd]
        else:
            self._CurCalcInd = self._Model.DateTimeIndex
            LastInd = self._CurCalcInd - 1
            LastDateTime = self._Model.DateTimeSeries[LastInd]
        if (LastInd < 0): return 0
        IDs = self._FactorTable.getFilteredID(idt=idt,
                                              id_filter_str=self.IDFilter)
        LastCovMatrix, self._CovMatrix = self._CovMatrix, dropRiskMatrixNA(
            self.RiskTable.readCov(dts=[idt], ids=IDs).iloc[0])
        IDs = self._CovMatrix.index.tolist()
        LastPortfolios, self._Portfolios = self._Portfolios, self._genPortfolio(
            idt, IDs)
        if not LastPortfolios:
            AllPortfolioNames = list(self._Portfolios)
            self._Output["Z-Score"] = pd.DataFrame(columns=AllPortfolioNames)
            self._Output["Robust Z-Score"] = pd.DataFrame(
                columns=AllPortfolioNames)
            self._Output["Bias 统计量"] = pd.DataFrame(columns=AllPortfolioNames)
            self._Output["Robust Bias 统计量"] = pd.DataFrame(
                columns=AllPortfolioNames)
            return 0
        else:
            self._Output["Robust Bias 统计量"].loc[idt] = self._Output[
                "Bias 统计量"].loc[idt] = self._Output["Robust Z-Score"].loc[
                    idt] = self._Output["Z-Score"].loc[idt] = np.nan
        Price = self._FactorTable.readData(
            dts=[LastDateTime, idt],
            ids=self._FactorTable.getID(ifactor_name=self.PriceFactor),
            factor_names=[self.PriceFactor]).iloc[0]
        Return = Price.iloc[1] / Price.iloc[0] - 1
        for jPortfolioName, jPortfolio in LastPortfolios.items():
            jCovMatrix = LastCovMatrix.loc[jPortfolio.index, jPortfolio.index]
            jStd = np.dot(np.dot(jPortfolio.values, jCovMatrix.values),
                          jPortfolio.values)**0.5
            jReturn = (Return[jPortfolio.index] * jPortfolio).sum()
            self._Output["Z-Score"].loc[idt, jPortfolioName] = jReturn / jStd
            self._Output["Robust Z-Score"].loc[idt, jPortfolioName] = max(
                (-3, min((3, jReturn / jStd))))
            if self._Output["Z-Score"].shape[0] >= self.LookBack:
                self._Output["Bias 统计量"].loc[
                    idt, jPortfolioName] = self._Output["Z-Score"][
                        jPortfolioName].iloc[-self.LookBack:].std()
                self._Output["Robust Bias 统计量"].loc[
                    idt, jPortfolioName] = self._Output["Robust Z-Score"][
                        jPortfolioName].iloc[-self.LookBack:].std()
        AllPortfolioNames = list(LastPortfolios)
        self._Output["Z-Score"] = self._Output[
            "Z-Score"].loc[:, AllPortfolioNames]
        self._Output["Robust Z-Score"] = self._Output[
            "Robust Z-Score"].loc[:, AllPortfolioNames]
        self._Output["Bias 统计量"] = self._Output[
            "Bias 统计量"].loc[:, AllPortfolioNames]
        self._Output["Robust Bias 统计量"] = self._Output[
            "Robust Bias 统计量"].loc[:, AllPortfolioNames]
        return 0

    def __QS_end__(self):
        if not self._isStarted: return 0
        self._Output["汇总统计量"] = pd.DataFrame(
            index=self._Output["Bias 统计量"].columns)
        self._Output["汇总统计量"]["RAD 统计量"] = (self._Output["Bias 统计量"] -
                                            1).abs().mean()
        self._Output["汇总统计量"]["Robust RAD 统计量"] = (
            self._Output["Robust Bias 统计量"] - 1).abs().mean()
        self._Output["Bias 统计量"].insert(0, "95%置信下界",
                                        1 - (2 / self.LookBack)**0.5)
        self._Output["Bias 统计量"].insert(0, "95%置信上界",
                                        1 + (2 / self.LookBack)**0.5)
        self._Output["Robust Bias 统计量"].insert(0, "95%置信下界",
                                               1 - (2 / self.LookBack)**0.5)
        self._Output["Robust Bias 统计量"].insert(0, "95%置信上界",
                                               1 + (2 / self.LookBack)**0.5)
        Stats = self._Output["Bias 统计量"].iloc[:, 2:]
        SampleNum = pd.notnull(Stats).sum(axis=0)
        self._Output["汇总统计量"]["Bias 统计量高估比例"] = (
            Stats.T < self._Output["Bias 统计量"]["95%置信下界"]).sum(
                axis=1) / SampleNum
        self._Output["汇总统计量"]["Bias 统计量低估比例"] = (
            Stats.T > self._Output["Bias 统计量"]["95%置信上界"]).sum(
                axis=1) / SampleNum
        self._Output["汇总统计量"]["Bias 统计量准确度"] = 1 - self._Output["汇总统计量"][
            "Bias 统计量高估比例"] - self._Output["汇总统计量"]["Bias 统计量低估比例"]
        Stats = self._Output["Robust Bias 统计量"].iloc[:, 2:]
        SampleNum = pd.notnull(Stats).sum(axis=0)
        self._Output["汇总统计量"]["Robust Bias 统计量高估比例"] = (
            Stats.T < self._Output["Robust Bias 统计量"]["95%置信下界"]).sum(
                axis=1) / SampleNum
        self._Output["汇总统计量"]["Robust Bias 统计量低估比例"] = (
            Stats.T > self._Output["Robust Bias 统计量"]["95%置信上界"]).sum(
                axis=1) / SampleNum
        self._Output["汇总统计量"]["Robust Bias 统计量准确度"] = 1 - self._Output[
            "汇总统计量"]["Robust Bias 统计量高估比例"] - self._Output["汇总统计量"][
                "Robust Bias 统计量低估比例"]
        return 0
예제 #3
0
class Test(HasTraits):
    var = ListInt()
예제 #4
0
class MicGeom(HasPrivateTraits):
    """
    Provides the geometric arrangement of microphones in the array.
    
    The geometric arrangement of microphones is read in from an 
    xml-source with element tag names `pos` and attributes Name, `x`, `y` and `z`. 
    Can also be used with programmatically generated arrangements.
    """

    #: Name of the .xml-file from wich to read the data.
    from_file = File(filter=['*.xml'], desc="name of the xml file to import")

    #: Basename of the .xml-file, without the extension; is set automatically / readonly.
    basename = Property(depends_on='from_file', desc="basename of xml file")

    #: List that gives the indices of channels that should not be considered.
    #: Defaults to a blank list.
    invalid_channels = ListInt(desc="list of invalid channels")

    #: Number of microphones in the array; readonly.
    num_mics = Property(depends_on=[
        'mpos',
    ],
                        desc="number of microphones in the geometry")

    #: Center of the array (arithmetic mean of all used array positions); readonly.
    center = Property(depends_on=[
        'mpos',
    ], desc="array center")

    #: Positions as (3, :attr:`num_mics`) array of floats, may include also invalid
    #: microphones (if any). Set either automatically on change of the
    #: :attr:`from_file` argument or explicitely by assigning an array of floats.
    mpos_tot = CArray(dtype=float, desc="x, y, z position of all microphones")

    #: Positions as (3, :attr:`num_mics`) array of floats, without invalid
    #: microphones; readonly.
    mpos = Property(depends_on=['mpos_tot', 'invalid_channels'],
                    desc="x, y, z position of microphones")

    # internal identifier
    digest = Property(depends_on=[
        'mpos',
    ])

    @cached_property
    def _get_digest(self):
        return digest(self)

    @cached_property
    def _get_basename(self):
        return path.splitext(path.basename(self.from_file))[0]

    @cached_property
    def _get_mpos(self):
        if len(self.invalid_channels) == 0:
            return self.mpos_tot
        allr = [
            i for i in range(self.mpos_tot.shape[-1])
            if i not in self.invalid_channels
        ]
        return self.mpos_tot[:, array(allr)]

    @cached_property
    def _get_num_mics(self):
        return self.mpos.shape[-1]

    @cached_property
    def _get_center(self):
        if self.mpos.any():
            center = average(self.mpos, axis=1)
            # set very small values to zero
            center[abs(center) < 1e-16] = 0.
            return center

    @on_trait_change('basename')
    def import_mpos(self):
        """
        Import the microphone positions from .xml file.
        Called when :attr:`basename` changes.
        """
        if not path.isfile(self.from_file):
            # no file there
            self.mpos_tot = array([], 'd')
            self.num_mics = 0
            return
        import xml.dom.minidom
        doc = xml.dom.minidom.parse(self.from_file)
        names = []
        xyz = []
        for el in doc.getElementsByTagName('pos'):
            names.append(el.getAttribute('Name'))
            xyz.append(list(map(lambda a: float(el.getAttribute(a)), 'xyz')))
        self.mpos_tot = array(xyz, 'd').swapaxes(0, 1)
예제 #5
0
class MaskedTimeSamples(TimeSamples):
    """
    Container for time data in `*.h5` format.
    
    This class loads measured data from h5 files 
    and provides information about this data.
    It supports storing information about (in)valid samples and (in)valid channels
    It also serves as an interface where the data can be accessed
    (e.g. for use in a block chain) via the :meth:`result` generator.
    
    """

    #: Index of the first sample to be considered valid.
    start = CLong(0, desc="start of valid samples")

    #: Index of the last sample to be considered valid.
    stop = Trait(None, None, CLong, desc="stop of valid samples")

    #: Channels that are to be treated as invalid.
    invalid_channels = ListInt(desc="list of invalid channels")

    #: Channel mask to serve as an index for all valid channels, is set automatically.
    channels = Property(depends_on=['invalid_channels', 'numchannels_total'],
                        desc="channel mask")

    #: Number of channels (including invalid channels), is set automatically.
    numchannels_total = CLong(0, desc="total number of input channels")

    #: Number of time data samples (including invalid samples), is set automatically.
    numsamples_total = CLong(0, desc="total number of samples per channel")

    #: Number of valid channels, is set automatically.
    numchannels = Property(depends_on = ['invalid_channels', \
        'numchannels_total'], desc="number of valid input channels")

    #: Number of valid time data samples, is set automatically.
    numsamples = Property(depends_on=['start', 'stop', 'numsamples_total'],
                          desc="number of valid samples per channel")

    # internal identifier
    digest = Property( depends_on = ['basename', 'start', 'stop', \
        'calib.digest', 'invalid_channels','_datachecksum'])

    @cached_property
    def _get_digest(self):
        return digest(self)

    @cached_property
    def _get_basename(self):
        return path.splitext(path.basename(self.name))[0]

    @cached_property
    def _get_channels(self):
        if len(self.invalid_channels) == 0:
            return slice(0, None, None)
        allr = [
            i for i in range(self.numchannels_total)
            if i not in self.invalid_channels
        ]
        return array(allr)

    @cached_property
    def _get_numchannels(self):
        if len(self.invalid_channels) == 0:
            return self.numchannels_total
        return len(self.channels)

    @cached_property
    def _get_numsamples(self):
        sli = slice(self.start, self.stop).indices(self.numsamples_total)
        return sli[1] - sli[0]

    @on_trait_change('basename')
    def load_data(self):
        #""" open the .h5 file and set attributes
        #"""
        if not path.isfile(self.name):
            # no file there
            self.numsamples_total = 0
            self.numchannels_total = 0
            self.sample_freq = 0
            raise IOError("No such file: %s" % self.name)
        if self.h5f != None:
            try:
                self.h5f.close()
            except IOError:
                pass
        file = _get_h5file_class()
        self.h5f = file(self.name)
        self.data = self.h5f.get_data_by_reference('time_data')
        self.sample_freq = self.h5f.get_node_attribute(self.data,
                                                       'sample_freq')
        (self.numsamples_total, self.numchannels_total) = self.data.shape

    def result(self, num=128):
        """
        Python generator that yields the output block-wise.
        
        Parameters
        ----------
        num : integer, defaults to 128
            This parameter defines the size of the blocks to be yielded
            (i.e. the number of samples per block).
        
        Returns
        -------
        Samples in blocks of shape (num, numchannels). 
            The last block may be shorter than num.
        """
        sli = slice(self.start, self.stop).indices(self.numsamples_total)
        i = sli[0]
        stop = sli[1]
        cal_factor = 1.0
        if i >= stop:
            raise IOError("no samples available")
        self._datachecksum  # trigger checksum calculation
        if self.calib:
            if self.calib.num_mics == self.numchannels_total:
                cal_factor = self.calib.data[self.channels][newaxis]
            elif self.calib.num_mics == self.numchannels:
                cal_factor = self.calib.data[newaxis]
            elif self.calib.num_mics == 0:
                warn("No calibration data used.", Warning, stacklevel=2)
            else:
                raise ValueError("calibration data not compatible: %i, %i" % \
                            (self.calib.num_mics, self.numchannels))
        while i < stop:
            yield self.data[i:min(i + num, stop)][:,
                                                  self.channels] * cal_factor
            i += num