Questão 1

  1. Gere sinais sintéticos que simulem a forma de onda do ciclo respiratório para diferentes faixas etárias. Considere as seguintes taxas de respiração por minuto: do nascimento a 6 semanas (30 a 40), 6 meses (25 a 40), 3 anos (20 a 30), 6 anos (18 a 25), 10 anos (17 a 23), adultos (12 a 18), idosos de 65 anos (12 a 28) e idosos de 80 anos (10 a 30).

  2. Utilize a função ggplot para plotar cada um dos sinais gerados no item a. A imagem resultante deverá conter um painel dividido em duas colunas e quatro linhas. Para isso, utilize a função facet_wrap da biblioteca ggplot2. Adicione legendas para os eixos x e y de cada gráfico.

  3. Utilize a biblioteca dygraph para gerar um gráfico para cada um dos sinais simulados no item a. Adicione legendas para os eixos x e y de cada gráfico. O resultado final deverá ser apresentado em um único painel HTML contendo os gráficos gerados. Para isso, consulte o código exemplo que realiza algo semelhante ao solicitado.

  4. Escolha um sinal simulado no item a e plote-o utilizando a função dyStemSeries. Explique por que há um intervalo temporal entre cada amostra. Sua resposta deve ser completa e abordar conceitos como amostragem e digitalização de sinais.

# Instalar pacotes necessários (todos juntos no início)
if (!requireNamespace("ggplot2", quietly = TRUE)) install.packages("ggplot2")
if (!requireNamespace("dygraphs", quietly = TRUE)) install.packages("dygraphs")
if (!requireNamespace("xts", quietly = TRUE)) install.packages("xts")
if (!requireNamespace("RColorBrewer", quietly = TRUE)) install.packages("RColorBrewer")

# Carregar pacotes necessários (todos juntos no início)
library(ggplot2)
library(dygraphs)
library(xts)
## Carregando pacotes exigidos: zoo
## 
## Anexando pacote: 'zoo'
## Os seguintes objetos são mascarados por 'package:base':
## 
##     as.Date, as.Date.numeric
library(RColorBrewer)

# Letra A
# Faixas etárias e frequências respiratórias
faixas_etarias <- list(
  "Nascimento a 6 semanas" = c(30, 40),
  "6 meses" = c(25, 40),
  "3 anos" = c(20, 30),
  "6 anos" = c(18, 25),
  "10 anos" = c(17, 23),
  "Adultos" = c(12, 18),
  "Idosos (65 anos)" = c(12, 28),
  "Idosos (80 anos)" = c(10, 30)
)

# Tempo total (30 segundos com amostragem de 0.1 s)
tempo <- seq(0, 30, by = 0.1)

# Função para gerar sinais trapezoidais
gerar_sinal_trapezoidal <- function(freq_min, freq_max, tempo) {
  freq_resp <- runif(1, freq_min, freq_max)  # Frequência respiratória aleatória
  periodo <- 60 / freq_resp                 # Período do ciclo respiratório
  
  # Tempo dentro de um ciclo
  ciclo_tempo <- tempo %% periodo
  amplitude <- ifelse(
    ciclo_tempo < periodo / 4,                # Subida
    4 * ciclo_tempo / periodo,
    ifelse(
      ciclo_tempo < 3 * periodo / 4,          # Platô alto
      1,
      ifelse(
        ciclo_tempo < periodo,                # Descida
        4 * (periodo - ciclo_tempo) / periodo,
        0
      )
    )
  )
  
  return(list(sinal = amplitude, freq_resp = freq_resp))
}

# Lista para armazenar os dados
dados_plot <- list()

# Gerar sinais para cada faixa etária
for (faixa in names(faixas_etarias)) {
  freq_min <- faixas_etarias[[faixa]][1]
  freq_max <- faixas_etarias[[faixa]][2]
  
  # Gerar sinal trapezoidal
  resultado <- gerar_sinal_trapezoidal(freq_min, freq_max, tempo)
  sinal <- resultado$sinal
  freq_resp <- resultado$freq_resp
  
  # Criar data.frame para cada faixa etária
  dados_plot[[faixa]] <- data.frame(
    Tempo = tempo,
    Amplitude = sinal,
    Faixa = faixa,
    Frequencia = sprintf("%.1f resp/min", freq_resp)
  )
}

# Combinar todos os data.frames em um único
dados_comb <- do.call(rbind, dados_plot)

# Letra B
# Criar o gráfico usando ggplot2
grafico <- ggplot(dados_comb, aes(x = Tempo, y = Amplitude, color = Faixa)) +
  geom_line(size = 0.5) +
  facet_wrap(~ Faixa, scales = "free_y", ncol = 2) +  # Configurar 2 colunas e 4 linhas
  labs(
    title = "Sinais Trapezoidais por Faixa Etária",
    x = "Tempo (s)",
    y = "Amplitude",
    color = "Faixa Etária"
  ) +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    strip.text = element_text(size = 10), # Ajustar tamanho do texto nos painéis
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12)
  )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Exibir o gráfico
print(grafico)

# Letra C
# Criar gráficos interativos com dygraphs
dygraph_list <- lapply(names(dados_plot), function(faixa) {
  # Dados da faixa etária
  dados_faixa <- dados_plot[[faixa]]
  
  # Criar um objeto xts (necessário para dygraphs)
  dados_xts <- xts(dados_faixa$Amplitude, order.by = as.POSIXct(dados_faixa$Tempo, origin = "1970-01-01"))
  
  # Criar gráfico com dygraphs
  dygraph(dados_xts, main = paste("Sinal Trapezoidal -", faixa)) %>%
    dyAxis("x", label = "Tempo (s)") %>%
    dyAxis("y", label = "Amplitude") %>%
    dyOptions(colors = RColorBrewer::brewer.pal(8, "Set2"))
})

# Renderizar os gráficos em um único painel HTML
htmltools::browsable(htmltools::tagList(dygraph_list))
# Resposta teórica sobre o intervalo entre amostras
cat("Por que há um intervalo temporal entre cada amostra?\n")
## Por que há um intervalo temporal entre cada amostra?
cat("O intervalo temporal entre cada amostra ocorre devido ao processo de amostragem, 
    algo natural da digitalização de sinais, uma vez que é impossível digitalizar infinitos pontos
    para amostrar um sinal contínuo. Assim, o que se faz consiste em capturar valores discretos do
    sinal em intervalos regulares de tempo, chamados de período de amostragem.")
## O intervalo temporal entre cada amostra ocorre devido ao processo de amostragem, 
##     algo natural da digitalização de sinais, uma vez que é impossível digitalizar infinitos pontos
##     para amostrar um sinal contínuo. Assim, o que se faz consiste em capturar valores discretos do
##     sinal em intervalos regulares de tempo, chamados de período de amostragem.
# Letra D
# Escolher um sinal específico para visualização interativa
faixa_escolhida <- "Adultos"  # Alterar conforme a faixa desejada
dados_escolhidos <- dados_plot[[faixa_escolhida]]

# Criar um objeto xts para dygraphs
dados_xts_escolhidos <- xts(dados_escolhidos$Amplitude, order.by = as.POSIXct(dados_escolhidos$Tempo, origin = "1970-01-01"))

# Criar gráfico com dygraphs para o sinal escolhido
dygraph(dados_xts_escolhidos, main = paste("Sinal Trapezoidal -", faixa_escolhida)) %>%
  dyAxis("x", label = "Tempo (s)") %>%
  dyAxis("y", label = "Amplitude") %>%
  dyOptions(colors = RColorBrewer::brewer.pal(8, "Set2"))

Por que há um intervalo temporal entre cada amostra?

O intervalo temporal entre cada amostra ocorre devido ao processo de amostragem,algo natural da digitalização de sinais, uma vez que é impossível digitalizar infinitos pontos para amostrar um sinal contínuo. Assim, o que se faz consiste em capturar valores discretos do sinal em intervalos regulares de tempo, chamados de período de amostragem.

Questão 2

  1. O armazenamento de dados biomédicos pode ocorrer em diversos formatos, incluindo arquivos gerados por programas comerciais como o Matlab. É essencial ser capaz de abrir esses arquivos no ambiente R. Para isso, importe o arquivo A07 no R utilizando o pacote R.matlab.

  2. Gere um gráfico de cada uma das três variáveis disponíveis no arquivo em função do tempo. A imagem final deverá conter um painel com uma coluna e três linhas. Utilize a função facet_wrap para organizar os gráficos e leve em conta que a resolução temporal está na variável isi, cuja unidade é milissegundos. Adicione legendas apropriadas para os eixos e filtre os dados em um intervalo de tempo adequado para a visualização, como entre 0 e 10 segundos.

  3. Utilize a função ggsave da biblioteca ggplot2 para salvar os gráficos resultantes, considerando o trecho de sinal entre 0 e 10 segundos. Salve as imagens nos formatos PDF e PNG, definindo dimensões de 100 mm de largura por 200 mm de altura e resolução de 300 dpi. As imagens geradas devem ser incluídas no relatório.

# Instalar os pacotes necessários, caso não estejam instalados
if (!requireNamespace("R.matlab", quietly = TRUE)) install.packages("R.matlab")
if (!requireNamespace("tidyverse", quietly = TRUE)) install.packages("tidyverse")

# Carregar os pacotes
library(R.matlab)
## R.matlab v3.7.0 (2022-08-25 21:52:34 UTC) successfully loaded. See ?R.matlab for help.
## 
## Anexando pacote: 'R.matlab'
## Os seguintes objetos são mascarados por 'package:base':
## 
##     getOption, isOpen
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ lubridate 1.9.4     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::first()  masks xts::first()
## ✖ dplyr::lag()    masks stats::lag()
## ✖ dplyr::last()   masks xts::last()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# Letra A
# Definir o caminho do arquivo .mat
arquivo_mat <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\A07\\A07.mat"

# Importar o arquivo .mat
dados_mat <- readMat(arquivo_mat)

# Letra B
# Extração e organização dos dados
variaveis <- as.data.frame(dados_mat$data)  # Extrair os dados das variáveis
colnames(variaveis) <- c("PPG", "RSP", "ECG")  # Nomear as colunas com base nos rótulos

isi <- as.numeric(dados_mat$isi) / 1000  # Converter o intervalo de amostragem (isi) para segundos
tempo <- seq(0, by = isi, length.out = nrow(variaveis))  # Gerar o vetor de tempo

# Adicionar o vetor de tempo e reorganizar os dados
dados <- variaveis %>%
  mutate(Tempo = tempo) %>%
  filter(Tempo <= 10) %>%  # Filtrar para o intervalo de 0 a 10 segundos
  pivot_longer(cols = -Tempo, names_to = "Variável", values_to = "Valor")  # Converter para formato longo

# Gerar o gráfico
grafico <- ggplot(dados, aes(x = Tempo, y = Valor, color = Variável)) +
  geom_line() +
  facet_wrap(~ Variável, ncol = 1, scales = "free_y") +
  labs(
    title = "Dados Biomédicos",
    x = "Tempo (s)",
    y = "Amplitude"
  ) +
  theme_minimal()

# Exibir o gráfico
print(grafico)

# Letra C
# Salvar os gráficos nos formatos PDF e PNG
ggsave("grafico_biomedico.pdf", plot = grafico, width = 100, height = 200, units = "mm", dpi = 300)
ggsave("grafico_biomedico.png", plot = grafico, width = 100, height = 200, units = "mm", dpi = 300)

Questão 3

  1. A base de dados disponível na plataforma Moodle foi coletada com o dispositivo TREMSEN (Precise Tremor Sensing), um sensor inercial posicionado no dorso da mão, sobre o osso Capitato. O eixo X do acelerômetro foi alinhado paralelamente à terceira falange distal, e os dados foram coletados durante cinco flexões, cinco extensões, cinco aduções e cinco abduções do punho. Os arquivos estão no formato EDF e TXT, nomeados de acordo com o tipo de movimento realizado.

  2. Abra o arquivo TXT no Excel e salve uma versão no formato XLS. Em seguida, salve o arquivo XLS no formato CSV.

  3. Abra o arquivo XLS no R e gere um gráfico com ggplot, adicionando legendas para os eixos x (tempo em segundos) e y (amplitude em g).

  4. Abra o arquivo CSV no R e gere um gráfico utilizando ggplot, garantindo que as legendas dos eixos x (tempo em segundos) e y (amplitude em g) estejam presentes.

  5. Abra o arquivo EDF no R e gere um gráfico utilizando ggplot, incluindo as legendas apropriadas para os eixos x (tempo em segundos) e y (amplitude em g).

  6. Inclua todos os resultados e códigos utilizados na execução dessa sequência de passos na resposta da questão.

# Instalar pacotes se necessário
if (!requireNamespace("readxl", quietly = TRUE)) install.packages("readxl")
if (!requireNamespace("data.table", quietly = TRUE)) install.packages("data.table")
if (!requireNamespace("ggplot2", quietly = TRUE)) install.packages("ggplot2")
if (!requireNamespace("edfReader", quietly = TRUE)) install.packages("edfReader")
if (!requireNamespace("openxlsx", quietly = TRUE)) install.packages("openxlsx")

# Carregar bibliotecas
library(readxl)
library(data.table)
## 
## Anexando pacote: 'data.table'
## Os seguintes objetos são mascarados por 'package:lubridate':
## 
##     hour, isoweek, mday, minute, month, quarter, second, wday, week,
##     yday, year
## Os seguintes objetos são mascarados por 'package:dplyr':
## 
##     between, first, last
## O seguinte objeto é mascarado por 'package:purrr':
## 
##     transpose
## Os seguintes objetos são mascarados por 'package:xts':
## 
##     first, last
## Os seguintes objetos são mascarados por 'package:zoo':
## 
##     yearmon, yearqtr
library(ggplot2)
library(edfReader)
library(openxlsx)

# Caminhos dos arquivos XLSX
caminho_XLSX_Aduccao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\xlsx\\Aduccao.xlsx"
caminho_XLSX_Flexao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\xlsx\\Flexao.xlsx"
caminho_XLSX_Rotacao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\xlsx\\Rotacao.xlsx"

# Caminhos dos arquivos CSV
caminho_CSV_Aduccao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\csv\\Aduccao.csv"
caminho_CSV_Flexao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\csv\\Flexao.csv"
caminho_CSV_Rotacao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\csv\\Rotacao.csv"

# Caminhos dos arquivos EDF
caminho_EDF_Aduccao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\edf\\Aduccao.edf"
caminho_EDF_Flexao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\edf\\Flexao.edf"
caminho_EDF_Rotacao <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\M2\\edf\\Rotacao.edf"

# --- Parte 1: Processar arquivo XLSX ---
dadosXLSX_a <- read_excel(caminho_XLSX_Aduccao)
dadosXLSX_b <- read_excel(caminho_XLSX_Flexao)
dadosXLSX_c <- read_excel(caminho_XLSX_Rotacao)

# Criar gráfico para o arquivo XLSX
grafxlsx_a <- ggplot(data = dadosXLSX_a) +
  geom_line(aes(x = `Time`, y = `G1.Y`), color = "red") +
  labs(title = "Dados - Aducção.xlsx", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

# Criar gráficos para os demais arquivos XLSX
grafxlsx_b <- ggplot(data = dadosXLSX_b) +
  geom_line(aes(x = `Time`, y = `G1.Y`), color = "blue") +
  labs(title = "Dados - Flexão.xlsx", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

grafxlsx_c <- ggplot(data = dadosXLSX_c) +
  geom_line(aes(x = `Time`, y = `G1.Y`), color = "green") +
  labs(title = "Dados - Rotação.xlsx", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

# --- Parte 2: Processar arquivos CSV ---
dadosCSV1_a <- read.csv(file = caminho_CSV_Aduccao, sep = ";")
dadosCSV2_b <- read.csv(file = caminho_CSV_Flexao, sep = ";")
dadosCSV3_c <- read.csv(file = caminho_CSV_Rotacao, sep = ";")

# Criar gráficos para os arquivos CSV
grafcsv_a <- ggplot(data = dadosCSV1_a) +
  geom_line(aes(x = time, y = dados), color = "red") +
  labs(title = "Dados - Aducção.csv", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

grafcsv_b <- ggplot(data = dadosCSV2_b) +
  geom_line(aes(x = time, y = dados), color = "blue") +
  labs(title = "Dados - Flexão.csv", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

grafcsv_c <- ggplot(data = dadosCSV3_c) +
  geom_line(aes(x = time, y = dados), color = "green") +
  labs(title = "Dados - Rotação.csv", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

# --- Parte 3: Processar arquivos EDF ---
hdr_a <- readEdfHeader(caminho_EDF_Aduccao)
dadosEDF_a <- readEdfSignals(hdr_a)

hdr_b <- readEdfHeader(caminho_EDF_Flexao)
dadosEDF_b <- readEdfSignals(hdr_b)

hdr_c <- readEdfHeader(caminho_EDF_Rotacao)
dadosEDF_c <- readEdfSignals(hdr_c)

# Converter para data.table
dadosEDF_a <- as.data.table(dadosEDF_a)
## Warning in as.data.table.list(dadosEDF_a): O item 41 possui 12 linhas, mas o
## item mais longo possui 19; reciclado com o restante.
dadosEDF_b <- as.data.table(dadosEDF_b)
## Warning in as.data.table.list(dadosEDF_b): O item 41 possui 12 linhas, mas o
## item mais longo possui 19; reciclado com o restante.
dadosEDF_c <- as.data.table(dadosEDF_c)
## Warning in as.data.table.list(dadosEDF_c): O item 41 possui 12 linhas, mas o
## item mais longo possui 19; reciclado com o restante.
# Criar gráficos para os arquivos EDF
grafedf_a <- ggplot(data = dadosEDF_a) +
  geom_line(aes(x = time, y = dados), color = "red") +
  labs(title = "Dados - Aducção.edf", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

grafedf_b <- ggplot(data = dadosEDF_b) +
  geom_line(aes(x = time, y = dados), color = "blue") +
  labs(title = "Dados - Flexão.edf", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

grafedf_c <- ggplot(data = dadosEDF_c) +
  geom_line(aes(x = time, y = dados), color = "green") +
  labs(title = "Dados - Rotação.edf", x = "Tempo (s)", y = "Amplitude (g)") +
  theme_minimal()

Questão 4

  1. Arquivos do tipo EDF são amplamente utilizados na indústria devido à sua padronização, que facilita o compartilhamento de dados. Para compreender sua estrutura, importe o arquivo binário V16C1RCC92.edf utilizando a biblioteca readr e a função read_file_raw.

  2. Extraia as informações do arquivo V16C1RCC92.edf e preencha a tabela correspondente, convertendo os dados binários para caracteres com a função rawToChar.

  3. Os itens a serem identificados incluem a versão do formato de dados, identificação do paciente e da gravação, data e hora de início da gravação, número de bytes no cabeçalho, campo reservado, número de registros de dados, duração de um registro e número de sinais no registro de dados.

# Instalar o pacote readr se ainda não estiver instalado
if (!requireNamespace("readr", quietly = TRUE)) install.packages("readr")

# Carregar a biblioteca
library(readr)

# Caminho para o arquivo EDF
edf_path <- "C:\\Users\\enzof\\OneDrive\\Documentos\\UFU\\Sétimo Período\\PSB\\listas\\V16C1RCC92.edf"

# Ler o arquivo binário usando read_file_raw
edf_raw_data <- read_file_raw(edf_path)

# Converter os bytes necessários para caracteres e interpretar os campos
version <- rawToChar(edf_raw_data[1:8])                    # Versão do formato de dados
patient_id <- rawToChar(edf_raw_data[9:88])                # Identificação do paciente
recording_id <- rawToChar(edf_raw_data[89:168])            # Identificação da gravação
start_date <- rawToChar(edf_raw_data[169:176])             # Data de início da gravação
start_time <- rawToChar(edf_raw_data[177:184])             # Hora de início da gravação
header_bytes <- rawToChar(edf_raw_data[185:192])           # Número de bytes no cabeçalho
reserved <- rawToChar(edf_raw_data[193:236])               # Reservado
num_data_records <- rawToChar(edf_raw_data[237:244])       # Número de registros de dados
duration <- rawToChar(edf_raw_data[245:252])               # Duração de um registro de dados (em segundos)
num_signals <- rawToChar(edf_raw_data[253:256])            # Número de sinais em cada registro de dados

# Criar uma tabela com os dados extraídos
edf_info <- data.frame(
  Tamanho = c(8, 80, 80, 8, 8, 8, 44, 8, 8, 4),
  Explicacao = c(
    "Versão do formato de dados",
    "Identificação do paciente",
    "Identificação da gravação",
    "Data de início da gravação (dd.mm.yy)",
    "Hora de início da gravação (hh.mm.ss)",
    "Número de bytes no cabeçalho",
    "Reservado",
    "Número de registros de dados (-1 se desconhecido)",
    "Duração de um registro de dados (em segundos)",
    "Número de sinais em cada registro de dados"
  ),
  Conteudo = c(version, patient_id, recording_id, start_date, start_time, header_bytes, reserved, num_data_records, duration, num_signals)
)

# Exibir a tabela
print(edf_info)
##    Tamanho                                        Explicacao
## 1        8                        Versão do formato de dados
## 2       80                         Identificação do paciente
## 3       80                         Identificação da gravação
## 4        8             Data de início da gravação (dd.mm.yy)
## 5        8             Hora de início da gravação (hh.mm.ss)
## 6        8                      Número de bytes no cabeçalho
## 7       44                                         Reservado
## 8        8 Número de registros de dados (-1 se desconhecido)
## 9        8     Duração de um registro de dados (em segundos)
## 10       4        Número de sinais em cada registro de dados
##                                                                            Conteudo
## 1                                                                          0       
## 2  X X X X                                                                         
## 3  Startdate 24-JAN-2018 X X TREMESEN_Firmware_version:_V2.4-2017                  
## 4                                                                          24.01.18
## 5                                                                          14.13.47
## 6                                                                          10752   
## 7                                      EDF+C                                       
## 8                                                                          21      
## 9                                                                          1       
## 10                                                                             41